From 01f3fb25751a8bd0c54309dabf3dc71ef3598129 Mon Sep 17 00:00:00 2001 From: jeanp413 Date: Fri, 8 Jul 2022 13:24:01 -0500 Subject: [PATCH 001/599] Fixes #152785 --- .../terminal/browser/terminalInstance.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 527493739e4..ae284145c7e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1334,6 +1334,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { override dispose(immediate?: boolean): void { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + this._logService.trace(`terminalInstance#dispose (instanceId: ${this.instanceId})`); dispose(this._linkManager); this._linkManager = undefined; @@ -1351,7 +1356,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._horizontalScrollbar = undefined; } } - this.xterm?.dispose(); + + try { + this.xterm?.dispose(); + } catch (err: unknown) { + // See https://github.com/microsoft/vscode/issues/153486 + this._logService.error('Exception occurred during xterm disposal', err); + } // HACK: Workaround for Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=559561, // as 'blur' event in xterm.raw.textarea is not triggered on xterm.dispose() @@ -1372,10 +1383,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // hasn't happened yet this._onProcessExit(undefined); - if (!this._isDisposed) { - this._isDisposed = true; - this._onDisposed.fire(this); - } + this._onDisposed.fire(this); + super.dispose(); } From 0be896fef5522026d1733b5440f1803cdc9be840 Mon Sep 17 00:00:00 2001 From: pingren <5123601+Pingren@users.noreply.github.com> Date: Sun, 31 Jul 2022 22:19:16 +0800 Subject: [PATCH 002/599] Enable user-select for monaco editor on macOS Fixes https://github.com/microsoft/vscode/issues/85632 --- src/vs/editor/browser/config/editorConfiguration.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/config/editorConfiguration.ts b/src/vs/editor/browser/config/editorConfiguration.ts index e3f41e0d416..1815f37072d 100644 --- a/src/vs/editor/browser/config/editorConfiguration.ts +++ b/src/vs/editor/browser/config/editorConfiguration.ts @@ -206,7 +206,7 @@ function digitCount(n: number): number { function getExtraEditorClassName(): string { let extra = ''; - if (!browser.isSafari && !browser.isWebkitWebView) { + if (!browser.isSafari && !browser.isWebkitWebView && !platform.isMacintosh) { // Use user-select: none in all browsers except Safari and native macOS WebView extra += 'no-user-select '; } @@ -217,6 +217,11 @@ function getExtraEditorClassName(): string { } if (platform.isMacintosh) { extra += 'mac '; + // Use user-select: initial for lookup feature on macOS + // https://github.com/microsoft/vscode/issues/85632 + if (!extra.includes('enable-user-select')) { + extra += 'enable-user-select '; + } } return extra; } From 12896eef4f88fcea42a6b40b00884a77d2772a14 Mon Sep 17 00:00:00 2001 From: pingren <5123601+Pingren@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:10:26 +0800 Subject: [PATCH 003/599] fix: use :hover pseudo class --- src/vs/editor/browser/config/editorConfiguration.ts | 7 +------ src/vs/editor/browser/viewParts/lines/viewLines.css | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/browser/config/editorConfiguration.ts b/src/vs/editor/browser/config/editorConfiguration.ts index 1815f37072d..e3f41e0d416 100644 --- a/src/vs/editor/browser/config/editorConfiguration.ts +++ b/src/vs/editor/browser/config/editorConfiguration.ts @@ -206,7 +206,7 @@ function digitCount(n: number): number { function getExtraEditorClassName(): string { let extra = ''; - if (!browser.isSafari && !browser.isWebkitWebView && !platform.isMacintosh) { + if (!browser.isSafari && !browser.isWebkitWebView) { // Use user-select: none in all browsers except Safari and native macOS WebView extra += 'no-user-select '; } @@ -217,11 +217,6 @@ function getExtraEditorClassName(): string { } if (platform.isMacintosh) { extra += 'mac '; - // Use user-select: initial for lookup feature on macOS - // https://github.com/microsoft/vscode/issues/85632 - if (!extra.includes('enable-user-select')) { - extra += 'enable-user-select '; - } } return extra; } diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.css b/src/vs/editor/browser/viewParts/lines/viewLines.css index 16b5fe52182..43e3ead7c83 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.css +++ b/src/vs/editor/browser/viewParts/lines/viewLines.css @@ -26,6 +26,15 @@ -webkit-user-select: none; -ms-user-select: none; } +/* Use user-select: text for lookup feature on macOS */ +/* https://github.com/microsoft/vscode/issues/85632 */ +.monaco-editor.mac .lines-content:hover, +.monaco-editor.mac .view-line:hover, +.monaco-editor.mac .view-lines:hover { + user-select: text; + -webkit-user-select: text; + -ms-user-select: text; +} .monaco-editor.enable-user-select { user-select: initial; From 880ffb665816d3cbeb43be4f7e7beeaf223fe794 Mon Sep 17 00:00:00 2001 From: Cyril OG Date: Sat, 13 Aug 2022 19:57:25 +0200 Subject: [PATCH 004/599] exit code is not restored when PROMPT_COMMAND is an array When the original PROMPT_COMMAND is an array: # exit code of last executed command was not restored before executing the commands stored inside the original PROMPT_COMMAND array # __vsc_status was assigned the exit code of the penultimate command stored inside the original PROMPT_COMMAND array Note: the proposed fix also works when PROMPT_COMMAND is not an array --- .../browser/media/shellIntegration-bash.sh | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index 41a2f5cb61f..215c8670c51 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -159,22 +159,17 @@ fi __vsc_update_prompt __vsc_restore_exit_code() { - return $1 + return "$1" } __vsc_prompt_cmd_original() { __vsc_status="$?" + __vsc_restore_exit_code "${__vsc_status}" # Evaluate the original PROMPT_COMMAND similarly to how bash would normally # See https://unix.stackexchange.com/a/672843 for technique - if [[ ${#__vsc_original_prompt_command[@]} -gt 1 ]]; then - for cmd in "${__vsc_original_prompt_command[@]}"; do - __vsc_status="$?" - eval "${cmd:-}" - done - else - __vsc_restore_exit_code "${__vsc_status}" - eval "${__vsc_original_prompt_command:-}" - fi + for cmd in "${__vsc_original_prompt_command[@]}"; do + eval "${cmd:-}" + done __vsc_precmd } From d3ceb08e3c4bef7b23fc22a9e4490914f57539be Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Sat, 20 Aug 2022 08:31:05 +0100 Subject: [PATCH 005/599] Add an `outline.initialState` setting (#53262) --- .../browser/outline/documentSymbolsOutline.ts | 8 ++++++- .../outline/browser/outline.contribution.ts | 21 +++++++++++++++---- .../services/outline/browser/outline.ts | 1 + 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index 5f44dc67e26..96265a7c1a9 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -103,6 +103,11 @@ class DocumentSymbolBreadcrumbsSource implements IBreadcrumbsDataSource { private readonly _disposables = new DisposableStore(); @@ -156,8 +161,9 @@ class DocumentSymbolsOutline implements IOutline { } }; const comparator = new DocumentSymbolComparator(); + const initialState = _configurationService.getValue(OutlineConfigKeys.initialState); const options = { - collapseByDefault: target === OutlineTarget.Breadcrumbs, + collapseByDefault: target === OutlineTarget.Breadcrumbs || (target === OutlineTarget.OutlinePane && initialState === DocumentSymbolsOutlineInitialState.Collapsed), expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, identityProvider: new DocumentSymbolIdentityProvider(), diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index 5b512f1e3c3..d2a15b135c4 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -40,22 +40,35 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'type': 'object', 'properties': { [OutlineConfigKeys.icons]: { - 'description': localize('outline.showIcons', "Render Outline Elements with Icons."), + 'description': localize('outline.showIcons', "Render outline elements with icons."), 'type': 'boolean', 'default': true }, + [OutlineConfigKeys.initialState]: { + 'description': localize('outline.initialState', "Initial state of outline."), + 'type': 'string', + 'enum': [ + 'collapsed', + 'expanded' + ], + 'enumDescriptions': [ + localize('outline.initialState.collapsed', "Collapse all nodes upon loading."), + localize('outline.initialState.expanded', "Expand all nodes upon loading.") + ], + 'default': 'expanded' + }, [OutlineConfigKeys.problemsEnabled]: { - 'description': localize('outline.showProblem', "Show Errors & Warnings on Outline Elements."), + 'description': localize('outline.showProblem', "Show errors and warnings on outline elements."), 'type': 'boolean', 'default': true }, [OutlineConfigKeys.problemsColors]: { - 'description': localize('outline.problem.colors', "Use colors for Errors & Warnings."), + 'description': localize('outline.problem.colors', "Use colors for errors and warnings on outline elements."), 'type': 'boolean', 'default': true }, [OutlineConfigKeys.problemsBadges]: { - 'description': localize('outline.problems.badges', "Use badges for Errors & Warnings."), + 'description': localize('outline.problems.badges', "Use badges for errors and warnings on outline elements."), 'type': 'boolean', 'default': true }, diff --git a/src/vs/workbench/services/outline/browser/outline.ts b/src/vs/workbench/services/outline/browser/outline.ts index 022a6004f26..e0ca0de4f6a 100644 --- a/src/vs/workbench/services/outline/browser/outline.ts +++ b/src/vs/workbench/services/outline/browser/outline.ts @@ -92,6 +92,7 @@ export interface IOutline { export const enum OutlineConfigKeys { 'icons' = 'outline.icons', + 'initialState' = 'outline.initialState', 'problemsEnabled' = 'outline.problems.enabled', 'problemsColors' = 'outline.problems.colors', 'problemsBadges' = 'outline.problems.badges' From 766e410d0994ac42469c975b196516f2413f7f46 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Sat, 20 Aug 2022 08:35:03 +0100 Subject: [PATCH 006/599] Fix outline items collapsing when switching between files --- .../contrib/outline/browser/outlinePane.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index d41777b2c54..5af3569c5d5 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -36,6 +36,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Event } from 'vs/base/common/event'; import { ITreeSorter } from 'vs/base/browser/ui/tree/tree'; import { AbstractTreeViewState, IAbstractTreeViewState, TreeFindMode } from 'vs/base/browser/ui/tree/abstractTree'; +import { URI } from 'vs/base/common/uri'; const _ctxFollowsCursor = new RawContextKey('outlineFollowsCursor', false); const _ctxFilterOnType = new RawContextKey('outlineFiltersOnType', false); @@ -180,11 +181,14 @@ export class OutlinePane extends ViewPane { this._message.innerText = message; } - private _captureViewState(): boolean { + private _captureViewState(uri?: URI): boolean { if (this._tree) { const oldOutline = this._tree.getInput(); - if (oldOutline && oldOutline.uri) { - this._treeStates.set(`${oldOutline.outlineKind}/${oldOutline.uri}`, this._tree.getViewState()); + if (!uri) { + uri = oldOutline?.uri; + } + if (oldOutline && uri) { + this._treeStates.set(`${oldOutline.outlineKind}/${uri}`, this._tree.getViewState()); return true; } } @@ -269,13 +273,13 @@ export class OutlinePane extends ViewPane { if (newOutline.isEmpty) { // no more elements this._showMessage(localize('no-symbols', "No symbols found in document '{0}'", basename(resource))); - this._captureViewState(); + this._captureViewState(resource); tree.setInput(undefined); } else if (!tree.getInput()) { // first: init tree this._domNode.classList.remove('message'); - const state = this._treeStates.get(`${newOutline.outlineKind}/${resource}`); + const state = this._treeStates.get(`${newOutline.outlineKind}/${newOutline.uri}`); tree.setInput(newOutline, state && AbstractTreeViewState.lift(state)); } else { From 8c1cd4194b71479c14ebff8a3673a85defc686ed Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Sat, 20 Aug 2022 19:07:27 +0100 Subject: [PATCH 007/599] Make `outline.initialState` configurable per language --- .../codeEditor/browser/outline/documentSymbolsOutline.ts | 2 +- .../workbench/contrib/outline/browser/outline.contribution.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index 96265a7c1a9..e8a133db925 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -161,7 +161,7 @@ class DocumentSymbolsOutline implements IOutline { } }; const comparator = new DocumentSymbolComparator(); - const initialState = _configurationService.getValue(OutlineConfigKeys.initialState); + const initialState = textResourceConfigurationService.getValue(_editor.getModel()?.uri, OutlineConfigKeys.initialState); const options = { collapseByDefault: target === OutlineTarget.Breadcrumbs || (target === OutlineTarget.OutlinePane && initialState === DocumentSymbolsOutlineInitialState.Collapsed), expandOnlyOnTwistieClick: true, diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index d2a15b135c4..d4620a4d3b4 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -47,6 +47,7 @@ Registry.as(ConfigurationExtensions.Configuration).regis [OutlineConfigKeys.initialState]: { 'description': localize('outline.initialState', "Initial state of outline."), 'type': 'string', + scope: ConfigurationScope.LANGUAGE_OVERRIDABLE, 'enum': [ 'collapsed', 'expanded' From 2a0eada25bd3a1e53736b1625aa1654d98988ae4 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Tue, 23 Aug 2022 21:44:37 +0100 Subject: [PATCH 008/599] Make 'Collapse All' become 'Expand All' when tree is fully collapsed --- .../contrib/outline/browser/outlinePane.ts | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index 5af3569c5d5..aa168798533 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -38,9 +38,10 @@ import { ITreeSorter } from 'vs/base/browser/ui/tree/tree'; import { AbstractTreeViewState, IAbstractTreeViewState, TreeFindMode } from 'vs/base/browser/ui/tree/abstractTree'; import { URI } from 'vs/base/common/uri'; -const _ctxFollowsCursor = new RawContextKey('outlineFollowsCursor', false); -const _ctxFilterOnType = new RawContextKey('outlineFiltersOnType', false); +const _ctxFollowsCursor = new RawContextKey('outlineFollowsCursor', false); +const _ctxFilterOnType = new RawContextKey('outlineFiltersOnType', false); const _ctxSortMode = new RawContextKey('outlineSortMode', OutlineSortOrder.ByPosition); +const _ctxAllCollapsed = new RawContextKey('outlineAllCollapsed', false); class OutlineTreeSorter implements ITreeSorter { @@ -83,6 +84,10 @@ export class OutlinePane extends ViewPane { private _ctxFollowsCursor!: IContextKey; private _ctxFilterOnType!: IContextKey; private _ctxSortMode!: IContextKey; + private _ctxAllCollapsed!: IContextKey; + private _updateAllCollapsedContext(): void { + this._ctxAllCollapsed.set(this._tree?.getNode(null).children.every(node => !node.collapsible || node.collapsed) || false); + } constructor( options: IViewletViewOptions, @@ -108,6 +113,7 @@ export class OutlinePane extends ViewPane { this._ctxFollowsCursor = _ctxFollowsCursor.bindTo(contextKeyService); this._ctxFilterOnType = _ctxFilterOnType.bindTo(contextKeyService); this._ctxSortMode = _ctxSortMode.bindTo(contextKeyService); + this._ctxAllCollapsed = _ctxAllCollapsed.bindTo(contextKeyService); }); const updateContext = () => { @@ -117,6 +123,8 @@ export class OutlinePane extends ViewPane { }; updateContext(); this._disposables.add(this._outlineViewState.onDidChange(updateContext)); + + this._updateAllCollapsedContext(); } override dispose(): void { @@ -171,6 +179,10 @@ export class OutlinePane extends ViewPane { this._tree?.collapseAll(); } + expandAll(): void { + this._tree?.expandAll(); + } + get outlineViewState() { return this._outlineViewState; } @@ -359,13 +371,14 @@ export class OutlinePane extends ViewPane { } })); - // last: set tree property + // last: set tree property and wire it up to one of our context keys tree.layout(this._treeDimensions?.height, this._treeDimensions?.width); this._tree = tree; this._editorControlDisposables.add(toDisposable(() => { tree.dispose(); this._tree = undefined; })); + this._disposables.add(this._tree.onDidChangeCollapseState(() => this._updateAllCollapsedContext())); } } @@ -383,7 +396,7 @@ registerAction2(class Collapse extends ViewAction { menu: { id: MenuId.ViewTitle, group: 'navigation', - when: ContextKeyExpr.equals('view', OutlinePane.Id) + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', OutlinePane.Id), _ctxAllCollapsed.isEqualTo(false)) } }); } @@ -392,6 +405,26 @@ registerAction2(class Collapse extends ViewAction { } }); +registerAction2(class Collapse extends ViewAction { + constructor() { + super({ + viewId: OutlinePane.Id, + id: 'outline.expand', + title: localize('expand', "Expand All"), + f1: false, + icon: Codicon.expandAll, + menu: { + id: MenuId.ViewTitle, + group: 'navigation', + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', OutlinePane.Id), _ctxAllCollapsed.isEqualTo(true)) + } + }); + } + runInView(_accessor: ServicesAccessor, view: OutlinePane) { + view.expandAll(); + } +}); + registerAction2(class FollowCursor extends ViewAction { constructor() { super({ From 797fb52adc521f46c3eb1e4a5b531c8e9b4cd88a Mon Sep 17 00:00:00 2001 From: Matt Adam Date: Wed, 24 Aug 2022 13:24:25 -0700 Subject: [PATCH 009/599] Test --- .../viewParts/contentWidgets/contentWidgets.ts | 4 ++++ .../editor/browser/widget/codeEditorWidget.ts | 7 +++++++ src/vs/editor/common/model.ts | 4 ++++ .../contrib/hover/browser/contentHover.ts | 13 ++++++++++++- .../editor/contrib/hover/browser/hoverTypes.ts | 2 ++ .../hover/browser/markdownHoverParticipant.ts | 18 ++++++++++++++---- .../inlayHints/browser/inlayHintsHover.ts | 10 +++++----- .../browser/unicodeHighlighter.ts | 2 +- src/vs/monaco.d.ts | 4 ++++ 9 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index f45578d9f15..a2d4594dfb0 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -431,6 +431,10 @@ class Widget { firstLineMinLeft = visibleRange.left; } } + if (this._affinity === PositionAffinity.LeftOfInjectedText && + this._viewRange.startColumn === 1) { + firstLineMinLeft = 0; + } let lastLineMinLeft = Constants.MAX_SAFE_SMALL_INTEGER;//lastLine.Constants.MAX_SAFE_SMALL_INTEGER; for (const visibleRange of lastLine.ranges) { diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 8a49db0edb7..21f64e2a069 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1359,7 +1359,14 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const opts = this._resolveDecorationOptions(typeKey, !!decorationOption.hoverMessage); if (decorationOption.hoverMessage) { opts.hoverMessage = decorationOption.hoverMessage; + + if (decorationOption.renderOptions?.before || + decorationOption.renderOptions?.dark?.before || + decorationOption.renderOptions?.light?.before) { + opts.hoverMessageBefore = true; + } } + newModelDecorations.push({ range: decorationOption.range, options: opts }); } diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index bf2cc58e639..ea02164cbbd 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -100,6 +100,10 @@ export interface IModelDecorationOptions { * Array of MarkdownString to render as the decoration message. */ hoverMessage?: IMarkdownString | IMarkdownString[] | null; + /** + * If true, hover message will be left-aligned to the beforecontent on the line + */ + hoverMessageBefore?: boolean | null; /** * Should the decoration expand to encompass a whole line. */ diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 666337b5614..357e33f10a9 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -13,7 +13,7 @@ import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IConte import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IModelDecoration } from 'vs/editor/common/model'; +import { IModelDecoration, PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { TokenizationRegistry } from 'vs/editor/common/languages'; import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/browser/hoverOperation'; @@ -139,6 +139,8 @@ export class ContentHoverController extends Disposable { this._hoverOperation.cancel(); + // console.log(`--- HOVER CHANGE s-line: ${anchor.range.startLineNumber} s-col: ${anchor.range.startColumn} e-line: ${anchor.range.endLineNumber} e-col: ${anchor.range.endColumn}`); + if (this._widget.position) { // The range might have changed, but the hover is visible // Instead of hiding it completely, filter out messages that are still in the new range and @@ -224,6 +226,9 @@ export class ContentHoverController extends Disposable { disposables.add(participant.renderHoverParts(context, hoverParts)); } } + + const isBefore = messages.some(m => m.isBeforeContent); + if (statusBar.hasContent) { fragment.appendChild(statusBar.hoverElement); } @@ -256,6 +261,7 @@ export class ContentHoverController extends Disposable { showAtRange, this._editor.getOption(EditorOption.hover).above, this._computer.shouldFocus, + isBefore, disposables )); } else { @@ -303,6 +309,7 @@ class ContentHoverVisibleData { public readonly showAtRange: Range, public readonly preferAbove: boolean, public readonly stoleFocus: boolean, + public readonly isBefore: boolean, public readonly disposables: DisposableStore ) { } } @@ -372,6 +379,9 @@ export class ContentHoverWidget extends Disposable implements IContentWidget { // Prefer rendering above if the suggest widget is visible preferAbove = true; } + + const affinity = this._visibleData.isBefore ? PositionAffinity.LeftOfInjectedText : undefined; + return { position: this._visibleData.showAtPosition, range: this._visibleData.showAtRange, @@ -380,6 +390,7 @@ export class ContentHoverWidget extends Disposable implements IContentWidget { ? [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW] : [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE] ), + positionAffinity: affinity }; } diff --git a/src/vs/editor/contrib/hover/browser/hoverTypes.ts b/src/vs/editor/contrib/hover/browser/hoverTypes.ts index 7dfa9e2a916..ce8cf3c048e 100644 --- a/src/vs/editor/contrib/hover/browser/hoverTypes.ts +++ b/src/vs/editor/contrib/hover/browser/hoverTypes.ts @@ -26,6 +26,8 @@ export interface IHoverPart { * even in the case of multiple hover parts. */ readonly forceShowAtRange?: boolean; + + readonly isBeforeContent?: boolean; /** * Is this hover part still valid for this new anchor? */ diff --git a/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts b/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts index c2e2f56a91e..ed2f7ff673e 100644 --- a/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts +++ b/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts @@ -30,6 +30,7 @@ export class MarkdownHover implements IHoverPart { public readonly owner: IEditorHoverParticipant, public readonly range: Range, public readonly contents: IMarkdownString[], + public readonly isBeforeContent: boolean, public readonly ordinal: number ) { } @@ -55,7 +56,7 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant= maxTokenizationLineLength) { result.push(new MarkdownHover(this, anchor.range, [{ value: nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. This can be configured via `editor.maxTokenizationLineLength`.") - }], index++)); + }], false, index++)); } + let isBeforeContent = false; + for (const d of lineDecorations) { const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1; const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; @@ -90,8 +93,15 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant !isEmptyMarkdownString(item.hover.contents)) .map(item => { const rng = item.hover.range ? Range.lift(item.hover.range) : anchor.range; - return new MarkdownHover(this, rng, item.hover.contents, item.ordinal); + return new MarkdownHover(this, rng, item.hover.contents, false, item.ordinal); }); } diff --git a/src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts b/src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts index a4710cb752e..1ceb105f6fc 100644 --- a/src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts +++ b/src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts @@ -87,11 +87,11 @@ export class InlayHintsHover extends MarkdownHoverParticipant implements IEditor itemTooltip = part.item.hint.tooltip; } if (itemTooltip) { - executor.emitOne(new MarkdownHover(this, anchor.range, [itemTooltip], 0)); + executor.emitOne(new MarkdownHover(this, anchor.range, [itemTooltip], false, 0)); } // (1.2) Inlay dbl-click gesture if (isNonEmptyArray(part.item.hint.textEdits)) { - executor.emitOne(new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(localize('hint.dbl', "Double click to insert"))], 10001)); + executor.emitOne(new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(localize('hint.dbl', "Double click to insert"))], false, 10001)); } // (2) Inlay Label Part Tooltip @@ -102,7 +102,7 @@ export class InlayHintsHover extends MarkdownHoverParticipant implements IEditor partTooltip = part.part.tooltip; } if (partTooltip) { - executor.emitOne(new MarkdownHover(this, anchor.range, [partTooltip], 1)); + executor.emitOne(new MarkdownHover(this, anchor.range, [partTooltip], false, 1)); } // (2.2) Inlay Label Part Help Hover @@ -125,7 +125,7 @@ export class InlayHintsHover extends MarkdownHoverParticipant implements IEditor linkHint = new MarkdownString(`[${localize('hint.cmd', "Execute Command")}](${asCommandLink(part.part.command)} "${part.part.command.title}") (${kb})`, { isTrusted: true }); } if (linkHint) { - executor.emitOne(new MarkdownHover(this, anchor.range, [linkHint], 10000)); + executor.emitOne(new MarkdownHover(this, anchor.range, [linkHint], false, 10000)); } } @@ -151,7 +151,7 @@ export class InlayHintsHover extends MarkdownHoverParticipant implements IEditor } return getHover(this._languageFeaturesService.hoverProvider, model, new Position(range.startLineNumber, range.startColumn), token) .filter(item => !isEmptyMarkdownString(item.hover.contents)) - .map(item => new MarkdownHover(this, part.item.anchor.range, item.hover.contents, 2 + item.ordinal)); + .map(item => new MarkdownHover(this, part.item.anchor.range, item.hover.contents, false, 2 + item.ordinal)); } finally { ref.dispose(); } diff --git a/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts b/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts index b9f16e4c68a..bd6d9cd9b84 100644 --- a/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts +++ b/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts @@ -483,7 +483,7 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa .appendMarkdown(reason) .appendText(' ') .appendLink(uri, adjustSettings); - result.push(new MarkdownHover(this, d.range, [markdown], index++)); + result.push(new MarkdownHover(this, d.range, [markdown], false, index++)); } return result; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 7bd8af19e51..557618cd3e3 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1496,6 +1496,10 @@ declare namespace monaco.editor { * Array of MarkdownString to render as the decoration message. */ hoverMessage?: IMarkdownString | IMarkdownString[] | null; + /** + * If true, hover message will be left-aligned to the beforecontent on the line + */ + hoverMessageBefore?: boolean | null; /** * Should the decoration expand to encompass a whole line. */ From 78851b53761616960e4ce0680a36238f823818ef Mon Sep 17 00:00:00 2001 From: Matt Adam Date: Thu, 25 Aug 2022 12:44:08 -0700 Subject: [PATCH 010/599] Cleanup --- .../viewParts/contentWidgets/contentWidgets.ts | 2 ++ src/vs/editor/browser/widget/codeEditorWidget.ts | 6 ------ src/vs/editor/common/model.ts | 4 ---- src/vs/editor/contrib/hover/browser/contentHover.ts | 11 +++++------ src/vs/editor/contrib/hover/browser/hoverTypes.ts | 3 +++ .../contrib/hover/browser/markdownHoverParticipant.ts | 3 --- src/vs/monaco.d.ts | 4 ---- 7 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index a2d4594dfb0..37c8f7ac5d0 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -431,6 +431,8 @@ class Widget { firstLineMinLeft = visibleRange.left; } } + + // Left-align widgets that should appear :before content if (this._affinity === PositionAffinity.LeftOfInjectedText && this._viewRange.startColumn === 1) { firstLineMinLeft = 0; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 21f64e2a069..0b291331cd3 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1359,12 +1359,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const opts = this._resolveDecorationOptions(typeKey, !!decorationOption.hoverMessage); if (decorationOption.hoverMessage) { opts.hoverMessage = decorationOption.hoverMessage; - - if (decorationOption.renderOptions?.before || - decorationOption.renderOptions?.dark?.before || - decorationOption.renderOptions?.light?.before) { - opts.hoverMessageBefore = true; - } } newModelDecorations.push({ range: decorationOption.range, options: opts }); diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index ea02164cbbd..bf2cc58e639 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -100,10 +100,6 @@ export interface IModelDecorationOptions { * Array of MarkdownString to render as the decoration message. */ hoverMessage?: IMarkdownString | IMarkdownString[] | null; - /** - * If true, hover message will be left-aligned to the beforecontent on the line - */ - hoverMessageBefore?: boolean | null; /** * Should the decoration expand to encompass a whole line. */ diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 357e33f10a9..9e90b8aa0fc 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -139,8 +139,6 @@ export class ContentHoverController extends Disposable { this._hoverOperation.cancel(); - // console.log(`--- HOVER CHANGE s-line: ${anchor.range.startLineNumber} s-col: ${anchor.range.startColumn} e-line: ${anchor.range.endLineNumber} e-col: ${anchor.range.endColumn}`); - if (this._widget.position) { // The range might have changed, but the hover is visible // Instead of hiding it completely, filter out messages that are still in the new range and @@ -227,7 +225,7 @@ export class ContentHoverController extends Disposable { } } - const isBefore = messages.some(m => m.isBeforeContent); + const isBeforeContent = messages.some(m => m.isBeforeContent); if (statusBar.hasContent) { fragment.appendChild(statusBar.hoverElement); @@ -261,7 +259,7 @@ export class ContentHoverController extends Disposable { showAtRange, this._editor.getOption(EditorOption.hover).above, this._computer.shouldFocus, - isBefore, + isBeforeContent, disposables )); } else { @@ -309,7 +307,7 @@ class ContentHoverVisibleData { public readonly showAtRange: Range, public readonly preferAbove: boolean, public readonly stoleFocus: boolean, - public readonly isBefore: boolean, + public readonly isBeforeContent: boolean, public readonly disposables: DisposableStore ) { } } @@ -380,7 +378,8 @@ export class ContentHoverWidget extends Disposable implements IContentWidget { preferAbove = true; } - const affinity = this._visibleData.isBefore ? PositionAffinity.LeftOfInjectedText : undefined; + // :before content can align left of the text content + const affinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; return { position: this._visibleData.showAtPosition, diff --git a/src/vs/editor/contrib/hover/browser/hoverTypes.ts b/src/vs/editor/contrib/hover/browser/hoverTypes.ts index ce8cf3c048e..3fb6e5dee58 100644 --- a/src/vs/editor/contrib/hover/browser/hoverTypes.ts +++ b/src/vs/editor/contrib/hover/browser/hoverTypes.ts @@ -27,6 +27,9 @@ export interface IHoverPart { */ readonly forceShowAtRange?: boolean; + /** + * If true, the hover item should appear before content + */ readonly isBeforeContent?: boolean; /** * Is this hover part still valid for this new anchor? diff --git a/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts b/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts index ed2f7ff673e..19d151cf757 100644 --- a/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts +++ b/src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts @@ -93,9 +93,6 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant Date: Fri, 26 Aug 2022 15:52:13 +0100 Subject: [PATCH 011/599] Check for unsaved editors before asking to save --- src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 6da4739e321..5061c51a3d3 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1824,7 +1824,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Never) { return false; - } else if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Prompt) { + } else if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Prompt && this._editorService.editors.some(e => e.isDirty())) { const dialogOptions = await this._dialogService.show( Severity.Info, nls.localize('TaskSystem.saveBeforeRun.prompt.title', 'Save all editors?'), From 8533550d9139da2064244a2965b7eb09785404f0 Mon Sep 17 00:00:00 2001 From: Matt Adam Date: Mon, 29 Aug 2022 10:29:27 -0700 Subject: [PATCH 012/599] Remove --- src/vs/editor/browser/widget/codeEditorWidget.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 0b291331cd3..8a49db0edb7 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1360,7 +1360,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (decorationOption.hoverMessage) { opts.hoverMessage = decorationOption.hoverMessage; } - newModelDecorations.push({ range: decorationOption.range, options: opts }); } From 00414a3755f924bbd5b5438a64e04402d0b4fe8c Mon Sep 17 00:00:00 2001 From: Tobias Hernstig <30827238+thernstig@users.noreply.github.com> Date: Thu, 8 Sep 2022 10:37:31 +0200 Subject: [PATCH 013/599] Update Groovy extension language contribution Change `filenamePatterns` to `Jenkinsfile.*` to `Jenkinsfile*` to capture files starting with Jenkinsfile, not necessarily having a period as a delimiter. --- extensions/groovy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/groovy/package.json b/extensions/groovy/package.json index a7000f89e20..1f50ff6caf7 100644 --- a/extensions/groovy/package.json +++ b/extensions/groovy/package.json @@ -30,7 +30,7 @@ "Jenkinsfile" ], "filenamePatterns": [ - "Jenkinsfile.*" + "Jenkinsfile*" ], "firstLine": "^#!.*\\bgroovy\\b", "configuration": "./language-configuration.json" From ae90723b6ff8e524cd8abc4d2fdcf01b35970125 Mon Sep 17 00:00:00 2001 From: Chris Keilbart Date: Tue, 13 Sep 2022 14:27:43 -0700 Subject: [PATCH 014/599] Removed erroneous references to PREFIX environment variable --- .../contrib/terminal/browser/media/shellIntegration-bash.sh | 2 +- .../contrib/terminal/browser/media/shellIntegration-rc.zsh | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index e3ce0fa6771..9cd34f5f33f 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -98,7 +98,7 @@ __vsc_update_prompt() { # means the user re-exported the PS1 so we should re-wrap it if [[ "$__vsc_custom_PS1" == "" || "$__vsc_custom_PS1" != "$PS1" ]]; then __vsc_original_PS1=$PS1 - __vsc_custom_PS1="\[$(__vsc_prompt_start)\]$PREFIX$__vsc_original_PS1\[$(__vsc_prompt_end)\]" + __vsc_custom_PS1="\[$(__vsc_prompt_start)\]$__vsc_original_PS1\[$(__vsc_prompt_end)\]" PS1="$__vsc_custom_PS1" fi if [[ "$__vsc_custom_PS2" == "" || "$__vsc_custom_PS2" != "$PS2" ]]; then diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh index 84d7ef55c8a..0ab72f1886d 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh @@ -84,14 +84,11 @@ if [[ -o NOUNSET ]]; then if [ -z "${RPROMPT-}" ]; then RPROMPT="" fi - if [ -z "${PREFIX-}" ]; then - PREFIX="" - fi fi __vsc_update_prompt() { __vsc_prior_prompt="$PS1" __vsc_in_command_execution="" - PS1="%{$(__vsc_prompt_start)%}$PREFIX$PS1%{$(__vsc_prompt_end)%}" + PS1="%{$(__vsc_prompt_start)%}$PS1%{$(__vsc_prompt_end)%}" PS2="%{$(__vsc_continuation_start)%}$PS2%{$(__vsc_continuation_end)%}" if [ -n "$RPROMPT" ]; then __vsc_prior_rprompt="$RPROMPT" From 76d2ad1c9a50de9f22675f4c7f8770603d6615fb Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 23 Sep 2022 08:50:49 +0200 Subject: [PATCH 015/599] fix change short name command title --- .../browser/parts/activitybar/activitybarPart.ts | 14 ++------------ .../userDataProfile/browser/userDataProfile.ts | 2 +- .../userDataProfile/common/userDataProfile.ts | 1 + .../common/userDataProfileService.ts | 10 ++++++++++ 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 666363ec87a..8b3c5d96691 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -46,7 +46,7 @@ import { IPaneCompositePart, IPaneCompositeSelectorPart } from 'vs/workbench/bro import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; import { IUserDataProfileService, PROFILES_TTILE } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; interface IPlaceholderViewContainer { readonly id: string; @@ -620,22 +620,12 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart const icon = this.userDataProfileService.currentProfile.shortName ? ThemeIcon.fromString(this.userDataProfileService.currentProfile.shortName) : undefined; return { id: 'workbench.actions.profiles', - name: icon ? this.userDataProfileService.currentProfile.name : this.getProfileEntryDisplayName(this.userDataProfileService.currentProfile), + name: icon ? this.userDataProfileService.currentProfile.name : this.userDataProfileService.getShortName(this.userDataProfileService.currentProfile), cssClass: icon ? `${ThemeIcon.asClassName(icon)} profile-activity-item` : 'profile-activity-item', icon: !!icon }; } - private getProfileEntryDisplayName(profile: IUserDataProfile): string { - if (profile.shortName) { - return profile.shortName; - } - if (profile.isTransient) { - return `T${this.userDataProfileService.currentProfile.name.charAt(this.userDataProfileService.currentProfile.name.length - 1)}`; - } - return this.userDataProfileService.currentProfile.name.substring(0, 2).toUpperCase(); - } - private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction } { let compositeActions = this.compositeActions.get(compositeId); if (!compositeActions) { diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 74775e7c433..a196b4d7018 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -162,7 +162,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements super({ id: `workbench.profiles.actions.updateCurrentProfileShortName`, title: { - value: localize('change short name profile', "Change Short Name ({0})...", that.userDataProfileService.currentProfile.shortName), + value: localize('change short name profile', "Change Short Name ({0})...", that.userDataProfileService.getShortName(that.userDataProfileService.currentProfile)), original: `Change Short Name (${that.userDataProfileService.currentProfile.shortName})...` }, menu: [ diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts index f45c89a4111..5aba82d0c06 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts @@ -26,6 +26,7 @@ export interface IUserDataProfileService { readonly onDidChangeCurrentProfile: Event; readonly currentProfile: IUserDataProfile; updateCurrentProfile(currentProfile: IUserDataProfile, preserveData: boolean): Promise; + getShortName(profile: IUserDataProfile): string; } export const IUserDataProfileManagementService = createDecorator('IUserDataProfileManagementService'); diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts index 77f8c28e6ce..8b34656b973 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts @@ -64,4 +64,14 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi await Promises.settled(joiners); } + getShortName(profile: IUserDataProfile): string { + if (profile.shortName) { + return profile.shortName; + } + if (profile.isTransient) { + return `T${profile.name.charAt(profile.name.length - 1)}`; + } + return profile.name.substring(0, 2).toUpperCase(); + } + } From 17151ad7ff9f6a1e2c23768ab4bdcdbc52953171 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 23 Sep 2022 15:12:45 +0200 Subject: [PATCH 016/599] fix compilation errror --- .../workbench/browser/parts/activitybar/activitybarPart.ts | 5 +++-- src/vs/workbench/test/browser/workbenchTestServices.ts | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 8b3c5d96691..f86c4ea3d63 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -617,10 +617,11 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart } private createProfilesActivity(): IProfileActivity { - const icon = this.userDataProfileService.currentProfile.shortName ? ThemeIcon.fromString(this.userDataProfileService.currentProfile.shortName) : undefined; + const shortName = this.userDataProfileService.getShortName(this.userDataProfileService.currentProfile); + const icon = ThemeIcon.fromString(shortName); return { id: 'workbench.actions.profiles', - name: icon ? this.userDataProfileService.currentProfile.name : this.userDataProfileService.getShortName(this.userDataProfileService.currentProfile), + name: icon ? this.userDataProfileService.currentProfile.name : shortName, cssClass: icon ? `${ThemeIcon.asClassName(icon)} profile-activity-item` : 'profile-activity-item', icon: !!icon }; diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index b955a8c3efb..5b58848a51a 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -159,7 +159,7 @@ import { ExtensionIdentifier, ExtensionType, IExtension, IExtensionDescription, import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { ILayoutOffsetInfo } from 'vs/platform/layout/browser/layoutService'; -import { IUserDataProfilesService, toUserDataProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile, IUserDataProfilesService, toUserDataProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { UserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfileService'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { EnablementState, IExtensionManagementServer, IScannedExtension, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -2012,6 +2012,7 @@ export class TestUserDataProfileService implements IUserDataProfileService { readonly onDidChangeCurrentProfile = Event.None; readonly currentProfile = toUserDataProfile('test', 'test', URI.file('tests').with({ scheme: 'vscode-tests' })); async updateCurrentProfile(): Promise { } + getShortName(profile: IUserDataProfile): string { return profile.shortName ?? profile.name; } } export class TestWebExtensionsScannerService implements IWebExtensionsScannerService { From 8ebd4762c59aef37e7e9c88304a263962cc8dd8d Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 23 Sep 2022 18:13:21 +0200 Subject: [PATCH 017/599] explore auto-renderer profiling Use the longtask-performance observer to start heartbeat monitoring, use devtools profiling when heartbeat stop, send telemetry for expensive stacks. Unfortunately `inspector.sendCommand('Profiler.start')` doesn't have a chance to be dispatched while the window is frozen... --- src/vs/platform/native/common/native.ts | 5 + .../electron-main/nativeHostMainService.ts | 43 ++- src/vs/platform/profiling/common/profiling.ts | 2 +- .../electron-main/windowProfiling.ts | 258 ++++++++++++++++++ .../performance.contribution.ts | 8 + .../electron-sandbox/rendererAutoProfiler.ts | 104 +++++++ .../electron-browser/workbenchTestServices.ts | 4 +- 7 files changed, 421 insertions(+), 3 deletions(-) create mode 100644 src/vs/platform/profiling/electron-main/windowProfiling.ts create mode 100644 src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index 2a87cf7d285..2d4a245027d 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -163,6 +163,11 @@ export interface ICommonNativeHostService { toggleSharedProcessWindow(): Promise; sendInputEvent(event: MouseInputEvent): Promise; + // Perf Introspection + startHeartbeat(): Promise; + sendHeartbeat(): Promise; + stopHeartbeat(): Promise; + // Connectivity resolveProxy(url: string): Promise; findFreePort(startPort: number, giveUpAfter: number, timeout: number, stride?: number): Promise; diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index d5da363f058..1500fcdae5a 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -41,6 +41,8 @@ import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/worksp import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; import { VSBuffer } from 'vs/base/common/buffer'; import { hasWSLFeatureInstalled } from 'vs/platform/remote/node/wsl'; +import { WindowProfiler } from 'vs/platform/profiling/electron-main/windowProfiling'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export interface INativeHostMainService extends AddFirstParameterToFunctions /* only methods, not events */, number | undefined /* window ID */> { } @@ -59,7 +61,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain @ILogService private readonly logService: ILogService, @IProductService private readonly productService: IProductService, @IThemeMainService private readonly themeMainService: IThemeMainService, - @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService + @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService, + @ITelemetryService private readonly telemetryService: ITelemetryService, ) { super(); } @@ -777,6 +780,44 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#endregion + // #region Performance + + private readonly _profilingSessions = new Map(); + + async startHeartbeat(windowId: number | undefined): Promise { + const win = this.windowById(windowId); + if (!win || !win.win) { + return false; + } + if (!this._profilingSessions.has(win.id)) { + const session = new WindowProfiler(win.win, this.logService, this.telemetryService); + this._profilingSessions.set(win.id, session); + session.start(); + } + return true; + } + + async sendHeartbeat(windowId: number | undefined): Promise { + const win = this.windowById(windowId); + if (!win || !this._profilingSessions.has(win.id)) { + return false; + } + this._profilingSessions.get(win.id)!.receiveHeartbeat(); + return false; + } + + async stopHeartbeat(windowId: number | undefined): Promise { + const win = this.windowById(windowId); + if (!win || !this._profilingSessions.has(win.id)) { + return false; + } + this._profilingSessions.get(win.id)!.stop(); + this._profilingSessions.delete(win.id); + return false; + } + + // #endregion + //#region Registry (windows) diff --git a/src/vs/platform/profiling/common/profiling.ts b/src/vs/platform/profiling/common/profiling.ts index 7c3e9bf142c..bf63e95ecc7 100644 --- a/src/vs/platform/profiling/common/profiling.ts +++ b/src/vs/platform/profiling/common/profiling.ts @@ -48,7 +48,7 @@ export namespace Utils { export function rewriteAbsolutePaths(profile: IV8Profile, replace: string = 'noAbsolutePaths') { for (const node of profile.nodes) { if (node.callFrame && node.callFrame.url) { - if (isAbsolute(node.callFrame.url) || /^\w[\w\d+.-]*:\/\/\//.test(node.callFrame.url)) { + if (isAbsolute(node.callFrame.url) || /^\w[\w\d+.-]*:\/\/\/?/.test(node.callFrame.url)) { node.callFrame.url = join(replace, basename(node.callFrame.url)); } } diff --git a/src/vs/platform/profiling/electron-main/windowProfiling.ts b/src/vs/platform/profiling/electron-main/windowProfiling.ts new file mode 100644 index 00000000000..c78139af4d9 --- /dev/null +++ b/src/vs/platform/profiling/electron-main/windowProfiling.ts @@ -0,0 +1,258 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { Profile, ProfileNode, ProfileResult } from 'v8-inspect-profiler'; +import { BrowserWindow } from 'electron'; +import { timeout } from 'vs/base/common/async'; +import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Promises } from 'vs/base/node/pfs'; +import { tmpdir } from 'os'; +import { join } from 'vs/base/common/path'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { Utils } from 'vs/platform/profiling/common/profiling'; + + +type TelemetryHeavyCall = { + session: number; + selfTime: number; + totalTime: number; + functionName: string; + callstack: string; +}; + +type TelemetryHeavyCallClassification = { + owner: 'jrieken'; + comment: 'A callstack that took a long time to execute'; + session: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate call from one profile' }; + selfTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Self time of the function' }; + totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Total time of the function' }; + functionName: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The name of the function' }; + callstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The stacktrace leading into the function' }; +}; + +class Node { + + // these are set later + parent: Node | undefined; + children: Node[] = []; + selfTime: number = -1; + totalTime: number = -1; + + constructor( + readonly node: ProfileNode, + readonly callFrame: typeof node.callFrame, + ) { + // noop + } + + toString() { + return `${this.callFrame.url}#${this.callFrame.functionName}@${this.callFrame.lineNumber}:${this.callFrame.columnNumber}`; + } + + static makeTotals(call: Node) { + if (call.totalTime !== -1) { + return call.totalTime; + } + let result = call.selfTime; + for (const child of call.children) { + result += Node.makeTotals(child); + } + call.totalTime = result; + return result; + } +} + +export class WindowProfiler { + + private static _idPool = 1; + + readonly id: number = WindowProfiler._idPool++; + + private _profileAtOrAfter: number = 0; + private _session = new DisposableStore(); + private _isProfiling?: Promise; + + private _isStarted: boolean = false; + + constructor( + private readonly _window: BrowserWindow, + @ILogService private readonly _logService: ILogService, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + ) { + // noop + } + + async stop() { + + await this._isProfiling; + + this._logService.warn('[perf] STOPPING to monitor renderer', this.id); + this._session.clear(); + + try { + const inspector = this._window.webContents.debugger; + await inspector.sendCommand('Profiler.disable'); + inspector.detach(); + } catch (error) { + this._logService.error('[perf] FAILED to disable profiler', this.id); + } + } + + receiveHeartbeat(): void { + this._profileAtOrAfter = Date.now() + 1000; + // this._logService.info('[perf] received heartbeat', this.id); + } + + async start() { + if (this._isStarted) { + this._logService.warn('[perf] already STARTED, ignoring request', this.id); + return; + } + + try { + const inspector = this._window.webContents.debugger; + inspector.attach(); + await inspector.sendCommand('Profiler.enable'); + } catch (error) { + this._logService.error('[perf] FAILED to enable profiler', this.id); + return; + } + + this._logService.warn('[perf] started to EXPECT frequent heartbeat', this.id); + + this._session.clear(); + this._profileAtOrAfter = Date.now(); + + const handle = setInterval(() => { + if (Date.now() >= this._profileAtOrAfter) { + clearInterval(handle); + this._captureRendererProfile(); + } + }, 500); + + this._session.add(toDisposable(() => { + this._isStarted = false; + clearInterval(handle); + })); + } + + + private async _captureRendererProfile(): Promise { + this._logService.warn('[perf] MISSED heartbeat, trying to profile renderer', this.id); + + const profiling = (async () => { + const inspector = this._window.webContents.debugger; + await inspector.sendCommand('Profiler.start'); + this._logService.warn('[perf] profiling STARTED', this.id); + await timeout(5000); + const res: ProfileResult = await inspector.sendCommand('Profiler.stop'); + this._logService.warn('[perf] profiling DONE', this.id); + await this._store(res.profile); + this._digest(res.profile); + })(); + + this._isProfiling = profiling + .catch(err => { + this._logService.error('[perf] profiling the renderer FAILED', this.id); + this._logService.error(err); + }).finally(() => { + this._isProfiling = undefined; + }); + } + + private async _store(profile: Profile): Promise { + try { + const path = join(tmpdir(), `renderer-profile-${Date.now()}.cpuprofile`); + await Promises.writeFile(path, JSON.stringify(profile)); + this._logService.info('[perf] stored profile to DISK', this.id, path); + } catch (error) { + this._logService.error('[perf] FAILED to write profile to disk', this.id, error); + } + } + + private _digest(profile: Profile): void { + // https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-Profile + + if (!profile.samples || !profile.timeDeltas) { + this._logService.warn('[perf] INVALID profile: no samples or timeDeltas', this.id); + return; + } + + // PII removal - no absolute paths + Utils.rewriteAbsolutePaths(profile, 'piiRemoved'); + + // create nodes + const all = new Map(); + for (const node of profile.nodes) { + all.set(node.id, new Node(node, node.callFrame)); + } + + // set children/parents + for (const node of profile.nodes) { + if (node.children) { + const parent = all.get(node.id)!; + for (const id of node.children) { + const child = all.get(id)!; + parent.children.push(child); + child.parent = parent; + } + } + } + + // SELF times + const duration = (profile.endTime - profile.startTime); + let lastNodeTime = duration - profile.timeDeltas[0]; + for (let i = 0; i < profile.samples.length - 1; i++) { + const sample = profile.samples[i]; + const node = all.get(sample); + if (node) { + const duration = profile.timeDeltas[i + 1]; + node.selfTime += duration; + lastNodeTime -= duration; + } + } + const lastNode = all.get(profile.samples[profile.samples.length - 1]); + if (lastNode) { + lastNode.selfTime += lastNodeTime; + } + + // TOTAL times + all.forEach(Node.makeTotals); + + const session = Date.now(); + const sorted = Array.from(all.values()).sort((a, b) => b.selfTime - a.selfTime); + + if (sorted[0].callFrame.functionName === '(idle)') { + this._logService.warn('[perf] top stack is IDLE, ignoring this profile...', this.id); + return; + } + + for (let i = 0; i < sorted.length; i++) { + if (i > 4) { + // report top 5 + break; + } + const node = sorted[i]; + const callstack: string[] = []; + let candidate: Node | undefined = node; + while (candidate) { + callstack.push(candidate.toString()); + candidate = candidate.parent; + } + + const data: TelemetryHeavyCall = { + session, + selfTime: node.selfTime / 1000, + totalTime: node.totalTime / 1000, + functionName: node.callFrame.functionName, + callstack: callstack.join('\n') + }; + this._telemetryService.publicLog2('prof.slowcall', data); + + console.log(data); + } + } +} diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts b/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts index 36df52641bc..35adfeaff21 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts @@ -8,6 +8,14 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { StartupProfiler } from './startupProfiler'; import { StartupTimings } from './startupTimings'; +import { RendererProfiling } from 'vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler'; + + +Registry.as(Extensions.Workbench).registerWorkbenchContribution( + RendererProfiling, + 'RendererProfiling', + LifecyclePhase.Eventually +); // -- startup profiler diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts new file mode 100644 index 00000000000..9df4bdd7375 --- /dev/null +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { ITimerService } from 'vs/workbench/services/timer/browser/timerService'; + + +export class RendererProfiling { + + private readonly _disposables = new DisposableStore(); + + constructor( + @ITimerService timerService: ITimerService, + @INativeHostService nativeHostService: INativeHostService, + @ILogService logService: ILogService, + ) { + + + timerService.whenReady().then(() => { + const slowThreshold = (timerService.startupMetrics.timers.ellapsedRequire / 2) | 0; + + const sessionDisposables = this._disposables.add(new DisposableStore()); + + const obs = new PerformanceObserver(list => { + + let maxDuration = 0; + for (const entry of list.getEntries()) { + maxDuration = Math.max(maxDuration, entry.duration); + } + obs.takeRecords(); + + if (maxDuration < slowThreshold) { + return; + } + + // pause observation, we'll take a detailed look + obs.disconnect(); + + nativeHostService.startHeartbeat().then(success => { + if (!success) { + logService.warn('[perf] FAILED to start heartbeat sending'); + return; + } + logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), started to send heartbeat`); + + // start sending a repeated heartbeat which is expected to be received by the main side + const handle1 = setInterval(() => nativeHostService.sendHeartbeat(), 500); + + // stop heartbeat after 20s + const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); + + // cleanup + // - stop heartbeat + // - reconnect perf observer + sessionDisposables.add(toDisposable(() => { + clearInterval(handle1); + clearTimeout(handle2); + nativeHostService.stopHeartbeat(); + logService.warn(`[perf] STOPPING to send heartbeat`); + + obs.observe({ entryTypes: ['longtask'] }); + })); + + }); + }); + + this._disposables.add(toDisposable(() => obs.disconnect())); + obs.observe({ entryTypes: ['longtask'] }); + }); + } + + dispose(): void { + this._disposables.dispose(); + } +} + + +registerAction2(class SLOW extends Action2 { + + constructor() { + super({ + id: 'slow.fib', + title: 'Fib(N)', + f1: true, + }); + } + + run(accessor: ServicesAccessor, ...args: any[]): void { + function fib(n: number): number { + if (n <= 2) { + return n; + } + return fib(n - 1) + fib(n - 2); + } + + console.log('fib(44): ', fib(44)); + } +}); diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index ac3c3da9155..fc06130a04a 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -188,7 +188,6 @@ export class TestSharedProcessService implements ISharedProcessService { } export class TestNativeHostService implements INativeHostService { - declare readonly _serviceBrand: undefined; readonly windowId = -1; @@ -276,6 +275,9 @@ export class TestNativeHostService implements INativeHostService { async hasClipboard(format: string, type?: 'selection' | 'clipboard' | undefined): Promise { return false; } async sendInputEvent(event: MouseInputEvent): Promise { } async windowsGetStringRegKey(hive: 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG', path: string, name: string): Promise { return undefined; } + async startHeartbeat(): Promise { return false; } + async sendHeartbeat(): Promise { return false; } + async stopHeartbeat(): Promise { return false; } } export function workbenchInstantiationService(disposables = new DisposableStore()): ITestInstantiationService { From 9e7eb0d8be8a47ed95cd43aeb4db2a9212b38ca5 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 23 Sep 2022 11:12:25 -0700 Subject: [PATCH 018/599] Expose scrollable element delegatePointerDown in List View --- src/vs/base/browser/ui/list/listView.ts | 8 ++++++-- src/vs/base/browser/ui/scrollbar/scrollableElement.ts | 2 +- .../contrib/notebook/browser/diff/notebookTextDiffList.ts | 6 +++++- .../contrib/notebook/browser/view/notebookCellList.ts | 6 +++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 7e9f2aecba6..d8d980a9cfc 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -405,8 +405,12 @@ export class ListView implements ISpliceable, IDisposable { } } - triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { - this.scrollableElement.triggerScrollFromMouseWheelEvent(browserEvent); + delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { + this.scrollableElement.delegateScrollFromMouseWheelEvent(browserEvent); + } + + delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent) { + this.scrollableElement.delegateVerticalScrollbarPointerDown(browserEvent); } updateElementHeight(index: number, size: number | undefined, anchorIndex: number | null): void { diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index c7bffd0c8d6..b6b6c32a1dc 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -334,7 +334,7 @@ export abstract class AbstractScrollableElement extends Widget { this._revealOnScroll = value; } - public triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { + public delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { this._onMouseWheel(new StandardWheelEvent(browserEvent)); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 0ec024ae116..3504ac2a58d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -336,7 +336,11 @@ export class NotebookTextDiffList extends WorkbenchList implements ID } triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { - this.view.triggerScrollFromMouseWheelEvent(browserEvent); + this.view.delegateScrollFromMouseWheelEvent(browserEvent); + } + + delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent) { + this.view.delegateVerticalScrollbarPointerDown(browserEvent); } isElementAboveViewport(index: number) { From bf3cbdff018c839866cff04299de400b3ca64c32 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 23 Sep 2022 11:13:09 -0700 Subject: [PATCH 019/599] hook up overview ruler with notebook diff editor --- .../notebook/browser/diff/notebookDiff.css | 29 ++- .../browser/diff/notebookDiffEditorBrowser.ts | 4 + .../browser/diff/notebookDiffOverviewRuler.ts | 192 ++++++++++++++++++ .../browser/diff/notebookTextDiffEditor.ts | 53 ++++- 4 files changed, 266 insertions(+), 12 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 801d217ba08..cdd889d3afa 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -16,6 +16,10 @@ width: 50%; } */ +.notebook-text-diff-editor { + position: relative; +}; + .notebook-text-diff-editor .cell-body { display: flex; flex-direction: row; @@ -61,7 +65,7 @@ /* overflow: hidden; */ } -.notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { +.notebook-text-diff-editor > .notebook-diff-list-view > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { cursor: default; } @@ -142,13 +146,13 @@ overflow: hidden; } -.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { +.monaco-workbench .notebook-text-diff-editor > .notebook-diff-list-view > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { overflow: visible !important; } -.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row, -.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover, -.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { +.monaco-workbench .notebook-text-diff-editor > .notebook-diff-list-view > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row, +.monaco-workbench .notebook-text-diff-editor > .notebook-diff-list-view > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover, +.monaco-workbench .notebook-text-diff-editor > .notebook-diff-list-view > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { outline: none !important; background-color: transparent !important; } @@ -287,3 +291,18 @@ left: 4px !important; width: 15px !important; } + +.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .scrollbar.visible { + z-index: var(--z-index-notebook-scrollbar); + cursor: default; +} + +.notebook-text-diff-editor .notebook-overview-ruler-container { + position: absolute; + top: 0; + right: 0; +} + +.notebook-text-diff-editor .notebook-overview-ruler-container .diffViewport { + z-index: var(--notebook-diff-view-viewport-slider); +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index ebb303246b8..13559d512e4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -30,9 +30,12 @@ export interface INotebookTextDiffEditor { notebookOptions: NotebookOptions; readonly textModel?: NotebookTextModel; onMouseUp: Event<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase }>; + onDidScroll: Event; onDidDynamicOutputRendered: Event<{ cell: IGenericCellViewModel; output: ICellOutputViewModel }>; getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; + getScrollTop(): number; + getScrollHeight(): number; layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; createOutput(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void; showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, displayOutput: ICellOutputViewModel, diffSide: DiffSide): void; @@ -42,6 +45,7 @@ export interface INotebookTextDiffEditor { * Trigger the editor to scroll from scroll event programmatically */ triggerScroll(event: IMouseWheelEvent): void; + delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent): void; getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): Promise; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): Promise; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts new file mode 100644 index 00000000000..08e81c40f0f --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts @@ -0,0 +1,192 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as browser from 'vs/base/browser/browser'; +import * as DOM from 'vs/base/browser/dom'; +import { createFastDomNode, FastDomNode } from 'vs/base/browser/fastDomNode'; +import { Color } from 'vs/base/common/color'; +import { defaultInsertColor, defaultRemoveColor, diffInserted, diffOverviewRulerInserted, diffOverviewRulerRemoved, diffRemoved, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; +import { IColorTheme, IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService'; +import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; +import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; + +export class NotebookDiffOverviewRuler extends Themable { + private readonly _domNode: FastDomNode; + private readonly _overviewViewportDomElement: FastDomNode; + + private _diffElementViewModels: DiffElementViewModelBase[] = []; + private _lanes = 2; + + protected _insertColor: Color | null; + protected _removeColor: Color | null; + + constructor(readonly notebookEditor: INotebookTextDiffEditor, readonly width: number, container: HTMLElement, @IThemeService themeService: IThemeService) { + super(themeService); + this._insertColor = null; + this._removeColor = null; + this._domNode = createFastDomNode(document.createElement('canvas')); + this._domNode.setPosition('relative'); + this._domNode.setLayerHinting(true); + this._domNode.setContain('strict'); + + container.appendChild(this._domNode.domNode); + + this._overviewViewportDomElement = createFastDomNode(document.createElement('div')); + this._overviewViewportDomElement.setClassName('diffViewport'); + this._overviewViewportDomElement.setPosition('absolute'); + this._overviewViewportDomElement.setWidth(width); + container.appendChild(this._overviewViewportDomElement.domNode); + + this._register(browser.PixelRatio.onDidChange(() => { + this.layout(); + })); + + this._register(this.themeService.onDidColorThemeChange(e => { + const colorChanged = this.applyColors(e); + if (colorChanged) { + this.layout(); + } + })); + this.applyColors(this.themeService.getColorTheme()); + + this._register(this.notebookEditor.onDidScroll(() => { + this._layoutOverviewViewport(); + })); + + this._register(DOM.addStandardDisposableListener(this._overviewViewportDomElement.domNode, DOM.EventType.POINTER_DOWN, (e) => { + this.notebookEditor.delegateVerticalScrollbarPointerDown(e); + })); + } + + private applyColors(theme: IColorTheme): boolean { + const newInsertColor = theme.getColor(diffOverviewRulerInserted) || (theme.getColor(diffInserted) || defaultInsertColor).transparent(2); + const newRemoveColor = theme.getColor(diffOverviewRulerRemoved) || (theme.getColor(diffRemoved) || defaultRemoveColor).transparent(2); + const hasChanges = !newInsertColor.equals(this._insertColor) || !newRemoveColor.equals(this._removeColor); + this._insertColor = newInsertColor; + this._removeColor = newRemoveColor; + return hasChanges; + } + + layout() { + const layoutInfo = this.notebookEditor.getLayoutInfo(); + const scrollHeight = layoutInfo.scrollHeight; + const height = layoutInfo.height; + const ratio = browser.PixelRatio.value; + this._domNode.setWidth(this.width); + this._domNode.setHeight(height); + this._domNode.domNode.width = this.width * ratio; + this._domNode.domNode.height = height * ratio; + const ctx = this._domNode.domNode.getContext('2d')!; + ctx.clearRect(0, 0, this.width * ratio, height * ratio); + this._render(ctx, this.width * ratio, height * ratio, scrollHeight * ratio, ratio); + this._layoutOverviewViewport(); + } + + updateViewModels(elements: DiffElementViewModelBase[]) { + this._diffElementViewModels = elements; + this.layout(); + } + + + private _layoutOverviewViewport(): void { + const layout = this._computeOverviewViewport(); + if (!layout) { + this._overviewViewportDomElement.setTop(0); + this._overviewViewportDomElement.setHeight(0); + } else { + this._overviewViewportDomElement.setTop(layout.top); + this._overviewViewportDomElement.setHeight(layout.height); + } + } + + private _computeOverviewViewport(): { height: number; top: number } | null { + const layoutInfo = this.notebookEditor.getLayoutInfo(); + if (!layoutInfo) { + return null; + } + + const scrollTop = this.notebookEditor.getScrollTop(); + const scrollHeight = this.notebookEditor.getScrollHeight(); + + const computedAvailableSize = Math.max(0, layoutInfo.height); + const computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * 0); + const computedRatio = scrollHeight > 0 ? (computedRepresentableSize / scrollHeight) : 0; + + const computedSliderSize = Math.max(0, Math.floor(layoutInfo.height * computedRatio)); + const computedSliderPosition = Math.floor(scrollTop * computedRatio); + + return { + height: computedSliderSize, + top: computedSliderPosition + }; + } + + private _render(ctx: CanvasRenderingContext2D, width: number, height: number, scrollHeight: number, ratio: number) { + if (!this._insertColor || !this._removeColor) { + // no op when colors are not yet known + return; + } + + const insertColorHex = Color.Format.CSS.formatHexA(this._insertColor); + const removeColorHex = Color.Format.CSS.formatHexA(this._removeColor); + + const laneWidth = width / this._lanes; + let currentFrom = 0; + for (let i = 0; i < this._diffElementViewModels.length; i++) { + const element = this._diffElementViewModels[i]; + + const cellHeight = element.layoutInfo.totalHeight * ratio; + switch (element.type) { + case 'insert': + ctx.fillStyle = insertColorHex; + ctx.fillRect(laneWidth, currentFrom, laneWidth, cellHeight); + break; + case 'delete': + ctx.fillStyle = removeColorHex; + ctx.fillRect(0, currentFrom, laneWidth, cellHeight); + break; + case 'unchanged': + break; + case 'modified': + ctx.fillStyle = removeColorHex; + ctx.fillRect(0, currentFrom, laneWidth, cellHeight); + ctx.fillStyle = insertColorHex; + ctx.fillRect(laneWidth, currentFrom, laneWidth, cellHeight); + break; + } + + currentFrom += cellHeight; + } + } +} + +registerThemingParticipant((theme, collector) => { + const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground); + if (scrollbarSliderBackgroundColor) { + collector.addRule(` + .notebook-text-diff-editor .diffViewport { + background: ${scrollbarSliderBackgroundColor}; + } + `); + } + + const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground); + if (scrollbarSliderHoverBackgroundColor) { + collector.addRule(` + .notebook-text-diff-editor .diffViewport:hover { + background: ${scrollbarSliderHoverBackgroundColor}; + } + `); + } + + const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground); + if (scrollbarSliderActiveBackgroundColor) { + collector.addRule(` + .notebook-text-diff-editor .diffViewport:active { + background: ${scrollbarSliderActiveBackgroundColor}; + } + `); + } +}); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 53f2626ba24..7e9ee0bc76c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -44,6 +44,8 @@ import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/co import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { cellIndexesToRanges, cellRangesToIndexes } from 'vs/workbench/contrib/notebook/common/notebookRange'; +import { NotebookDiffOverviewRuler } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler'; +import { registerZIndex, ZIndex } from 'vs/platform/layout/browser/zIndexRegistry'; const $ = DOM.$; @@ -82,11 +84,15 @@ class NotebookDiffEditorSelection implements IEditorPaneSelection { } export class NotebookTextDiffEditor extends EditorPane implements INotebookTextDiffEditor, INotebookDelegateForWebview, IEditorPaneWithSelection { + public static readonly ENTIRE_DIFF_OVERVIEW_WIDTH = 30; creationOptions: INotebookEditorCreationOptions = getDefaultNotebookCreationOptions(); static readonly ID: string = NOTEBOOK_DIFF_EDITOR_ID; private _rootElement!: HTMLElement; + private _listViewContainer!: HTMLElement; private _overflowContainer!: HTMLElement; + private _overviewRulerContainer!: HTMLElement; + private _overviewRuler!: NotebookDiffOverviewRuler; private _dimension: DOM.Dimension | null = null; private _diffElementViewModels: DiffElementViewModelBase[] = []; private _list!: NotebookTextDiffList; @@ -97,6 +103,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase }>()); public readonly onMouseUp = this._onMouseUp.event; + private readonly _onDidScroll = this._register(new Emitter()); + readonly onDidScroll: Event = this._onDidScroll.event; private _eventDispatcher: NotebookDiffEditorEventDispatcher | undefined; protected _scopeContextKeyService!: IContextKeyService; private _model: INotebookDiffEditorModel | null = null; @@ -166,6 +174,18 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // throw new Error('Method not implemented.'); } + getScrollTop() { + return this._list?.scrollTop ?? 0; + } + + getScrollHeight() { + return this._list?.scrollHeight ?? 0; + } + + delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent) { + this._list?.delegateVerticalScrollbarPointerDown(browserEvent); + } + updateOutputHeight(cellInfo: IDiffCellInfo, output: ICellOutputViewModel, outputHeight: number, isInit: boolean): void { const diffElement = cellInfo.diffElement; const cell = this.getCellByInfo(cellInfo); @@ -217,10 +237,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this.instantiationService.createInstance(CellDiffSideBySideRenderer, this), ]; + this._listViewContainer = DOM.append(this._rootElement, DOM.$('.notebook-diff-list-view')); + this._list = this.instantiationService.createInstance( NotebookTextDiffList, 'NotebookTextDiff', - this._rootElement, + this._listViewContainer, this.instantiationService.createInstance(NotebookCellTextDiffListDelegate), renderers, this.contextKeyService, @@ -274,8 +296,17 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } })); + this._register(this._list.onDidScroll(() => { + this._onDidScroll.fire(); + })); + this._register(this._list.onDidChangeFocus(() => this._onDidChangeSelection.fire({ reason: EditorPaneSelectionChangeReason.USER }))); + this._overviewRulerContainer = document.createElement('div'); + this._overviewRulerContainer.classList.add('notebook-overview-ruler-container'); + this._rootElement.appendChild(this._overviewRulerContainer); + this._registerOverviewRuler(); + // transparent cover this._webviewTransparentCover = DOM.append(this._list.rowsContainer, $('.webview-cover')); this._webviewTransparentCover.style.display = 'none'; @@ -296,8 +327,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._register(this._list.onDidScroll(e => { this._webviewTransparentCover!.style.top = `${e.scrollTop}px`; })); + } - + private _registerOverviewRuler() { + this._overviewRuler = this._register(this.instantiationService.createInstance(NotebookDiffOverviewRuler, this, NotebookTextDiffEditor.ENTIRE_DIFF_OVERVIEW_WIDTH, this._overviewRulerContainer!)); } private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined, diffSide: DiffSide) { @@ -526,6 +559,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _setViewModel(viewModels: DiffElementViewModelBase[]) { this._diffElementViewModels = viewModels; this._list.splice(0, this._list.length, this._diffElementViewModels); + this._overviewRuler.updateViewModels(this._diffElementViewModels); } /** @@ -942,12 +976,13 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD layout(dimension: DOM.Dimension): void { this._rootElement.classList.toggle('mid-width', dimension.width < 1000 && dimension.width >= 600); this._rootElement.classList.toggle('narrow-width', dimension.width < 600); - this._dimension = dimension; - this._rootElement.style.height = `${dimension.height}px`; + this._dimension = dimension.with(dimension.width - NotebookTextDiffEditor.ENTIRE_DIFF_OVERVIEW_WIDTH); + + this._listViewContainer.style.height = `${dimension.height}px`; + this._listViewContainer.style.width = `${this._dimension.width}px`; this._list?.layout(this._dimension.height, this._dimension.width); - if (this._modifiedWebview) { this._modifiedWebview.element.style.width = `calc(50% - 16px)`; this._modifiedWebview.element.style.left = `calc(50%)`; @@ -959,10 +994,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } if (this._webviewTransparentCover) { - this._webviewTransparentCover.style.height = `${dimension.height}px`; - this._webviewTransparentCover.style.width = `${dimension.width}px`; + this._webviewTransparentCover.style.height = `${this._dimension.height}px`; + this._webviewTransparentCover.style.width = `${this._dimension.width}px`; } + this._overviewRuler.layout(); + this._eventDispatcher?.emit([new NotebookDiffLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } @@ -974,6 +1011,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } } +registerZIndex(ZIndex.Base, 10, 'notebook-diff-view-viewport-slider'); + registerThemingParticipant((theme, collector) => { const cellBorderColor = theme.getColor(notebookCellBorder); if (cellBorderColor) { From b4cf032804b3b12569a1b9e03c3dd50c67b2964b Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 23 Sep 2022 12:02:49 -0700 Subject: [PATCH 020/599] Update overview once per frame --- .../browser/diff/notebookDiffOverviewRuler.ts | 99 ++++++++++++++----- .../browser/diff/notebookTextDiffEditor.ts | 2 +- 2 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts index 08e81c40f0f..c446f07e32b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts @@ -7,9 +7,11 @@ import * as browser from 'vs/base/browser/browser'; import * as DOM from 'vs/base/browser/dom'; import { createFastDomNode, FastDomNode } from 'vs/base/browser/fastDomNode'; import { Color } from 'vs/base/common/color'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { defaultInsertColor, defaultRemoveColor, diffInserted, diffOverviewRulerInserted, diffOverviewRulerRemoved, diffRemoved, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme, IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService'; import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; +import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; export class NotebookDiffOverviewRuler extends Themable { @@ -19,13 +21,22 @@ export class NotebookDiffOverviewRuler extends Themable { private _diffElementViewModels: DiffElementViewModelBase[] = []; private _lanes = 2; - protected _insertColor: Color | null; - protected _removeColor: Color | null; + private _insertColor: Color | null; + private _insertColorHex: string | null; + private _removeColor: Color | null; + private _removeColorHex: string | null; + + private _disposables: DisposableStore; + private _renderAnimationFrame: IDisposable | null; constructor(readonly notebookEditor: INotebookTextDiffEditor, readonly width: number, container: HTMLElement, @IThemeService themeService: IThemeService) { super(themeService); this._insertColor = null; this._removeColor = null; + this._insertColorHex = null; + this._removeColorHex = null; + this._disposables = this._register(new DisposableStore()); + this._renderAnimationFrame = null; this._domNode = createFastDomNode(document.createElement('canvas')); this._domNode.setPosition('relative'); this._domNode.setLayerHinting(true); @@ -40,19 +51,19 @@ export class NotebookDiffOverviewRuler extends Themable { container.appendChild(this._overviewViewportDomElement.domNode); this._register(browser.PixelRatio.onDidChange(() => { - this.layout(); + this._scheduleRender(); })); this._register(this.themeService.onDidColorThemeChange(e => { const colorChanged = this.applyColors(e); if (colorChanged) { - this.layout(); + this._scheduleRender(); } })); this.applyColors(this.themeService.getColorTheme()); this._register(this.notebookEditor.onDidScroll(() => { - this._layoutOverviewViewport(); + this._renderOverviewViewport(); })); this._register(DOM.addStandardDisposableListener(this._overviewViewportDomElement.domNode, DOM.EventType.POINTER_DOWN, (e) => { @@ -66,12 +77,52 @@ export class NotebookDiffOverviewRuler extends Themable { const hasChanges = !newInsertColor.equals(this._insertColor) || !newRemoveColor.equals(this._removeColor); this._insertColor = newInsertColor; this._removeColor = newRemoveColor; + if (this._insertColor) { + this._insertColorHex = Color.Format.CSS.formatHexA(this._insertColor); + } + + if (this._removeColor) { + this._removeColorHex = Color.Format.CSS.formatHexA(this._removeColor); + } + return hasChanges; } layout() { + this._layoutNow(); + } + + updateViewModels(elements: DiffElementViewModelBase[], eventDispatcher: NotebookDiffEditorEventDispatcher | undefined) { + this._disposables.clear(); + + this._diffElementViewModels = elements; + + if (eventDispatcher) { + this._disposables.add(eventDispatcher.onDidChangeLayout(() => { + this._scheduleRender(); + })); + + this._disposables.add(eventDispatcher.onDidChangeCellLayout(() => { + this._scheduleRender(); + })); + } + + this._scheduleRender(); + } + + private _scheduleRender(): void { + if (this._renderAnimationFrame === null) { + this._renderAnimationFrame = DOM.runAtThisOrScheduleAtNextAnimationFrame(this._onRenderScheduled.bind(this), 100); + } + } + + private _onRenderScheduled(): void { + this._renderAnimationFrame = null; + this._layoutNow(); + } + + private _layoutNow() { const layoutInfo = this.notebookEditor.getLayoutInfo(); - const scrollHeight = layoutInfo.scrollHeight; const height = layoutInfo.height; const ratio = browser.PixelRatio.value; this._domNode.setWidth(this.width); @@ -80,17 +131,11 @@ export class NotebookDiffOverviewRuler extends Themable { this._domNode.domNode.height = height * ratio; const ctx = this._domNode.domNode.getContext('2d')!; ctx.clearRect(0, 0, this.width * ratio, height * ratio); - this._render(ctx, this.width * ratio, height * ratio, scrollHeight * ratio, ratio); - this._layoutOverviewViewport(); + this._renderCanvas(ctx, this.width * ratio, ratio); + this._renderOverviewViewport(); } - updateViewModels(elements: DiffElementViewModelBase[]) { - this._diffElementViewModels = elements; - this.layout(); - } - - - private _layoutOverviewViewport(): void { + private _renderOverviewViewport(): void { const layout = this._computeOverviewViewport(); if (!layout) { this._overviewViewportDomElement.setTop(0); @@ -123,15 +168,12 @@ export class NotebookDiffOverviewRuler extends Themable { }; } - private _render(ctx: CanvasRenderingContext2D, width: number, height: number, scrollHeight: number, ratio: number) { - if (!this._insertColor || !this._removeColor) { + private _renderCanvas(ctx: CanvasRenderingContext2D, width: number, ratio: number) { + if (!this._insertColorHex || !this._removeColorHex) { // no op when colors are not yet known return; } - const insertColorHex = Color.Format.CSS.formatHexA(this._insertColor); - const removeColorHex = Color.Format.CSS.formatHexA(this._removeColor); - const laneWidth = width / this._lanes; let currentFrom = 0; for (let i = 0; i < this._diffElementViewModels.length; i++) { @@ -140,19 +182,19 @@ export class NotebookDiffOverviewRuler extends Themable { const cellHeight = element.layoutInfo.totalHeight * ratio; switch (element.type) { case 'insert': - ctx.fillStyle = insertColorHex; + ctx.fillStyle = this._insertColorHex; ctx.fillRect(laneWidth, currentFrom, laneWidth, cellHeight); break; case 'delete': - ctx.fillStyle = removeColorHex; + ctx.fillStyle = this._removeColorHex; ctx.fillRect(0, currentFrom, laneWidth, cellHeight); break; case 'unchanged': break; case 'modified': - ctx.fillStyle = removeColorHex; + ctx.fillStyle = this._removeColorHex; ctx.fillRect(0, currentFrom, laneWidth, cellHeight); - ctx.fillStyle = insertColorHex; + ctx.fillStyle = this._insertColorHex; ctx.fillRect(laneWidth, currentFrom, laneWidth, cellHeight); break; } @@ -160,6 +202,15 @@ export class NotebookDiffOverviewRuler extends Themable { currentFrom += cellHeight; } } + + override dispose() { + if (this._renderAnimationFrame !== null) { + this._renderAnimationFrame.dispose(); + this._renderAnimationFrame = null; + } + + super.dispose(); + } } registerThemingParticipant((theme, collector) => { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 7e9ee0bc76c..977573bf87d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -559,7 +559,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _setViewModel(viewModels: DiffElementViewModelBase[]) { this._diffElementViewModels = viewModels; this._list.splice(0, this._list.length, this._diffElementViewModels); - this._overviewRuler.updateViewModels(this._diffElementViewModels); + this._overviewRuler.updateViewModels(this._diffElementViewModels, this._eventDispatcher); } /** From a609f1edcde374e9b4b10b076f99bd62b3d97f11 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 23 Sep 2022 13:14:07 -0700 Subject: [PATCH 021/599] fix diff css --- src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index cdd889d3afa..bb6786c48c2 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -18,7 +18,7 @@ .notebook-text-diff-editor { position: relative; -}; +} .notebook-text-diff-editor .cell-body { display: flex; From 3cd0a7f71255b41a6ee353f13e49d57d35127db0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 23 Sep 2022 13:23:20 -0700 Subject: [PATCH 022/599] Fix an issue where multiple tabs could open on ext .show() --- .../api/browser/mainThreadTerminalService.ts | 4 +- .../contrib/terminal/browser/terminal.ts | 2 +- .../terminal/browser/terminalActions.ts | 12 ++--- .../terminal/browser/terminalEditorService.ts | 47 +++++++++++-------- .../test/browser/workbenchTestServices.ts | 2 +- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index aa6848ff88a..d529c525786 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -170,9 +170,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape if (terminalInstance) { this._terminalService.setActiveInstance(terminalInstance); if (terminalInstance.target === TerminalLocation.Editor) { - this._terminalEditorService.revealActiveEditor(preserveFocus); + await this._terminalEditorService.revealActiveEditor(preserveFocus); } else { - this._terminalGroupService.showPanel(!preserveFocus); + await this._terminalGroupService.showPanel(!preserveFocus); } } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 56904518b62..d922faa8a8e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -242,7 +242,7 @@ export interface ITerminalEditorService extends ITerminalInstanceHost { detachActiveEditorInstance(): ITerminalInstance; detachInstance(instance: ITerminalInstance): void; splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance; - revealActiveEditor(preserveFocus?: boolean): void; + revealActiveEditor(preserveFocus?: boolean): Promise; resolveResource(instance: ITerminalInstance | URI): URI; reviveInput(deserializedInput: IDeserializedTerminalEditorInput): EditorInput; getInputFromResource(resource: URI): EditorInput; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index f0128ece068..1103c1a71ac 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -342,9 +342,9 @@ export function registerTerminalActions() { if (instance) { await instance.runRecent('command'); if (instance?.target === TerminalLocation.Editor) { - terminalEditorService.revealActiveEditor(); + await terminalEditorService.revealActiveEditor(); } else { - terminalGroupService.showPanel(false); + await terminalGroupService.showPanel(false); } } } @@ -392,9 +392,9 @@ export function registerTerminalActions() { if (instance) { await instance.runRecent('cwd'); if (instance?.target === TerminalLocation.Editor) { - terminalEditorService.revealActiveEditor(); + await terminalEditorService.revealActiveEditor(); } else { - terminalGroupService.showPanel(false); + await terminalGroupService.showPanel(false); } } } @@ -596,9 +596,9 @@ export function registerTerminalActions() { } instance.sendText(text, true); if (instance.target === TerminalLocation.Editor) { - terminalEditorService.revealActiveEditor(); + await terminalEditorService.revealActiveEditor(); } else { - terminalGroupService.showPanel(); + await terminalGroupService.showPanel(); } } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index c4b5c781128..dbd16927109 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -10,6 +10,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { EditorActivation } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IShellLaunchConfig, TerminalLocation } from 'vs/platform/terminal/common/terminal'; +import { IEditorPane } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IDeserializedTerminalEditorInput, ITerminalEditorService, ITerminalInstance, ITerminalInstanceService, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; @@ -26,6 +27,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor instances: ITerminalInstance[] = []; private _activeInstanceIndex: number = -1; private _isShuttingDown = false; + private _activeOpenEditorRequest?: { instanceId: number; promise: Promise }; private _terminalEditorActive: IContextKey; @@ -140,16 +142,21 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor async openEditor(instance: ITerminalInstance, editorOptions?: TerminalEditorLocation): Promise { const resource = this.resolveResource(instance); if (resource) { - await this._editorService.openEditor({ - resource, - description: instance.description || instance.shellLaunchConfig.type, - options: - { - pinned: true, - forceReload: true, - preserveFocus: editorOptions?.preserveFocus - } - }, editorOptions?.viewColumn || ACTIVE_GROUP); + await this._activeOpenEditorRequest?.promise; + this._activeOpenEditorRequest = { + instanceId: instance.instanceId, + promise: this._editorService.openEditor({ + resource, + description: instance.description || instance.shellLaunchConfig.type, + options: { + pinned: true, + forceReload: true, + preserveFocus: editorOptions?.preserveFocus + } + }, editorOptions?.viewColumn || ACTIVE_GROUP) + }; + await this._activeOpenEditorRequest?.promise; + this._activeOpenEditorRequest = undefined; } } @@ -173,9 +180,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this._editorService.openEditor(input, { pinned: true, forceReload: true - }, - input.group - ); + }, input.group); this._registerInstance(inputKey, input, instance); return instanceOrUri; }); @@ -232,13 +237,11 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this._editorService.openEditor({ resource: URI.revive(resource), description: instance.description, - options: - { + options: { pinned: true, forceReload: true } - }, - SIDE_GROUP); + }, SIDE_GROUP); } return instance; } @@ -294,12 +297,17 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this._onDidChangeInstances.fire(); } - revealActiveEditor(preserveFocus?: boolean): void { + async revealActiveEditor(preserveFocus?: boolean): Promise { const instance = this.activeInstance; if (!instance) { return; } + // If there is an active openEditor call for this instance it will be revealed by that + if (this._activeOpenEditorRequest?.instanceId === instance.instanceId) { + return; + } + const editorInput = this._editorInputs.get(instance.resource.path)!; this._editorService.openEditor( editorInput, @@ -308,8 +316,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor forceReload: true, preserveFocus, activation: EditorActivation.PRESERVE - }, - editorInput.group + } ); } } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index b955a8c3efb..5baa8488e4e 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1783,7 +1783,7 @@ export class TestTerminalEditorService implements ITerminalEditorService { detachActiveEditorInstance(): ITerminalInstance { throw new Error('Method not implemented.'); } detachInstance(instance: ITerminalInstance): void { throw new Error('Method not implemented.'); } splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance { throw new Error('Method not implemented.'); } - revealActiveEditor(preserveFocus?: boolean): void { throw new Error('Method not implemented.'); } + revealActiveEditor(preserveFocus?: boolean): Promise { throw new Error('Method not implemented.'); } resolveResource(instance: ITerminalInstance | URI): URI { throw new Error('Method not implemented.'); } reviveInput(deserializedInput: IDeserializedTerminalEditorInput): TerminalEditorInput { throw new Error('Method not implemented.'); } getInputFromResource(resource: URI): TerminalEditorInput { throw new Error('Method not implemented.'); } From 41bdf03368d2c03360c04ac596b9d3413bcc0886 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 23 Sep 2022 13:33:22 -0700 Subject: [PATCH 023/599] Use IExtHostInitDataService to get the language (#161625) --- src/vs/base/common/platform.ts | 2 +- .../api/common/extHostLocalizationService.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 506ee713281..f41a2f77df5 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -const LANGUAGE_DEFAULT = 'en'; +export const LANGUAGE_DEFAULT = 'en'; let _isWindows = false; let _isMacintosh = false; diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index 51006adaaaa..38f3b41f632 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -3,32 +3,38 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Language } from 'vs/base/common/platform'; +import { LANGUAGE_DEFAULT } from 'vs/base/common/platform'; import { format } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostLocalizationShape, IStringDetails, MainContext, MainThreadLocalizationShape } from 'vs/workbench/api/common/extHost.protocol'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; export class ExtHostLocalizationService implements ExtHostLocalizationShape { readonly _serviceBrand: undefined; private readonly _proxy: MainThreadLocalizationShape; + private readonly currentLanguage: string; + private readonly isDefaultLanguage: boolean; private readonly bundleCache: Map = new Map(); constructor( + @IExtHostInitDataService initData: IExtHostInitDataService, @IExtHostRpcService rpc: IExtHostRpcService, @ILogService private readonly logService: ILogService ) { this._proxy = rpc.getProxy(MainContext.MainThreadLocalization); + this.currentLanguage = initData.environment.appLanguage; + this.isDefaultLanguage = this.currentLanguage === LANGUAGE_DEFAULT; } getMessage(extensionId: string, details: IStringDetails): string { const { message, args, comment } = details; - if (Language.isDefault()) { + if (this.isDefaultLanguage) { return format(message, args); } @@ -52,7 +58,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { } async initializeLocalizedMessages(extension: IExtensionDescription): Promise { - if (Language.isDefault() + if (this.isDefaultLanguage // TODO: support builtin extensions || !extension.l10n ) { @@ -69,7 +75,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { this.logService.error(`No bundle location found for extension ${extension.identifier.value}`); return; } - const bundleUri = URI.joinPath(bundleLocation, `bundle.l10n.${Language.value()}.json`); + const bundleUri = URI.joinPath(bundleLocation, `bundle.l10n.${this.currentLanguage}.json`); try { const response = await this._proxy.$fetchBundleContents(bundleUri); From 9dc9b5a5bf4a0a12c402b9396d62704fc1978160 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 23 Sep 2022 14:05:48 -0700 Subject: [PATCH 024/599] update extension model to focus on last cell added through input box (#161630) * update extension model to focus on last cell added through input box * move service accessor to be with other calls --- .../interactive/browser/interactive.contribution.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 4647031ad07..51dbee30402 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -54,6 +54,7 @@ import { NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT } from 'vs/workbench/contrib/noteb import { INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService'; import { CellEditType, CellKind, CellUri, ICellOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -474,6 +475,7 @@ registerAction2(class extends Action2 { const editorService = accessor.get(IEditorService); const bulkEditService = accessor.get(IBulkEditService); const historyService = accessor.get(IInteractiveHistoryService); + const notebookEditorService = accessor.get(INotebookEditorService); let editorControl: { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined; if (context) { if (context.scheme === Schemas.vscodeInteractive) { @@ -514,6 +516,7 @@ registerAction2(class extends Action2 { outputCollapsed: false } : undefined; + await bulkEditService.apply([ new ResourceNotebookCellEdit(notebookDocument.uri, { @@ -534,8 +537,16 @@ registerAction2(class extends Action2 { ]); // reveal the cell into view first - editorControl.notebookEditor.revealCellRangeInView({ start: index, end: index + 1 }); + const range = { start: index, end: index + 1 }; + editorControl.notebookEditor.revealCellRangeInView(range); await editorControl.notebookEditor.executeNotebookCells(editorControl.notebookEditor.getCellsInRange({ start: index, end: index + 1 })); + + // update the selection and focus in the extension host model + const editor = notebookEditorService.getNotebookEditor(editorControl.notebookEditor.getId()); + if (editor) { + editor.setSelections([range]); + editor.setFocus(range); + } } } } From a82c06a66f29d08c75476648bd1c14aa17b5da74 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 23 Sep 2022 14:06:42 -0700 Subject: [PATCH 025/599] added IW commands to palette (#161533) * added IW commands to palette * disambiguate command category * don't hijack shift+tab keybinding --- .../browser/interactive.contribution.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 51dbee30402..0e31c344e68 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -325,7 +325,7 @@ registerAction2(class extends Action2 { id: '_interactive.open', title: { value: localize('interactive.open', "Open Interactive Window"), original: 'Open Interactive Window' }, f1: false, - category: 'Interactive', + category: 'Interactive Window', description: { description: localize('interactive.open', "Open Interactive Window"), args: [ @@ -441,7 +441,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.execute', title: { value: localize('interactive.execute', "Execute Code"), original: 'Execute Code' }, - category: 'Interactive', + category: 'Interactive Window', keybinding: { // when: NOTEBOOK_CELL_LIST_FOCUSED, when: ContextKeyExpr.equals('resourceScheme', Schemas.vscodeInteractive), @@ -557,7 +557,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.input.clear', title: { value: localize('interactive.input.clear', "Clear the interactive window input editor contents"), original: 'Clear the interactive window input editor contents' }, - category: 'Interactive', + category: 'Interactive Window', f1: false }); } @@ -583,7 +583,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.previous', title: { value: localize('interactive.history.previous', "Previous value in history"), original: 'Previous value in history' }, - category: 'Interactive', + category: 'Interactive Window', f1: false, keybinding: { when: ContextKeyExpr.and( @@ -622,7 +622,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.next', title: { value: localize('interactive.history.next', "Next value in history"), original: 'Next value in history' }, - category: 'Interactive', + category: 'Interactive Window', f1: false, keybinding: { when: ContextKeyExpr.and( @@ -668,7 +668,7 @@ registerAction2(class extends Action2 { mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }, weight: KeybindingWeight.WorkbenchContrib }, - category: 'Interactive', + category: 'Interactive Window', }); } @@ -697,7 +697,7 @@ registerAction2(class extends Action2 { mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, weight: KeybindingWeight.WorkbenchContrib }, - category: 'Interactive', + category: 'Interactive Window', }); } @@ -721,8 +721,8 @@ registerAction2(class extends Action2 { super({ id: 'interactive.input.focus', title: { value: localize('interactive.input.focus', "Focus input editor in the interactive window"), original: 'Focus input editor in the interactive window' }, - category: 'Interactive', - f1: false + category: 'Interactive Window', + f1: true }); } @@ -756,8 +756,9 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.focus', title: { value: localize('interactive.history.focus', "Focus history in the interactive window"), original: 'Focus input editor in the interactive window' }, - category: 'Interactive', - f1: false + category: 'Interactive Window', + f1: true, + precondition: ContextKeyExpr.equals('resourceScheme', Schemas.vscodeInteractive), }); } From 951a35c4361773de60ef301a36650f6655848e28 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Fri, 23 Sep 2022 14:14:14 -0700 Subject: [PATCH 026/599] reposition search tree button (#161632) --- .../workbench/contrib/search/browser/search.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 6cedf1989b2..3f8f2efa982 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -511,7 +511,7 @@ registerAction2(class ViewAsTreeAction extends Action2 { menu: [{ id: MenuId.ViewTitle, group: 'navigation', - order: 3, + order: 2, when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), Constants.InTreeViewKey.toNegated()), }] }); @@ -540,7 +540,7 @@ registerAction2(class ViewAsListAction extends Action2 { menu: [{ id: MenuId.ViewTitle, group: 'navigation', - order: 3, + order: 2, when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), Constants.InTreeViewKey), }] }); From be4cce2ab6c9bc151d392e5a277fbdb9fa351b96 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 23 Sep 2022 14:15:42 -0700 Subject: [PATCH 027/599] save/restore viewstate only when meaningful state changes (#161646) --- .../notebook/browser/diff/diffComponents.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 7d8ac846bcf..e3a628d0d87 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -1253,6 +1253,7 @@ export class InsertElement extends SingleSideDiffElement { export class ModifiedElement extends AbstractElementRenderer { private _editor?: DiffEditorWidget; + private _editorViewStateChanged: boolean; private _editorContainer!: HTMLElement; private _inputToolbarContainer!: HTMLElement; protected _toolbar!: ToolBar; @@ -1279,6 +1280,7 @@ export class ModifiedElement extends AbstractElementRenderer { super(notebookEditor, cell, templateData, 'full', instantiationService, languageService, modelService, textModelService, contextMenuService, keybindingService, notificationService, menuService, contextKeyService, configurationService); this.cell = cell; this.templateData = templateData; + this._editorViewStateChanged = false; } init() { } @@ -1598,7 +1600,26 @@ export class ModifiedElement extends AbstractElementRenderer { modified: modifiedTextModel }); - this._editor!.restoreViewState(this.cell.getSourceEditorViewState() as editorCommon.IDiffEditorViewState); + const handleViewStateChange = () => { + this._editorViewStateChanged = true; + }; + + const handleScrollChange = (e: editorCommon.IScrollEvent) => { + if (e.scrollTopChanged || e.scrollLeftChanged) { + this._editorViewStateChanged = true; + } + }; + + this._register(this._editor!.getOriginalEditor().onDidChangeCursorSelection(handleViewStateChange)); + this._register(this._editor!.getOriginalEditor().onDidScrollChange(handleScrollChange)); + this._register(this._editor!.getModifiedEditor().onDidChangeCursorSelection(handleViewStateChange)); + this._register(this._editor!.getModifiedEditor().onDidScrollChange(handleScrollChange)); + + const editorViewState = this.cell.getSourceEditorViewState() as editorCommon.IDiffEditorViewState | null; + if (editorViewState) { + console.log('restore view state', this.cell.modified.handle, editorViewState); + this._editor!.restoreViewState(editorViewState); + } const contentHeight = this._editor!.getContentHeight(); this.cell.editorHeight = contentHeight; @@ -1645,7 +1666,7 @@ export class ModifiedElement extends AbstractElementRenderer { } override dispose() { - if (this._editor) { + if (this._editor && this._editorViewStateChanged) { this.cell.saveSpirceEditorViewState(this._editor.saveViewState()); } From 25d51ed33f3d344991ab782eab50c7465bc2eb97 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 23 Sep 2022 15:02:19 -0700 Subject: [PATCH 028/599] dispose of quick fix decoration when the next command is run (#161641) * fix #161629 * dispose of decoration on execution for unix * do for windows as well --- .../terminal/common/capabilities/capabilities.ts | 1 + .../common/capabilities/commandDetectionCapability.ts | 4 ++++ .../terminal/browser/xterm/contextualActionAddon.ts | 11 ++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 5b00519a62d..03f863348fc 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -153,6 +153,7 @@ export interface ICommandDetectionCapability { readonly hasInput: boolean | undefined; readonly onCommandStarted: Event; readonly onCommandFinished: Event; + readonly onCommandExecuted: Event; readonly onCommandInvalidated: Event; readonly onCurrentCommandInvalidated: Event; setCwd(value: string): void; diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 48606b7fafa..757881846c1 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -97,6 +97,8 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { readonly onBeforeCommandFinished = this._onBeforeCommandFinished.event; private readonly _onCommandFinished = new Emitter(); readonly onCommandFinished = this._onCommandFinished.event; + private readonly _onCommandExecuted = new Emitter(); + readonly onCommandExecuted = this._onCommandExecuted.event; private readonly _onCommandInvalidated = new Emitter(); readonly onCommandInvalidated = this._onCommandInvalidated.event; private readonly _onCurrentCommandInvalidated = new Emitter(); @@ -422,6 +424,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { if (y === commandExecutedLine) { this._currentCommand.command += this._terminal.buffer.active.getLine(commandExecutedLine)?.translateToString(true, undefined, this._currentCommand.commandExecutedX) || ''; } + this._onCommandExecuted.fire(); } private _handleCommandExecutedWindows(): void { @@ -431,6 +434,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { this._onCursorMoveListener = undefined; this._evaluateCommandMarkersWindows(); this._currentCommand.commandExecutedX = this._terminal.buffer.active.cursorX; + this._onCommandExecuted.fire(); this._logService.debug('CommandDetectionCapability#handleCommandExecuted', this._currentCommand.commandExecutedX, this._currentCommand.commandExecutedMarker?.line); } diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts index f5c38ee5ff1..f8d407b4fc2 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts @@ -13,7 +13,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { ICommandAction, ITerminalContextualActionOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { Terminal } from 'xterm'; +import { Terminal, IDecoration } from 'xterm'; import { IAction } from 'vs/base/common/actions'; export interface IContextualAction { @@ -47,6 +47,8 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, private _matchActions: ICommandAction[] | undefined; + private _decoration: IDecoration | undefined; + constructor(private readonly _capabilities: ITerminalCapabilityStore, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IConfigurationService private readonly _configurationService: IConfigurationService) { @@ -83,7 +85,13 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, if (!terminal || !commandDetection) { return; } + this._register(commandDetection.onCommandExecuted(() => { + this._decoration?.dispose(); + this._decoration = undefined; + })); this._register(commandDetection.onCommandFinished(async command => { + this._decoration?.dispose(); + this._decoration = undefined; this._matchActions = getMatchActions(command, this._commandListeners, this._onDidRequestRerunCommand); })); // The buffer is not ready by the time command finish @@ -107,6 +115,7 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, } const actions = this._matchActions; const decoration = this._terminal.registerDecoration({ marker, layer: 'top' }); + this._decoration = decoration; decoration?.onRender((e: HTMLElement) => { if (!this._decorationMarkerIds.has(decoration.marker.id)) { this._currentQuickFixElement = e; From da506e9b8d86a7265d53255ef8a8603d792d74f5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 23 Sep 2022 15:18:57 -0700 Subject: [PATCH 029/599] Tag existing events with experimentation info in typescript-language-features (#161463) * Associate experiment info with existing telemetry. * Move the ExperimentTelemetryReporter to its own file. * Roughly copied the 'getPackageInfo' function from other extensions. * Addressed code review feedback. --- .../src/experimentTelemetryReporter.ts | 50 +++++++++ .../src/experimentationService.ts | 100 ++++++------------ .../src/extension.browser.ts | 13 +++ .../src/extension.ts | 20 +++- .../src/lazyClientHost.ts | 2 + .../src/typeScriptServiceClientHost.ts | 2 + .../src/typescriptServiceClient.ts | 6 +- .../src/utils/packageInfo.ts | 24 +++++ .../src/utils/telemetry.ts | 49 +-------- 9 files changed, 147 insertions(+), 119 deletions(-) create mode 100644 extensions/typescript-language-features/src/experimentTelemetryReporter.ts create mode 100644 extensions/typescript-language-features/src/utils/packageInfo.ts diff --git a/extensions/typescript-language-features/src/experimentTelemetryReporter.ts b/extensions/typescript-language-features/src/experimentTelemetryReporter.ts new file mode 100644 index 00000000000..d7561300761 --- /dev/null +++ b/extensions/typescript-language-features/src/experimentTelemetryReporter.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import VsCodeTelemetryReporter from '@vscode/extension-telemetry'; +import * as tas from 'vscode-tas-client'; + +export interface IExperimentationTelemetryReporter extends tas.IExperimentationTelemetry, vscode.Disposable { + postEventObj(eventName: string, props: { [prop: string]: string }): void; +} + +/** + * This reporter *supports* experimentation telemetry, + * but will only do so when passed to an {@link ExperimentationService}. + */ + +export class ExperimentationTelemetryReporter + implements IExperimentationTelemetryReporter { + private _sharedProperties: Record = {}; + private _reporter: VsCodeTelemetryReporter; + constructor(reporter: VsCodeTelemetryReporter) { + this._reporter = reporter; + } + + setSharedProperty(name: string, value: string): void { + this._sharedProperties[name] = value; + } + + postEvent(eventName: string, props: Map): void { + const propsObject = { + ...this._sharedProperties, + ...Object.fromEntries(props), + }; + this._reporter.sendTelemetryEvent(eventName, propsObject); + } + + postEventObj(eventName: string, props: { [prop: string]: string }) { + this._reporter.sendTelemetryEvent(eventName, { + ...this._sharedProperties, + ...props, + }); + } + + dispose() { + this._reporter.dispose(); + } +} + diff --git a/extensions/typescript-language-features/src/experimentationService.ts b/extensions/typescript-language-features/src/experimentationService.ts index f739872a824..1f3b1fbd73b 100644 --- a/extensions/typescript-language-features/src/experimentationService.ts +++ b/extensions/typescript-language-features/src/experimentationService.ts @@ -4,20 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import VsCodeTelemetryReporter from '@vscode/extension-telemetry'; import * as tas from 'vscode-tas-client'; +import { IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; + interface ExperimentTypes { // None for now. } -export class ExperimentationService implements vscode.Disposable { +export class ExperimentationService { private _experimentationServicePromise: Promise; - private _telemetryReporter: ExperimentTelemetryReporter; + private _telemetryReporter: IExperimentationTelemetryReporter; - constructor(private readonly _extensionContext: vscode.ExtensionContext) { - this._telemetryReporter = new ExperimentTelemetryReporter(_extensionContext); - this._experimentationServicePromise = this.createExperimentationService(); + constructor(telemetryReporter: IExperimentationTelemetryReporter, id: string, version: string, globalState: vscode.Memento) { + this._telemetryReporter = telemetryReporter; + this._experimentationServicePromise = createExperimentationService(this._telemetryReporter, id, version, globalState); } public async getTreatmentVariable(name: K, defaultValue: ExperimentTypes[K]): Promise { @@ -29,70 +30,33 @@ export class ExperimentationService implements vscode.Disposable { return defaultValue; } } - - private async createExperimentationService(): Promise { - let targetPopulation: tas.TargetPopulation; - switch (vscode.env.uriScheme) { - case 'vscode': - targetPopulation = tas.TargetPopulation.Public; - break; - case 'vscode-insiders': - targetPopulation = tas.TargetPopulation.Insiders; - break; - case 'vscode-exploration': - targetPopulation = tas.TargetPopulation.Internal; - break; - case 'code-oss': - targetPopulation = tas.TargetPopulation.Team; - break; - default: - targetPopulation = tas.TargetPopulation.Public; - break; - } - - const id = this._extensionContext.extension.id; - const version = this._extensionContext.extension.packageJSON.version || ''; - const experimentationService = tas.getExperimentationService(id, version, targetPopulation, this._telemetryReporter, this._extensionContext.globalState); - await experimentationService.initialFetch; - return experimentationService; - } - - - /** - * @inheritdoc - */ - public dispose() { - this._telemetryReporter.dispose(); - } } -export class ExperimentTelemetryReporter - implements tas.IExperimentationTelemetry, vscode.Disposable { - private _sharedProperties: Record = {}; - private _reporter: VsCodeTelemetryReporter; - constructor(ctxt: vscode.ExtensionContext) { - const extension = ctxt.extension; - const packageJSON = extension.packageJSON; - this._reporter = new VsCodeTelemetryReporter( - extension.id, - packageJSON.version || '', - packageJSON.aiKey || ''); - +export async function createExperimentationService( + reporter: IExperimentationTelemetryReporter, + id: string, + version: string, + globalState: vscode.Memento): Promise { + let targetPopulation: tas.TargetPopulation; + switch (vscode.env.uriScheme) { + case 'vscode': + targetPopulation = tas.TargetPopulation.Public; + break; + case 'vscode-insiders': + targetPopulation = tas.TargetPopulation.Insiders; + break; + case 'vscode-exploration': + targetPopulation = tas.TargetPopulation.Internal; + break; + case 'code-oss': + targetPopulation = tas.TargetPopulation.Team; + break; + default: + targetPopulation = tas.TargetPopulation.Public; + break; } - setSharedProperty(name: string, value: string): void { - this._sharedProperties[name] = value; - } - - postEvent(eventName: string, props: Map): void { - const propsObject = { - ...this._sharedProperties, - ...Object.fromEntries(props), - }; - this._reporter.sendTelemetryEvent(eventName, propsObject); - } - - dispose() { - this._reporter.dispose(); - } + const experimentationService = tas.getExperimentationService(id, version, targetPopulation, reporter, globalState); + await experimentationService.initialFetch; + return experimentationService; } diff --git a/extensions/typescript-language-features/src/extension.browser.ts b/extensions/typescript-language-features/src/extension.browser.ts index 06b650d2375..ad947fc0302 100644 --- a/extensions/typescript-language-features/src/extension.browser.ts +++ b/extensions/typescript-language-features/src/extension.browser.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import VsCodeTelemetryReporter from '@vscode/extension-telemetry'; import { Api, getExtensionApi } from './api'; import { CommandManager } from './commands/commandManager'; import { registerBaseCommands } from './commands/index'; @@ -17,6 +18,8 @@ import API from './utils/api'; import { TypeScriptServiceConfiguration } from './utils/configuration'; import { BrowserServiceConfigurationProvider } from './utils/configuration.browser'; import { PluginManager } from './utils/plugins'; +import { ExperimentationTelemetryReporter, IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; +import { getPackageInfo } from './utils/packageInfo'; class StaticVersionProvider implements ITypeScriptVersionProvider { @@ -57,6 +60,15 @@ export function activate( vscode.Uri.joinPath(context.extensionUri, 'dist/browser/typescript/tsserver.web.js').toString(), API.fromSimpleString('4.8.2'))); + let experimentTelemetryReporter: IExperimentationTelemetryReporter | undefined; + const packageInfo = getPackageInfo(context); + if (packageInfo) { + const { name: id, version, aiKey } = packageInfo; + const vscTelemetryReporter = new VsCodeTelemetryReporter(id, version, aiKey); + experimentTelemetryReporter = new ExperimentationTelemetryReporter(vscTelemetryReporter); + context.subscriptions.push(experimentTelemetryReporter); + } + const lazyClientHost = createLazyClientHost(context, false, { pluginManager, commandManager, @@ -66,6 +78,7 @@ export function activate( processFactory: WorkerServerProcess, activeJsTsEditorTracker, serviceConfigurationProvider: new BrowserServiceConfigurationProvider(), + experimentTelemetryReporter, }, item => { onCompletionAccepted.fire(item); }); diff --git a/extensions/typescript-language-features/src/extension.ts b/extensions/typescript-language-features/src/extension.ts index f6576dabc0d..e6b971260d3 100644 --- a/extensions/typescript-language-features/src/extension.ts +++ b/extensions/typescript-language-features/src/extension.ts @@ -5,10 +5,12 @@ import * as fs from 'fs'; import * as vscode from 'vscode'; +import VsCodeTelemetryReporter from '@vscode/extension-telemetry'; import { Api, getExtensionApi } from './api'; import { CommandManager } from './commands/commandManager'; import { registerBaseCommands } from './commands/index'; import { ExperimentationService } from './experimentationService'; +import { ExperimentationTelemetryReporter, IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; import { createLazyClientHost, lazilyActivateClient } from './lazyClientHost'; import { nodeRequestCancellerFactory } from './tsServer/cancellation.electron'; import { NodeLogDirectoryProvider } from './tsServer/logDirectoryProvider.electron'; @@ -20,6 +22,7 @@ import { ElectronServiceConfigurationProvider } from './utils/configuration.elec import { onCaseInsensitiveFileSystem } from './utils/fileSystem.electron'; import { PluginManager } from './utils/plugins'; import * as temp from './utils/temp.electron'; +import { getPackageInfo } from './utils/packageInfo'; export function activate( context: vscode.ExtensionContext @@ -42,6 +45,19 @@ export function activate( const jsWalkthroughState = new JsWalkthroughState(); context.subscriptions.push(jsWalkthroughState); + let experimentTelemetryReporter: IExperimentationTelemetryReporter | undefined; + const packageInfo = getPackageInfo(context); + if (packageInfo) { + const { name: id, version, aiKey } = packageInfo; + const vscTelemetryReporter = new VsCodeTelemetryReporter(id, version, aiKey); + experimentTelemetryReporter = new ExperimentationTelemetryReporter(vscTelemetryReporter); + context.subscriptions.push(experimentTelemetryReporter); + + // Currently we have no experiments, but creating the service adds the appropriate + // shared properties to the ExperimentationTelemetryReporter we just created. + new ExperimentationService(experimentTelemetryReporter, id, version, context.globalState); + } + const lazyClientHost = createLazyClientHost(context, onCaseInsensitiveFileSystem(), { pluginManager, commandManager, @@ -51,6 +67,7 @@ export function activate( processFactory: new ElectronServiceProcessFactory(), activeJsTsEditorTracker, serviceConfigurationProvider: new ElectronServiceConfigurationProvider(), + experimentTelemetryReporter, }, item => { onCompletionAccepted.fire(item); }); @@ -58,9 +75,6 @@ export function activate( registerBaseCommands(commandManager, lazyClientHost, pluginManager, activeJsTsEditorTracker); registerJsNodeWalkthrough(commandManager, jsWalkthroughState); - // Currently no variables in use. - context.subscriptions.push(new ExperimentationService(context)); - import('./task/taskProvider').then(module => { context.subscriptions.push(module.register(lazyClientHost.map(x => x.serviceClient))); }); diff --git a/extensions/typescript-language-features/src/lazyClientHost.ts b/extensions/typescript-language-features/src/lazyClientHost.ts index 8ad2efac84c..377d9c09fa1 100644 --- a/extensions/typescript-language-features/src/lazyClientHost.ts +++ b/extensions/typescript-language-features/src/lazyClientHost.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import { CommandManager } from './commands/commandManager'; +import { IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; import { OngoingRequestCancellerFactory } from './tsServer/cancellation'; import { ILogDirectoryProvider } from './tsServer/logDirectoryProvider'; import { TsServerProcessFactory } from './tsServer/server'; @@ -30,6 +31,7 @@ export function createLazyClientHost( processFactory: TsServerProcessFactory; activeJsTsEditorTracker: ActiveJsTsEditorTracker; serviceConfigurationProvider: ServiceConfigurationProvider; + experimentTelemetryReporter: IExperimentationTelemetryReporter | undefined; }, onCompletionAccepted: (item: vscode.CompletionItem) => void, ): Lazy { diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index c8635b2f668..6c2168a380c 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -10,6 +10,7 @@ import * as vscode from 'vscode'; import { CommandManager } from './commands/commandManager'; +import { IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; import { DiagnosticKind } from './languageFeatures/diagnostics'; import FileConfigurationManager from './languageFeatures/fileConfigurationManager'; import LanguageProvider from './languageProvider'; @@ -72,6 +73,7 @@ export default class TypeScriptServiceClientHost extends Disposable { processFactory: TsServerProcessFactory; activeJsTsEditorTracker: ActiveJsTsEditorTracker; serviceConfigurationProvider: ServiceConfigurationProvider; + experimentTelemetryReporter: IExperimentationTelemetryReporter | undefined; }, onCompletionAccepted: (item: vscode.CompletionItem) => void, ) { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index a42f5c29f06..169df72d203 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -6,6 +6,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; +import { IExperimentationTelemetryReporter } from './experimentTelemetryReporter'; import { DiagnosticKind, DiagnosticsManager } from './languageFeatures/diagnostics'; import * as Proto from './protocol'; import { EventName } from './protocol.const'; @@ -137,6 +138,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType versionProvider: ITypeScriptVersionProvider; processFactory: TsServerProcessFactory; serviceConfigurationProvider: ServiceConfigurationProvider; + experimentTelemetryReporter: IExperimentationTelemetryReporter | undefined; }, allModeIds: readonly string[] ) { @@ -205,14 +207,14 @@ export default class TypeScriptServiceClient extends Disposable implements IType } }, this, this._disposables); - this.telemetryReporter = this._register(new VSCodeTelemetryReporter(() => { + this.telemetryReporter = new VSCodeTelemetryReporter(services.experimentTelemetryReporter, () => { if (this.serverState.type === ServerState.Type.Running) { if (this.serverState.tsserverVersion) { return this.serverState.tsserverVersion; } } return this.apiVersion.fullVersionString; - })); + }); this.typescriptServerSpawner = new TypeScriptServerSpawner(this.versionProvider, this._versionManager, this.logDirectoryProvider, this.pluginPathsProvider, this.logger, this.telemetryReporter, this.tracer, this.processFactory); diff --git a/extensions/typescript-language-features/src/utils/packageInfo.ts b/extensions/typescript-language-features/src/utils/packageInfo.ts new file mode 100644 index 00000000000..09536ab4141 --- /dev/null +++ b/extensions/typescript-language-features/src/utils/packageInfo.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export interface PackageInfo { + name: string; + version: string; + aiKey: string; +} + +export function getPackageInfo(context: vscode.ExtensionContext) { + const packageJSON = context.extension.packageJSON; + if (packageJSON && typeof packageJSON === 'object') { + return { + name: packageJSON.name ?? '', + version: packageJSON.version ?? '', + aiKey: packageJSON.aiKey ?? '', + }; + } + return null; +} diff --git a/extensions/typescript-language-features/src/utils/telemetry.ts b/extensions/typescript-language-features/src/utils/telemetry.ts index da7ee73cad0..4b2d3867f6d 100644 --- a/extensions/typescript-language-features/src/utils/telemetry.ts +++ b/extensions/typescript-language-features/src/utils/telemetry.ts @@ -3,15 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import VsCodeTelemetryReporter from '@vscode/extension-telemetry'; -import { memoize } from './memoize'; - -interface PackageInfo { - readonly name: string; - readonly version: string; - readonly aiKey: string; -} +import { IExperimentationTelemetryReporter } from '../experimentTelemetryReporter'; export interface TelemetryProperties { readonly [prop: string]: string | number | boolean | undefined; @@ -19,14 +11,11 @@ export interface TelemetryProperties { export interface TelemetryReporter { logTelemetry(eventName: string, properties?: TelemetryProperties): void; - - dispose(): void; } export class VSCodeTelemetryReporter implements TelemetryReporter { - private _reporter: VsCodeTelemetryReporter | null = null; - constructor( + private readonly reporter: IExperimentationTelemetryReporter | undefined, private readonly clientVersionDelegate: () => string ) { } @@ -43,38 +32,6 @@ export class VSCodeTelemetryReporter implements TelemetryReporter { */ properties['version'] = this.clientVersionDelegate(); - reporter.sendTelemetryEvent(eventName, properties); - } - - public dispose() { - if (this._reporter) { - this._reporter.dispose(); - this._reporter = null; - } - } - - @memoize - private get reporter(): VsCodeTelemetryReporter | null { - if (this.packageInfo?.aiKey) { - this._reporter = new VsCodeTelemetryReporter( - this.packageInfo.name, - this.packageInfo.version, - this.packageInfo.aiKey); - return this._reporter; - } - return null; - } - - @memoize - private get packageInfo(): PackageInfo | null { - const { packageJSON } = vscode.extensions.getExtension('vscode.typescript-language-features')!; - if (packageJSON) { - return { - name: packageJSON.name, - version: packageJSON.version, - aiKey: packageJSON.aiKey - }; - } - return null; + reporter.postEventObj(eventName, properties); } } From deef6e402ef77ed3271d2e71f220c3d67de083f3 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Sun, 25 Sep 2022 16:46:58 +0200 Subject: [PATCH 030/599] Implements command to show base at top/middle in mixed column mode. --- .../mergeEditor/browser/commands/commands.ts | 32 ++++++++++++++++++- .../browser/mergeEditor.contribution.ts | 3 +- .../mergeEditor/browser/view/mergeEditor.ts | 20 +++++++++--- .../contrib/mergeEditor/common/mergeEditor.ts | 1 + 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 95f83325e3f..98fc203bfe6 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -8,6 +8,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -17,7 +18,7 @@ import { MergeEditorInput, MergeEditorInputData } from 'vs/workbench/contrib/mer import { IMergeEditorInputModel } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; -import { ctxIsMergeEditor, ctxMergeEditorLayout, ctxMergeEditorShowBase, ctxMergeEditorShowNonConflictingChanges } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; +import { ctxIsMergeEditor, ctxMergeEditorLayout, ctxMergeEditorShowBase, ctxMergeEditorShowBaseAtTop, ctxMergeEditorShowNonConflictingChanges } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; abstract class MergeEditorAction extends Action2 { @@ -276,6 +277,35 @@ export class ShowHideBase extends Action2 { } } +export class ShowHideAtTopBase extends Action2 { + constructor() { + super({ + id: 'merge.showBaseAtTop', + title: { + value: localize('layout.showBaseAtTop', 'Show Base At Top'), + original: 'Show Base At Top', + }, + toggled: ctxMergeEditorShowBaseAtTop.isEqualTo(true), + menu: [ + { + id: MenuId.EditorTitle, + when: ctxIsMergeEditor, + group: '2_merge', + order: 10, + }, + ], + precondition: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorShowBase), + }); + } + + run(accessor: ServicesAccessor): void { + const { activeEditorPane } = accessor.get(IEditorService); + if (activeEditorPane instanceof MergeEditor) { + activeEditorPane.toggleShowBaseAtTop(); + } + } +} + const mergeEditorCategory: ILocalizedString = { value: localize('mergeEditor', 'Merge Editor'), original: 'Merge Editor', diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index 0e8385ea1d0..b168f302520 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -11,7 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; -import { AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, ResetDirtyConflictsToBaseCommand, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideBase, ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; +import { AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, ResetDirtyConflictsToBaseCommand, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideAtTopBase, ShowHideBase, ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; import { MergeEditorCopyContentsToJSON, MergeEditorLoadContentsFromFolder, MergeEditorSaveContentsToFolder } from 'vs/workbench/contrib/mergeEditor/browser/commands/devCommands'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor, MergeEditorOpenHandlerContribution, MergeEditorResolverContribution } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -52,6 +52,7 @@ registerAction2(OpenResultResource); registerAction2(SetMixedLayout); registerAction2(SetColumnLayout); registerAction2(ShowHideBase); +registerAction2(ShowHideAtTopBase); registerAction2(OpenMergeEditor); registerAction2(OpenBaseFile); registerAction2(ShowNonConflictingChanges); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 27d137a9be4..b956e502130 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -547,6 +547,13 @@ export class MergeEditor extends AbstractTextEditor { }); } + public toggleShowBaseAtTop(): void { + this.setLayout({ + ...this._layoutMode.value, + showBaseAtTop: !this._layoutMode.value.showBaseAtTop, + }); + } + public setLayoutKind(kind: MergeEditorLayoutKind): void { this.setLayout({ ...this._layoutMode.value, @@ -590,13 +597,17 @@ export class MergeEditor extends AbstractTextEditor { if (layout.kind === 'mixed') { this.setGrid([ - layout.showBase ? { + layout.showBaseAtTop && layout.showBase ? { size: 38, data: this.baseView.get()!.view } : undefined, { size: 38, - groups: [{ data: this.input1View.view }, { data: this.input2View.view }] + groups: [ + { data: this.input1View.view }, + !layout.showBaseAtTop && layout.showBase ? { data: this.baseView.get()!.view } : undefined, + { data: this.input2View.view } + ].filter(isDefined) }, { size: 62, @@ -696,18 +707,19 @@ export class MergeEditor extends AbstractTextEditor { interface IMergeEditorLayout { readonly kind: MergeEditorLayoutKind; readonly showBase: boolean; + readonly showBaseAtTop: boolean; } // TODO use PersistentStore class MergeEditorLayoutStore { private static readonly _key = 'mergeEditor/layout'; - private _value: IMergeEditorLayout = { kind: 'mixed', showBase: false }; + private _value: IMergeEditorLayout = { kind: 'mixed', showBase: false, showBaseAtTop: true }; constructor(@IStorageService private _storageService: IStorageService) { const value = _storageService.get(MergeEditorLayoutStore._key, StorageScope.PROFILE, 'mixed'); if (value === 'mixed' || value === 'columns') { - this._value = { kind: value, showBase: false }; + this._value = { kind: value, showBase: false, showBaseAtTop: true }; } else if (value) { try { this._value = JSON.parse(value); diff --git a/src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts index f5c4b9f7dcf..07001c6684a 100644 --- a/src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/common/mergeEditor.ts @@ -12,6 +12,7 @@ export const ctxIsMergeEditor = new RawContextKey('isMergeEditor', fals export const ctxIsMergeResultEditor = new RawContextKey('isMergeResultEditor', false, { type: 'boolean', description: localize('isr', 'The editor is a the result editor of a merge editor.') }); export const ctxMergeEditorLayout = new RawContextKey('mergeEditorLayout', 'mixed', { type: 'string', description: localize('editorLayout', 'The layout mode of a merge editor') }); export const ctxMergeEditorShowBase = new RawContextKey('mergeEditorShowBase', false, { type: 'boolean', description: localize('showBase', 'If the merge editor shows the base version') }); +export const ctxMergeEditorShowBaseAtTop = new RawContextKey('mergeEditorShowBaseAtTop', false, { type: 'boolean', description: localize('showBaseAtTop', 'If base should be shown at the top') }); export const ctxMergeEditorShowNonConflictingChanges = new RawContextKey('mergeEditorShowNonConflictingChanges', false, { type: 'boolean', description: localize('showNonConflictingChanges', 'If the merge editor shows non-conflicting changes') }); export const ctxMergeBaseUri = new RawContextKey('mergeEditorBaseUri', '', { type: 'string', description: localize('baseUri', 'The uri of the baser of a merge editor') }); From d0c5e3848a605066645a868b3e65b8776f2cb237 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 25 Sep 2022 17:57:02 +0200 Subject: [PATCH 031/599] fix turn on sync - sync remote profiles that do not exist locally --- .../common/userDataAutoSyncService.ts | 1 - .../common/userDataSyncService.ts | 83 ++++++++++++------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 2507e379501..1cae7582e56 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -411,7 +411,6 @@ class AutoSync extends Disposable { this.syncTask?.stop(); this.logService.info('Auto Sync: Stopped'); })); - this.logService.info('Auto Sync: Started'); this.sync(AutoSync.INTERVAL_SYNCING, false); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 02cd2ff1c7a..f33f1406558 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -104,6 +104,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ async createSyncTask(manifest: IUserDataManifest | null, disableCache?: boolean): Promise { this.checkEnablement(); + this.logService.info('Sync started.'); + const startTime = new Date().getTime(); const executionId = generateUuid(); try { const syncHeaders = createSyncHeaders(executionId); @@ -127,7 +129,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ throw new Error('Can run a task only once'); } cancellablePromise = createCancelablePromise(token => that.sync(manifest, false, executionId, token)); - return cancellablePromise.finally(() => cancellablePromise = undefined); + await cancellablePromise.finally(() => cancellablePromise = undefined); + that.logService.info(`Sync done. Took ${new Date().getTime() - startTime}ms`); + that.updateLastSyncTime(); }, stop(): Promise { cancellablePromise?.cancel(); @@ -143,9 +147,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ throw new UserDataSyncError('Cannot start manual sync when sync is enabled', UserDataSyncErrorCode.LocalError); } + this.logService.info('Sync started.'); + const startTime = new Date().getTime(); const executionId = generateUuid(); const syncHeaders = createSyncHeaders(executionId); - let manifest: IUserDataManifest | null; try { manifest = await this.userDataSyncStoreService.manifest(null, syncHeaders); @@ -166,12 +171,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return that.sync(manifest, true, executionId, cancellableToken.token); }, async apply(): Promise { - for (const profileSynchronizer of that.getActiveProfileSynchronizers()) { - if (cancellableToken.token.isCancellationRequested) { - return; - } - await profileSynchronizer.apply(executionId, cancellableToken.token); - } + await that.applyManualSync(manifest, executionId, cancellableToken.token); + that.logService.info(`Sync done. Took ${new Date().getTime() - startTime}ms`); + that.updateLastSyncTime(); }, stop(): Promise { cancellableToken.cancel(); @@ -185,14 +187,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ } private async sync(manifest: IUserDataManifest | null, merge: boolean, executionId: string, token: CancellationToken): Promise { - // Return if cancellation is requested - if (token.isCancellationRequested) { - return; - } - const startTime = new Date().getTime(); this._syncErrors = []; try { - this.logService.info('Sync started.'); if (this.status !== SyncStatus.HasConflicts) { this.setStatus(SyncStatus.Syncing); } @@ -208,27 +204,56 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ if (token.isCancellationRequested) { return; } - for (const syncProfile of syncProfiles) { - if (token.isCancellationRequested) { - return; - } - const profile = this.userDataProfilesService.profiles.find(p => p.id === syncProfile.id); - if (!profile) { - this.logService.error(`Settings Profile with id:${syncProfile.id} and name: ${syncProfile.name} does not exist locally to sync.`); - continue; - } - this.logService.info('Syncing profile.', syncProfile.name); - const profileSynchronizer = this.getOrCreateActiveProfileSynchronizer(profile, syncProfile); - this._syncErrors.push(...await this.syncProfile(profileSynchronizer, manifest, merge, executionId, token)); - } + await this.syncRemoteProfiles(syncProfiles, manifest, merge, executionId, token); } - this.logService.info(`Sync done. Took ${new Date().getTime() - startTime}ms`); - this.updateLastSyncTime(); } finally { this._onSyncErrors.fire(this._syncErrors); } } + private async syncRemoteProfiles(remoteProfiles: ISyncUserDataProfile[], manifest: IUserDataManifest | null, merge: boolean, executionId: string, token: CancellationToken): Promise { + for (const syncProfile of remoteProfiles) { + if (token.isCancellationRequested) { + return; + } + const profile = this.userDataProfilesService.profiles.find(p => p.id === syncProfile.id); + if (!profile) { + this.logService.error(`Settings Profile with id:${syncProfile.id} and name: ${syncProfile.name} does not exist locally to sync.`); + continue; + } + this.logService.info('Syncing profile.', syncProfile.name); + const profileSynchronizer = this.getOrCreateActiveProfileSynchronizer(profile, syncProfile); + this._syncErrors.push(...await this.syncProfile(profileSynchronizer, manifest, merge, executionId, token)); + } + } + + private async applyManualSync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise { + const profileSynchronizers = this.getActiveProfileSynchronizers(); + for (const profileSynchronizer of profileSynchronizers) { + if (token.isCancellationRequested) { + return; + } + await profileSynchronizer.apply(executionId, token); + } + + const defaultProfileSynchronizer = profileSynchronizers.find(s => s.profile.isDefault); + if (!defaultProfileSynchronizer) { + return; + } + + const userDataProfileManifestSynchronizer = defaultProfileSynchronizer.enabled.find(s => s.resource === SyncResource.Profiles); + if (!userDataProfileManifestSynchronizer) { + return; + } + + // Sync remote profiles which are not synced locally + const remoteProfiles = (await (userDataProfileManifestSynchronizer as UserDataProfilesManifestSynchroniser).getRemoteSyncedProfiles(manifest?.latest ?? null)) || []; + const remoteProfilesToSync = remoteProfiles.filter(remoteProfile => profileSynchronizers.every(s => s.profile.id !== remoteProfile.id)); + if (remoteProfilesToSync.length) { + await this.syncRemoteProfiles(remoteProfilesToSync, manifest, false, executionId, token); + } + } + private async syncProfile(profileSynchronizer: ProfileSynchronizer, manifest: IUserDataManifest | null, merge: boolean, executionId: string, token: CancellationToken): Promise { const errors = await profileSynchronizer.sync(manifest, merge, executionId, token); return errors.map(([syncResource, error]) => ({ profile: profileSynchronizer.profile, syncResource, error })); From 87ab25a43e58ce310222f5c4b31367898843ebcf Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 26 Sep 2022 09:11:36 +0200 Subject: [PATCH 032/599] keep short record of commands that ran before a long task occurred, use better session id to correlate things --- src/vs/platform/native/common/native.ts | 6 +- .../electron-main/nativeHostMainService.ts | 8 +-- .../electron-main/windowProfiling.ts | 61 +++++++++-------- .../electron-sandbox/rendererAutoProfiler.ts | 68 +++++++++++++++++-- 4 files changed, 102 insertions(+), 41 deletions(-) diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index 2d4a245027d..d2321eeef5b 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -164,9 +164,9 @@ export interface ICommonNativeHostService { sendInputEvent(event: MouseInputEvent): Promise; // Perf Introspection - startHeartbeat(): Promise; - sendHeartbeat(): Promise; - stopHeartbeat(): Promise; + startHeartbeat(session: string): Promise; + sendHeartbeat(session: string): Promise; + stopHeartbeat(session: string): Promise; // Connectivity resolveProxy(url: string): Promise; diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 1500fcdae5a..8bc07ced50c 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -784,20 +784,20 @@ export class NativeHostMainService extends Disposable implements INativeHostMain private readonly _profilingSessions = new Map(); - async startHeartbeat(windowId: number | undefined): Promise { + async startHeartbeat(windowId: number | undefined, sessionId: string): Promise { const win = this.windowById(windowId); if (!win || !win.win) { return false; } if (!this._profilingSessions.has(win.id)) { - const session = new WindowProfiler(win.win, this.logService, this.telemetryService); + const session = new WindowProfiler(win.win, sessionId, this.logService, this.telemetryService); this._profilingSessions.set(win.id, session); session.start(); } return true; } - async sendHeartbeat(windowId: number | undefined): Promise { + async sendHeartbeat(windowId: number | undefined, _sessionId: string): Promise { const win = this.windowById(windowId); if (!win || !this._profilingSessions.has(win.id)) { return false; @@ -806,7 +806,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return false; } - async stopHeartbeat(windowId: number | undefined): Promise { + async stopHeartbeat(windowId: number | undefined, _sessionId: string): Promise { const win = this.windowById(windowId); if (!win || !this._profilingSessions.has(win.id)) { return false; diff --git a/src/vs/platform/profiling/electron-main/windowProfiling.ts b/src/vs/platform/profiling/electron-main/windowProfiling.ts index c78139af4d9..2b6971c3dd9 100644 --- a/src/vs/platform/profiling/electron-main/windowProfiling.ts +++ b/src/vs/platform/profiling/electron-main/windowProfiling.ts @@ -15,22 +15,22 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Utils } from 'vs/platform/profiling/common/profiling'; -type TelemetryHeavyCall = { - session: number; +type TelemetrySampleData = { + sessionId: string; selfTime: number; totalTime: number; functionName: string; callstack: string; }; -type TelemetryHeavyCallClassification = { +type TelemetrySampleDataClassification = { owner: 'jrieken'; comment: 'A callstack that took a long time to execute'; - session: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate call from one profile' }; - selfTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Self time of the function' }; - totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Total time of the function' }; - functionName: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The name of the function' }; - callstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The stacktrace leading into the function' }; + sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate samples from one profile' }; + selfTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Self time of the sample' }; + totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Total time of the sample' }; + functionName: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The name of the sample' }; + callstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The stacktrace leading into the sample' }; }; class Node { @@ -67,10 +67,6 @@ class Node { export class WindowProfiler { - private static _idPool = 1; - - readonly id: number = WindowProfiler._idPool++; - private _profileAtOrAfter: number = 0; private _session = new DisposableStore(); private _isProfiling?: Promise; @@ -79,6 +75,7 @@ export class WindowProfiler { constructor( private readonly _window: BrowserWindow, + private readonly _sessionId: string, @ILogService private readonly _logService: ILogService, @ITelemetryService private readonly _telemetryService: ITelemetryService, ) { @@ -89,7 +86,7 @@ export class WindowProfiler { await this._isProfiling; - this._logService.warn('[perf] STOPPING to monitor renderer', this.id); + this._logService.warn('[perf] STOPPING to monitor renderer', this._sessionId); this._session.clear(); try { @@ -97,7 +94,7 @@ export class WindowProfiler { await inspector.sendCommand('Profiler.disable'); inspector.detach(); } catch (error) { - this._logService.error('[perf] FAILED to disable profiler', this.id); + this._logService.error('[perf] FAILED to disable profiler', this._sessionId); } } @@ -108,7 +105,7 @@ export class WindowProfiler { async start() { if (this._isStarted) { - this._logService.warn('[perf] already STARTED, ignoring request', this.id); + this._logService.warn('[perf] already STARTED, ignoring request', this._sessionId); return; } @@ -117,11 +114,11 @@ export class WindowProfiler { inspector.attach(); await inspector.sendCommand('Profiler.enable'); } catch (error) { - this._logService.error('[perf] FAILED to enable profiler', this.id); + this._logService.error('[perf] FAILED to enable profiler', this._sessionId); return; } - this._logService.warn('[perf] started to EXPECT frequent heartbeat', this.id); + this._logService.warn('[perf] started to EXPECT frequent heartbeat', this._sessionId); this._session.clear(); this._profileAtOrAfter = Date.now(); @@ -141,22 +138,22 @@ export class WindowProfiler { private async _captureRendererProfile(): Promise { - this._logService.warn('[perf] MISSED heartbeat, trying to profile renderer', this.id); + this._logService.warn('[perf] MISSED heartbeat, trying to profile renderer', this._sessionId); const profiling = (async () => { const inspector = this._window.webContents.debugger; await inspector.sendCommand('Profiler.start'); - this._logService.warn('[perf] profiling STARTED', this.id); + this._logService.warn('[perf] profiling STARTED', this._sessionId); await timeout(5000); const res: ProfileResult = await inspector.sendCommand('Profiler.stop'); - this._logService.warn('[perf] profiling DONE', this.id); + this._logService.warn('[perf] profiling DONE', this._sessionId); await this._store(res.profile); this._digest(res.profile); })(); this._isProfiling = profiling .catch(err => { - this._logService.error('[perf] profiling the renderer FAILED', this.id); + this._logService.error('[perf] profiling the renderer FAILED', this._sessionId); this._logService.error(err); }).finally(() => { this._isProfiling = undefined; @@ -167,9 +164,9 @@ export class WindowProfiler { try { const path = join(tmpdir(), `renderer-profile-${Date.now()}.cpuprofile`); await Promises.writeFile(path, JSON.stringify(profile)); - this._logService.info('[perf] stored profile to DISK', this.id, path); + this._logService.info('[perf] stored profile to DISK', this._sessionId, path); } catch (error) { - this._logService.error('[perf] FAILED to write profile to disk', this.id, error); + this._logService.error('[perf] FAILED to write profile to disk', this._sessionId, error); } } @@ -177,7 +174,7 @@ export class WindowProfiler { // https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-Profile if (!profile.samples || !profile.timeDeltas) { - this._logService.warn('[perf] INVALID profile: no samples or timeDeltas', this.id); + this._logService.warn('[perf] INVALID profile: no samples or timeDeltas', this._sessionId); return; } @@ -222,11 +219,17 @@ export class WindowProfiler { // TOTAL times all.forEach(Node.makeTotals); - const session = Date.now(); const sorted = Array.from(all.values()).sort((a, b) => b.selfTime - a.selfTime); if (sorted[0].callFrame.functionName === '(idle)') { - this._logService.warn('[perf] top stack is IDLE, ignoring this profile...', this.id); + this._logService.warn('[perf] top stack is IDLE, ignoring this profile...', this._sessionId); + this._telemetryService.publicLog2('prof.sample', { + sessionId: this._sessionId, + selfTime: 0, + totalTime: 0, + functionName: '(idle)', + callstack: '' + }); return; } @@ -243,14 +246,14 @@ export class WindowProfiler { candidate = candidate.parent; } - const data: TelemetryHeavyCall = { - session, + const data: TelemetrySampleData = { + sessionId: this._sessionId, selfTime: node.selfTime / 1000, totalTime: node.totalTime / 1000, functionName: node.callFrame.functionName, callstack: callstack.join('\n') }; - this._telemetryService.publicLog2('prof.slowcall', data); + this._telemetryService.publicLog2('prof.freeze.sample', data); console.log(data); } diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index 9df4bdd7375..fb86ebd5f9c 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -4,10 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { generateUuid } from 'vs/base/common/uuid'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITimerService } from 'vs/workbench/services/timer/browser/timerService'; @@ -19,12 +22,19 @@ export class RendererProfiling { @ITimerService timerService: ITimerService, @INativeHostService nativeHostService: INativeHostService, @ILogService logService: ILogService, + @ICommandService commandService: ICommandService, + @ITelemetryService telemetryService: ITelemetryService, ) { - timerService.whenReady().then(() => { + + // SLOW threshold const slowThreshold = (timerService.startupMetrics.timers.ellapsedRequire / 2) | 0; + // Keep a record of the last events + const eventHistory = new RingBuffer(5); + this._disposables.add(commandService.onWillExecuteCommand(e => eventHistory.push(e.commandId))); + const sessionDisposables = this._disposables.add(new DisposableStore()); const obs = new PerformanceObserver(list => { @@ -42,15 +52,25 @@ export class RendererProfiling { // pause observation, we'll take a detailed look obs.disconnect(); - nativeHostService.startHeartbeat().then(success => { + const sessionId = generateUuid(); + logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); + + + // send telemetry event + telemetryService.publicLog2('perf.freeze.events', { + sessionId: sessionId, + events: JSON.stringify(eventHistory.values()), + }); + + // start heartbeat monitoring + nativeHostService.startHeartbeat(sessionId).then(success => { if (!success) { logService.warn('[perf] FAILED to start heartbeat sending'); return; } - logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), started to send heartbeat`); // start sending a repeated heartbeat which is expected to be received by the main side - const handle1 = setInterval(() => nativeHostService.sendHeartbeat(), 500); + const handle1 = setInterval(() => nativeHostService.sendHeartbeat(sessionId), 500); // stop heartbeat after 20s const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); @@ -61,7 +81,7 @@ export class RendererProfiling { sessionDisposables.add(toDisposable(() => { clearInterval(handle1); clearTimeout(handle2); - nativeHostService.stopHeartbeat(); + nativeHostService.stopHeartbeat(sessionId); logService.warn(`[perf] STOPPING to send heartbeat`); obs.observe({ entryTypes: ['longtask'] }); @@ -102,3 +122,41 @@ registerAction2(class SLOW extends Action2 { console.log('fib(44): ', fib(44)); } }); + + +type TelemetryEventData = { + sessionId: string; + events: string; +}; + +type TelemetryEventClassification = { + owner: 'jrieken'; + comment: 'A list of events that happened before a long task was reported'; + sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate samples and events' }; + events: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'List of events' }; +}; + +class RingBuffer { + + private static _value = {}; + + private readonly _data: any[]; + + private _index: number = 0; + private _size: number = 0; + + constructor(size: number) { + this._size = size; + this._data = new Array(size); + this._data.fill(RingBuffer._value, 0, size); + } + + push(value: T): void { + this._data[this._index] = value; + this._index = (this._index + 1) % this._size; + } + + values(): T[] { + return [...this._data.slice(this._index), this._data.slice(0, this._index)].filter(a => a !== RingBuffer._value); + } +} From f7678515ebb87961dd77744cf51a532523cbeffe Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 26 Sep 2022 03:13:34 -0400 Subject: [PATCH 033/599] Only show warning if edit session contents differ from local contents (#160464) * Don't present modal dialog if server edits are identical to local edits * Use custom modal to avoid stealing window focus when resuming edit sessions --- .../browser/editSessions.contribution.ts | 150 +++++++++++------- .../test/browser/editSessions.test.ts | 11 ++ 2 files changed, 106 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 238f1612300..73008f88f9c 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -15,7 +15,7 @@ import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; -import { joinPath, relativePath } from 'vs/base/common/resources'; +import { basename, joinPath, relativePath } from 'vs/base/common/resources'; import { encodeBase64 } from 'vs/base/common/buffer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; @@ -23,8 +23,8 @@ import { EditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { getFileNamesMessage, IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -53,6 +53,7 @@ import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSe import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IOutputService } from 'vs/workbench/services/output/common/output'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; +import { sha1Hex } from 'vs/base/browser/hash'; registerSingleton(IEditSessionsLogService, EditSessionsLogService, false); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false); @@ -367,57 +368,27 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } try { - const changes: ({ uri: URI; type: ChangeType; contents: string | undefined })[] = []; - let hasLocalUncommittedChanges = false; - const workspaceFolders = this.contextService.getWorkspace().folders; + const { changes, conflictingChanges } = await this.generateChanges(editSession, ref); - for (const folder of editSession.folders) { - const cancellationTokenSource = new CancellationTokenSource(); - let folderRoot: IWorkspaceFolder | undefined; + // TODO@joyceerhl Provide the option to diff files which would be overwritten by edit session contents + if (conflictingChanges.length > 0) { + const yes = localize('resume edit session yes', 'Yes'); + const cancel = localize('resume edit session cancel', 'Cancel'); + // Allow to show edit sessions - if (folder.canonicalIdentity) { - // Look for an edit session identifier that we can use - for (const f of workspaceFolders) { - const identity = await this.editSessionIdentityService.getEditSessionIdentifier(f, cancellationTokenSource); - this.logService.info(`Matching identity ${identity} against edit session folder identity ${folder.canonicalIdentity}...`); - if (equals(identity, folder.canonicalIdentity)) { - folderRoot = f; - break; - } - } - } else { - folderRoot = workspaceFolders.find((f) => f.name === folder.name); - } + const result = await this.dialogService.show( + Severity.Warning, + changes.length > 1 ? + localize('resume edit session warning many', 'Resuming your edit session will overwrite the following {0} files. Do you want to proceed?', changes.length) : + localize('resume edit session warning 1', 'Resuming your edit session will overwrite {0}. Do you want to proceed?', basename(changes[0].uri)), + [cancel, yes], + { + custom: true, + detail: changes.length > 1 ? getFileNamesMessage(conflictingChanges.map((c) => c.uri)) : undefined, + cancelId: 0 + }); - if (!folderRoot) { - this.logService.info(`Skipping applying ${folder.workingChanges.length} changes from edit session with ref ${ref} as no matching workspace folder was found.`); - return; - } - - for (const repository of this.scmService.repositories) { - if (repository.provider.rootUri !== undefined && - this.contextService.getWorkspaceFolder(repository.provider.rootUri)?.name === folder.name && - this.getChangedResources(repository).length > 0 - ) { - hasLocalUncommittedChanges = true; - break; - } - } - - for (const { relativeFilePath, contents, type } of folder.workingChanges) { - const uri = joinPath(folderRoot.uri, relativeFilePath); - changes.push({ uri: uri, type: type, contents: contents }); - } - } - - if (hasLocalUncommittedChanges) { - // TODO@joyceerhl Provide the option to diff files which would be overwritten by edit session contents - const result = await this.dialogService.confirm({ - message: localize('resume edit session warning', 'Resuming your edit session may overwrite your existing uncommitted changes. Do you want to proceed?'), - type: 'warning', - title: EDIT_SESSION_SYNC_CATEGORY.value - }); - if (!result.confirmed) { + if (result.choice === 0) { return; } } @@ -439,6 +410,77 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } } + private async generateChanges(editSession: EditSession, ref: string) { + const changes: ({ uri: URI; type: ChangeType; contents: string | undefined })[] = []; + const conflictingChanges = []; + const workspaceFolders = this.contextService.getWorkspace().folders; + + for (const folder of editSession.folders) { + const cancellationTokenSource = new CancellationTokenSource(); + let folderRoot: IWorkspaceFolder | undefined; + + if (folder.canonicalIdentity) { + // Look for an edit session identifier that we can use + for (const f of workspaceFolders) { + const identity = await this.editSessionIdentityService.getEditSessionIdentifier(f, cancellationTokenSource); + this.logService.info(`Matching identity ${identity} against edit session folder identity ${folder.canonicalIdentity}...`); + if (equals(identity, folder.canonicalIdentity)) { + folderRoot = f; + break; + } + } + } else { + folderRoot = workspaceFolders.find((f) => f.name === folder.name); + } + + if (!folderRoot) { + this.logService.info(`Skipping applying ${folder.workingChanges.length} changes from edit session with ref ${ref} as no matching workspace folder was found.`); + return { changes: [], conflictingChanges: [] }; + } + + const localChanges = new Set(); + for (const repository of this.scmService.repositories) { + if (repository.provider.rootUri !== undefined && + this.contextService.getWorkspaceFolder(repository.provider.rootUri)?.name === folder.name + ) { + const repositoryChanges = this.getChangedResources(repository); + repositoryChanges.forEach((change) => localChanges.add(change.toString())); + } + } + + for (const change of folder.workingChanges) { + const uri = joinPath(folderRoot.uri, change.relativeFilePath); + + changes.push({ uri, type: change.type, contents: change.contents }); + if (await this.willChangeLocalContents(localChanges, uri, change)) { + conflictingChanges.push({ uri, type: change.type, contents: change.contents }); + } + } + } + + return { changes, conflictingChanges }; + } + + private async willChangeLocalContents(localChanges: Set, uriWithIncomingChanges: URI, incomingChange: Change) { + if (!localChanges.has(uriWithIncomingChanges.toString())) { + return false; + } + + const { contents, type } = incomingChange; + + switch (type) { + case (ChangeType.Addition): { + const [originalContents, incomingContents] = await Promise.all([sha1Hex(contents), sha1Hex(encodeBase64((await this.fileService.readFile(uriWithIncomingChanges)).value))]); + return originalContents !== incomingContents; + } + case (ChangeType.Deletion): { + return await this.fileService.exists(uriWithIncomingChanges); + } + default: + throw new Error('Unhandled change type.'); + } + } + async storeEditSession(fromStoreCommand: boolean): Promise { const folders: Folder[] = []; let hasEdits = false; @@ -530,17 +572,15 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } private getChangedResources(repository: ISCMRepository) { - const trackedUris = repository.provider.groups.elements.reduce((resources, resourceGroups) => { + return repository.provider.groups.elements.reduce((resources, resourceGroups) => { resourceGroups.elements.forEach((resource) => resources.add(resource.sourceUri)); return resources; }, new Set()); // A URI might appear in more than one resource group - - return [...trackedUris]; } private hasEditSession() { for (const repository of this.scmService.repositories) { - if (this.getChangedResources(repository).length > 0) { + if (this.getChangedResources(repository).size > 0) { return true; } } diff --git a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts index 1f9f445495f..d88a15bafe1 100644 --- a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -35,6 +35,7 @@ import { Event } from 'vs/base/common/event'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; const folderName = 'test-folder'; const folderUri = URI.file(`/${folderName}`); @@ -69,6 +70,11 @@ suite('Edit session sync', () => { instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(ISCMService, SCMService); instantiationService.stub(IEnvironmentService, TestEnvironmentService); + instantiationService.stub(IDialogService, new class extends mock() { + override async show() { + return { choice: 1 }; + } + }); instantiationService.stub(IConfigurationService, new TestConfigurationService({ workbench: { experimental: { editSessions: { enabled: true } } } })); instantiationService.stub(IWorkspaceContextService, new class extends mock() { override getWorkspace() { @@ -133,6 +139,10 @@ suite('Edit session sync', () => { const readStub = sandbox.stub().returns({ editSession, ref: '0' }); instantiationService.stub(IEditSessionsStorageService, 'read', readStub); + // Ensure that user does not get prompted here + const dialogServiceShowStub = sandbox.stub(); + instantiationService.stub(IDialogService, 'show', dialogServiceShowStub); + // Create root folder await fileService.createFolder(folderUri); @@ -141,6 +151,7 @@ suite('Edit session sync', () => { // Verify edit session was correctly applied assert.equal((await fileService.readFile(fileUri)).value.toString(), fileContents); + assert.equal(dialogServiceShowStub.called, false); }); test('Edit session not stored if there are no edits', async function () { From 4e7b1a914b19042c05ae62760308f770116657e4 Mon Sep 17 00:00:00 2001 From: Yusuke Yamada Date: Mon, 26 Sep 2022 16:13:44 +0900 Subject: [PATCH 034/599] Correct handling of ZDOTDIR variable to avoid crashing terminal (#161433) --- .../terminal/node/terminalEnvironment.ts | 5 ++++- .../test/node/terminalEnvironment.test.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index d1884b8c3ab..4663e733489 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -188,7 +188,10 @@ export function getShellIntegrationInjection( const zdotdir = path.join(os.tmpdir(), `${os.userInfo().username}-vscode-zsh`); envMixin['ZDOTDIR'] = zdotdir; const userZdotdir = env?.ZDOTDIR ?? os.homedir() ?? `~`; - envMixin['USER_ZDOTDIR'] = userZdotdir; + // NOTE: When vscode is started from the integrated terminal, the environment variables are taken over. + // The ZDOTDIR variable is oriented to os.tmpdir(), so we cannot reuse. + // Therefore, we use USER_ZDOTDIR variable that is inherited. + envMixin['USER_ZDOTDIR'] = env?.USER_ZDOTDIR ?? userZdotdir; const filesToCopy: IShellIntegrationConfigInjection['filesToCopy'] = []; filesToCopy.push({ source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh'), diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index 2ce4d1864e9..742de1a9de6 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -99,6 +99,7 @@ suite('platform - terminalEnvironment', () => { const username = userInfo().username; const expectedDir = new RegExp(`.+\/${username}-vscode-zsh`); const customZdotdir = '/custom/zsh/dotdir'; + const customUserZdotdir = '/custom/zsh/user_dotdir'; const expectedDests = [ new RegExp(`.+\/${username}-vscode-zsh\/\.zshrc`), new RegExp(`.+\/${username}-vscode-zsh\/\.zprofile`), @@ -162,6 +163,23 @@ suite('platform - terminalEnvironment', () => { assertIsEnabled(result1); }); }); + suite('should incorporate global USER_ZDOTDIR env variable', () => { + test('when custom ZDOTDIR and USER_ZDOTDIR is undefined', () => { + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService); + deepStrictEqual(result1?.newArgs, ['-i']); + assertIsEnabled(result1, customZdotdir); + }); + test('when custom ZDOTDIR and USER_ZDOTDIR', () => { + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir, USER_ZDOTDIR: customUserZdotdir }, logService); + deepStrictEqual(result1?.newArgs, ['-i']); + assertIsEnabled(result1, customUserZdotdir); + }); + test('when undefined', () => { + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService); + deepStrictEqual(result1?.newArgs, ['-i']); + assertIsEnabled(result1, homedir()); + }); + }); }); }); suite('bash', () => { From 1eaea0bf739e237cc97d62ab1b5f623a6fe96ef6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 09:14:05 +0200 Subject: [PATCH 035/599] fix web ext mgmt service to be profile aware (#161709) --- .../abstractExtensionManagementService.ts | 8 +++--- .../common/extensionManagementService.ts | 4 +-- .../common/webExtensionManagementService.ts | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts index 6b805a92768..3e91ecf3b2c 100644 --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -50,16 +50,16 @@ export abstract class AbstractExtensionManagementService extends Disposable impl private readonly uninstallingExtensions = new Map(); private readonly _onInstallExtension = this._register(new Emitter()); - readonly onInstallExtension = this._onInstallExtension.event; + get onInstallExtension() { return this._onInstallExtension.event; } protected readonly _onDidInstallExtensions = this._register(new Emitter()); - readonly onDidInstallExtensions = this._onDidInstallExtensions.event; + get onDidInstallExtensions() { return this._onDidInstallExtensions.event; } protected readonly _onUninstallExtension = this._register(new Emitter()); - readonly onUninstallExtension = this._onUninstallExtension.event; + get onUninstallExtension() { return this._onUninstallExtension.event; } protected _onDidUninstallExtension = this._register(new Emitter()); - readonly onDidUninstallExtension = this._onDidUninstallExtension.event; + get onDidUninstallExtension() { return this._onDidUninstallExtension.event; } private readonly participants: IExtensionManagementParticipant[] = []; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index e4955cb1fa3..d39ae8f4315 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -84,8 +84,8 @@ export class ExtensionManagementService extends Disposable implements IWorkbench this.onDidChangeProfile = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(Event.map(server.extensionManagementService.onDidChangeProfile, e => ({ ...e, server }))); return emitter; }, new EventMultiplexer())).event; } - async getInstalled(type?: ExtensionType): Promise { - const result = await Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type))); + async getInstalled(type?: ExtensionType, profileLocation?: URI): Promise { + const result = await Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type, profileLocation))); return flatten(result); } diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index a19ff1b42f9..a1c21c2593e 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -6,7 +6,7 @@ import { ExtensionIdentifier, ExtensionType, IExtension, IExtensionIdentifier, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, Metadata, InstallOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; -import { Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IProfileAwareExtensionManagementService, IScannedExtension, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILogService } from 'vs/platform/log/common/log'; @@ -20,15 +20,31 @@ import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workb import { delta } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { DisposableStore } from 'vs/base/common/lifecycle'; export class WebExtensionManagementService extends AbstractExtensionManagementService implements IProfileAwareExtensionManagementService { declare readonly _serviceBrand: undefined; + private readonly disposables = this._register(new DisposableStore()); + get onProfileAwareInstallExtension() { return super.onInstallExtension; } + override get onInstallExtension() { return Event.filter(this.onProfileAwareInstallExtension, e => this.filterEvent(e), this.disposables); } + get onProfileAwareDidInstallExtensions() { return super.onDidInstallExtensions; } + override get onDidInstallExtensions() { + return Event.filter( + Event.map(this.onProfileAwareDidInstallExtensions, results => results.filter(e => this.filterEvent(e)), this.disposables), + results => results.length > 0, this.disposables); + } + get onProfileAwareUninstallExtension() { return super.onUninstallExtension; } + override get onUninstallExtension() { return Event.filter(this.onProfileAwareUninstallExtension, e => this.filterEvent(e), this.disposables); } + get onProfileAwareDidUninstallExtension() { return super.onDidUninstallExtension; } + override get onDidUninstallExtension() { return Event.filter(this.onProfileAwareDidUninstallExtension, e => this.filterEvent(e), this.disposables); } + private readonly _onDidChangeProfile = this._register(new Emitter<{ readonly added: ILocalExtension[]; readonly removed: ILocalExtension[] }>()); readonly onDidChangeProfile = this._onDidChangeProfile.event; @@ -42,11 +58,16 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, @IProductService productService: IProductService, @IUserDataProfilesService userDataProfilesService: IUserDataProfilesService, + @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, ) { super(extensionGalleryService, telemetryService, logService, productService, userDataProfilesService); this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.whenProfileChanged(e)))); } + private filterEvent({ profileLocation, applicationScoped }: { profileLocation?: URI; applicationScoped?: boolean }): boolean { + return applicationScoped || this.uriIdentityService.extUri.isEqual(this.userDataProfileService.currentProfile.extensionsResource, profileLocation); + } + async getTargetPlatform(): Promise { return TargetPlatform.WEB; } @@ -61,14 +82,14 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe return false; } - async getInstalled(type?: ExtensionType): Promise { + async getInstalled(type?: ExtensionType, profileLocation?: URI): Promise { const extensions = []; if (type === undefined || type === ExtensionType.System) { const systemExtensions = await this.webExtensionsScannerService.scanSystemExtensions(); extensions.push(...systemExtensions); } if (type === undefined || type === ExtensionType.User) { - const userExtensions = await this.webExtensionsScannerService.scanUserExtensions(this.userDataProfileService.currentProfile.extensionsResource); + const userExtensions = await this.webExtensionsScannerService.scanUserExtensions(profileLocation ?? this.userDataProfileService.currentProfile.extensionsResource); extensions.push(...userExtensions); } return Promise.all(extensions.map(e => toLocalExtension(e))); From e7e9a506467a92a58cea8f223c5a17c3b470bdd4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 26 Sep 2022 00:14:15 -0700 Subject: [PATCH 036/599] fix #138815 (#161613) * fix #138815 * add linux * fix compile and clarify --- src/vs/base/parts/sandbox/common/sandboxTypes.ts | 6 +++++- src/vs/platform/environment/common/environment.ts | 7 +++++++ src/vs/workbench/electron-sandbox/window.ts | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/vs/base/parts/sandbox/common/sandboxTypes.ts b/src/vs/base/parts/sandbox/common/sandboxTypes.ts index c6c087da214..8c296184f7d 100644 --- a/src/vs/base/parts/sandbox/common/sandboxTypes.ts +++ b/src/vs/base/parts/sandbox/common/sandboxTypes.ts @@ -26,7 +26,11 @@ export interface ISandboxConfiguration { windowId: number; /** - * Absolute installation path. + * Root path of the JavaScript sources. + * + * Note: This is NOT the installation root + * directory itself but contained in it at + * a level that is platform dependent. */ appRoot: string; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index faf55adc736..c740ddf77f6 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -124,6 +124,13 @@ export interface INativeEnvironmentService extends IEnvironmentService { args: NativeParsedArgs; // --- data paths + /** + * Root path of the JavaScript sources. + * + * Note: This is NOT the installation root + * directory itself but contained in it at + * a level that is platform dependent. + */ appRoot: string; userHome: URI; appSettingsHome: URI; diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 9a11377d30d..579ad0ea8bc 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -669,7 +669,16 @@ export class NativeWindow extends Disposable { // Installation Dir Warning if (this.environmentService.isBuilt) { - const installLocationUri = URI.file(this.environmentService.appRoot); + let installLocationUri: URI; + if (isMacintosh) { + // appRoot = /Applications/Visual Studio Code - Insiders.app/Contents/Resources/app + installLocationUri = dirname(dirname(dirname(URI.file(this.environmentService.appRoot)))); + } else { + // appRoot = C:\Users\\AppData\Local\Programs\Microsoft VS Code Insiders\resources\app + // appRoot = /usr/share/code-insiders/resources/app + installLocationUri = dirname(dirname(URI.file(this.environmentService.appRoot))); + } + for (const folder of this.contextService.getWorkspace().folders) { if (this.uriIdentityService.extUri.isEqualOrParent(folder.uri, installLocationUri)) { this.bannerService.show({ From c741d69449d0a277007663c9d86362569693c194 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 09:14:36 +0200 Subject: [PATCH 037/599] Use profile scoped services in extensions sync (#161713) - enablement - extension state --- .../userDataSync/common/extensionsSync.ts | 297 ++++++++++-------- .../userDataSyncProfilesStorageService.ts | 30 +- 2 files changed, 174 insertions(+), 153 deletions(-) diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index 95f526def9a..f2e742095d9 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -9,15 +9,19 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { getErrorMessage } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; import { toFormattedString } from 'vs/base/common/jsonFormatter'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { compare } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IExtensionGalleryService, IExtensionManagementService, IGlobalExtensionEnablementService, ILocalExtension, ExtensionManagementError, ExtensionManagementErrorCode, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; +import { IExtensionGalleryService, IExtensionManagementService, IGlobalExtensionEnablementService, ILocalExtension, ExtensionManagementError, ExtensionManagementErrorCode, IGalleryExtension, DISABLED_EXTENSIONS_STORAGE_PATH } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; +import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -27,6 +31,7 @@ import { AbstractInitializer, AbstractSynchroniser, IAcceptResult, IMergeResult, import { IMergeResult as IExtensionMergeResult, merge } from 'vs/platform/userDataSync/common/extensionsMerge'; import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions'; import { Change, IRemoteUserData, ISyncData, ISyncExtension, ISyncExtensionWithVersion, ISyncResourceHandle, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; type IExtensionResourceMergeResult = IAcceptResult & IExtensionMergeResult; @@ -98,15 +103,16 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncBackupStoreService userDataSyncBackupStoreService: IUserDataSyncBackupStoreService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, - @IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService, @IIgnoredExtensionsManagementService private readonly ignoredExtensionsManagementService: IIgnoredExtensionsManagementService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService configurationService: IConfigurationService, @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService, @ITelemetryService telemetryService: ITelemetryService, - @IExtensionStorageService private readonly extensionStorageService: IExtensionStorageService, - @IUriIdentityService uriIdentityService: IUriIdentityService + @IExtensionStorageService extensionStorageService: IExtensionStorageService, + @IUriIdentityService uriIdentityService: IUriIdentityService, + @IUserDataSyncProfilesStorageService private readonly userDataSyncProfilesStorageService: IUserDataSyncProfilesStorageService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super({ syncResource: SyncResource.Extensions, profile }, collection, fileService, environmentService, storageService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService, uriIdentityService); this.profileLocation = profile.extensionsResource; @@ -114,8 +120,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse Event.any( Event.filter(this.extensionManagementService.onDidInstallExtensions, (e => e.some(({ local }) => !!local))), Event.filter(this.extensionManagementService.onDidUninstallExtension, (e => !e.error)), - this.extensionEnablementService.onDidChangeEnablement, - this.extensionStorageService.onDidChangeExtensionStorageToSync)(() => this.triggerLocalChange())); + Event.filter(userDataSyncProfilesStorageService.onDidChange, e => e.valueChanges.some(({ profile, changes }) => this.syncResource.profile.id === profile.id && changes.some(change => change.key === DISABLED_EXTENSIONS_STORAGE_PATH))), + extensionStorageService.onDidChangeExtensionStorageToSync)(() => this.triggerLocalChange())); } protected async generateSyncPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise { @@ -124,7 +130,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData?.syncData ? await parseAndMigrateExtensions(lastSyncUserData.syncData, this.extensionManagementService) : null; const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); - const localExtensions = this.getLocalExtensions(installedExtensions); + const localExtensions = await this.getLocalExtensions(installedExtensions); const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); if (remoteExtensions) { @@ -162,7 +168,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse protected async hasRemoteChanged(lastSyncUserData: ILastSyncUserData): Promise { const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData.syncData ? await parseAndMigrateExtensions(lastSyncUserData.syncData, this.extensionManagementService) : null; const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); - const localExtensions = this.getLocalExtensions(installedExtensions); + const localExtensions = await this.getLocalExtensions(installedExtensions); const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); const { remote } = merge(localExtensions, lastSyncExtensions, lastSyncExtensions, lastSyncUserData.skippedExtensions || [], ignoredExtensions); return remote !== null; @@ -292,7 +298,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse if (this.extUri.isEqual(uri, ExtensionsSynchroniser.EXTENSIONS_DATA_URI)) { const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); - const localExtensions = this.getLocalExtensions(installedExtensions).filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier))); + const localExtensions = (await this.getLocalExtensions(installedExtensions)).filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier))); return this.stringify(localExtensions, true); } @@ -340,7 +346,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse async hasLocalData(): Promise { try { const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); - const localExtensions = this.getLocalExtensions(installedExtensions); + const localExtensions = await this.getLocalExtensions(installedExtensions); if (localExtensions.some(e => e.installed || e.disabled)) { return true; } @@ -351,159 +357,178 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse } private async updateLocalExtensions(added: ISyncExtension[], removed: IExtensionIdentifier[], updated: ISyncExtension[], skippedExtensions: ISyncExtension[]): Promise { - const removeFromSkipped: IExtensionIdentifier[] = []; - const addToSkipped: ISyncExtension[] = []; - const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); + return this.withProfileScopedServices(async (extensionEnablementService, extensionStorageService) => { + const removeFromSkipped: IExtensionIdentifier[] = []; + const addToSkipped: ISyncExtension[] = []; + const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); - if (removed.length) { - const extensionsToRemove = installedExtensions.filter(({ identifier, isBuiltin }) => !isBuiltin && removed.some(r => areSameExtensions(identifier, r))); - await Promises.settled(extensionsToRemove.map(async extensionToRemove => { - this.logService.trace(`${this.syncResourceLogLabel}: Uninstalling local extension...`, extensionToRemove.identifier.id); - await this.extensionManagementService.uninstall(extensionToRemove, { donotIncludePack: true, donotCheckDependents: true, profileLocation: this.profileLocation }); - this.logService.info(`${this.syncResourceLogLabel}: Uninstalled local extension.`, extensionToRemove.identifier.id); - removeFromSkipped.push(extensionToRemove.identifier); - })); - } + if (removed.length) { + const extensionsToRemove = installedExtensions.filter(({ identifier, isBuiltin }) => !isBuiltin && removed.some(r => areSameExtensions(identifier, r))); + await Promises.settled(extensionsToRemove.map(async extensionToRemove => { + this.logService.trace(`${this.syncResourceLogLabel}: Uninstalling local extension...`, extensionToRemove.identifier.id); + await this.extensionManagementService.uninstall(extensionToRemove, { donotIncludePack: true, donotCheckDependents: true, profileLocation: this.profileLocation }); + this.logService.info(`${this.syncResourceLogLabel}: Uninstalled local extension.`, extensionToRemove.identifier.id); + removeFromSkipped.push(extensionToRemove.identifier); + })); + } - if (added.length || updated.length) { - await Promises.settled([...added, ...updated].map(async e => { - const installedExtension = installedExtensions.find(installed => areSameExtensions(installed.identifier, e.identifier)); + if (added.length || updated.length) { + await Promises.settled([...added, ...updated].map(async e => { + const installedExtension = installedExtensions.find(installed => areSameExtensions(installed.identifier, e.identifier)); - // Builtin Extension Sync: Enablement & State - if (installedExtension && installedExtension.isBuiltin) { - if (e.state && installedExtension.manifest.version === e.version) { - this.updateExtensionState(e.state, installedExtension, installedExtension.manifest.version); - } - const isDisabled = this.extensionEnablementService.getDisabledExtensions().some(disabledExtension => areSameExtensions(disabledExtension, e.identifier)); - if (isDisabled !== !!e.disabled) { - if (e.disabled) { - this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...`, e.identifier.id); - await this.extensionEnablementService.disableExtension(e.identifier); - this.logService.info(`${this.syncResourceLogLabel}: Disabled extension`, e.identifier.id); - } else { - this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...`, e.identifier.id); - await this.extensionEnablementService.enableExtension(e.identifier); - this.logService.info(`${this.syncResourceLogLabel}: Enabled extension`, e.identifier.id); + // Builtin Extension Sync: Enablement & State + if (installedExtension && installedExtension.isBuiltin) { + if (e.state && installedExtension.manifest.version === e.version) { + this.updateExtensionState(e.state, installedExtension, installedExtension.manifest.version, extensionStorageService); } - } - removeFromSkipped.push(e.identifier); - return; - } - - // User Extension Sync: Install/Update, Enablement & State - const extension = (await this.extensionGalleryService.getExtensions([{ ...e.identifier, preRelease: e.preRelease }], CancellationToken.None))[0]; - - /* Update extension state only if - * extension is installed and version is same as synced version or - * extension is not installed and installable - */ - if (e.state && - (installedExtension ? installedExtension.manifest.version === e.version /* Installed and has same version */ - : !!extension /* Installable */) - ) { - this.updateExtensionState(e.state, installedExtension || extension, installedExtension?.manifest.version); - } - - if (extension) { - try { - const isDisabled = this.extensionEnablementService.getDisabledExtensions().some(disabledExtension => areSameExtensions(disabledExtension, e.identifier)); + const isDisabled = extensionEnablementService.getDisabledExtensions().some(disabledExtension => areSameExtensions(disabledExtension, e.identifier)); if (isDisabled !== !!e.disabled) { if (e.disabled) { - this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...`, e.identifier.id, extension.version); - await this.extensionEnablementService.disableExtension(extension.identifier); - this.logService.info(`${this.syncResourceLogLabel}: Disabled extension`, e.identifier.id, extension.version); + this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...`, e.identifier.id); + await extensionEnablementService.disableExtension(e.identifier); + this.logService.info(`${this.syncResourceLogLabel}: Disabled extension`, e.identifier.id); } else { - this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...`, e.identifier.id, extension.version); - await this.extensionEnablementService.enableExtension(extension.identifier); - this.logService.info(`${this.syncResourceLogLabel}: Enabled extension`, e.identifier.id, extension.version); + this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...`, e.identifier.id); + await extensionEnablementService.enableExtension(e.identifier); + this.logService.info(`${this.syncResourceLogLabel}: Enabled extension`, e.identifier.id); } } - - if (!installedExtension // Install if the extension does not exist - || installedExtension.preRelease !== e.preRelease // Install if the extension pre-release preference has changed - ) { - if (await this.extensionManagementService.canInstall(extension)) { - this.logService.trace(`${this.syncResourceLogLabel}: Installing extension...`, e.identifier.id, extension.version); - await this.extensionManagementService.installFromGallery(extension, { isMachineScoped: false, donotIncludePackAndDependencies: true, installPreReleaseVersion: e.preRelease, profileLocation: this.profileLocation } /* set isMachineScoped value to prevent install and sync dialog in web */); - this.logService.info(`${this.syncResourceLogLabel}: Installed extension.`, e.identifier.id, extension.version); - removeFromSkipped.push(extension.identifier); - } else { - this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because it cannot be installed.`, extension.displayName || extension.identifier.id); - addToSkipped.push(e); - } - } - } catch (error) { - addToSkipped.push(e); - if (error instanceof ExtensionManagementError && [ExtensionManagementErrorCode.Incompatible, ExtensionManagementErrorCode.IncompatiblePreRelease, ExtensionManagementErrorCode.IncompatibleTargetPlatform].includes(error.code)) { - this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because the compatible extension is not found.`, extension.displayName || extension.identifier.id); - } else { - this.logService.error(error); - this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension`, extension.displayName || extension.identifier.id); - } + removeFromSkipped.push(e.identifier); + return; } - } else { - addToSkipped.push(e); - this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because the extension is not found.`, e.identifier.id); - } - })); - } - const newSkippedExtensions: ISyncExtension[] = []; - for (const skippedExtension of skippedExtensions) { - if (!removeFromSkipped.some(e => areSameExtensions(e, skippedExtension.identifier))) { - newSkippedExtensions.push(skippedExtension); + // User Extension Sync: Install/Update, Enablement & State + const extension = (await this.extensionGalleryService.getExtensions([{ ...e.identifier, preRelease: e.preRelease }], CancellationToken.None))[0]; + + /* Update extension state only if + * extension is installed and version is same as synced version or + * extension is not installed and installable + */ + if (e.state && + (installedExtension ? installedExtension.manifest.version === e.version /* Installed and has same version */ + : !!extension /* Installable */) + ) { + this.updateExtensionState(e.state, installedExtension || extension, installedExtension?.manifest.version, extensionStorageService); + } + + if (extension) { + try { + const isDisabled = extensionEnablementService.getDisabledExtensions().some(disabledExtension => areSameExtensions(disabledExtension, e.identifier)); + if (isDisabled !== !!e.disabled) { + if (e.disabled) { + this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...`, e.identifier.id, extension.version); + await extensionEnablementService.disableExtension(extension.identifier); + this.logService.info(`${this.syncResourceLogLabel}: Disabled extension`, e.identifier.id, extension.version); + } else { + this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...`, e.identifier.id, extension.version); + await extensionEnablementService.enableExtension(extension.identifier); + this.logService.info(`${this.syncResourceLogLabel}: Enabled extension`, e.identifier.id, extension.version); + } + } + + if (!installedExtension // Install if the extension does not exist + || installedExtension.preRelease !== e.preRelease // Install if the extension pre-release preference has changed + ) { + if (await this.extensionManagementService.canInstall(extension)) { + this.logService.trace(`${this.syncResourceLogLabel}: Installing extension...`, e.identifier.id, extension.version); + await this.extensionManagementService.installFromGallery(extension, { isMachineScoped: false, donotIncludePackAndDependencies: true, installPreReleaseVersion: e.preRelease, profileLocation: this.profileLocation } /* set isMachineScoped value to prevent install and sync dialog in web */); + this.logService.info(`${this.syncResourceLogLabel}: Installed extension.`, e.identifier.id, extension.version); + removeFromSkipped.push(extension.identifier); + } else { + this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because it cannot be installed.`, extension.displayName || extension.identifier.id); + addToSkipped.push(e); + } + } + } catch (error) { + addToSkipped.push(e); + if (error instanceof ExtensionManagementError && [ExtensionManagementErrorCode.Incompatible, ExtensionManagementErrorCode.IncompatiblePreRelease, ExtensionManagementErrorCode.IncompatibleTargetPlatform].includes(error.code)) { + this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because the compatible extension is not found.`, extension.displayName || extension.identifier.id); + } else { + this.logService.error(error); + this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension`, extension.displayName || extension.identifier.id); + } + } + } else { + addToSkipped.push(e); + this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing extension because the extension is not found.`, e.identifier.id); + } + })); } - } - for (const skippedExtension of addToSkipped) { - if (!newSkippedExtensions.some(e => areSameExtensions(e.identifier, skippedExtension.identifier))) { - newSkippedExtensions.push(skippedExtension); + + const newSkippedExtensions: ISyncExtension[] = []; + for (const skippedExtension of skippedExtensions) { + if (!removeFromSkipped.some(e => areSameExtensions(e, skippedExtension.identifier))) { + newSkippedExtensions.push(skippedExtension); + } } - } - return newSkippedExtensions; + for (const skippedExtension of addToSkipped) { + if (!newSkippedExtensions.some(e => areSameExtensions(e.identifier, skippedExtension.identifier))) { + newSkippedExtensions.push(skippedExtension); + } + } + return newSkippedExtensions; + }); } - private updateExtensionState(state: IStringDictionary, extension: ILocalExtension | IGalleryExtension, version: string | undefined): void { - const extensionState = this.extensionStorageService.getExtensionState(extension, true) || {}; - const keys = version ? this.extensionStorageService.getKeysForSync({ id: extension.identifier.id, version }) : undefined; + private updateExtensionState(state: IStringDictionary, extension: ILocalExtension | IGalleryExtension, version: string | undefined, extensionStorageService: IExtensionStorageService): void { + const extensionState = extensionStorageService.getExtensionState(extension, true) || {}; + const keys = version ? extensionStorageService.getKeysForSync({ id: extension.identifier.id, version }) : undefined; if (keys) { keys.forEach(key => { extensionState[key] = state[key]; }); } else { Object.keys(state).forEach(key => extensionState[key] = state[key]); } - this.extensionStorageService.setExtensionState(extension, extensionState, true); + extensionStorageService.setExtensionState(extension, extensionState, true); } private parseExtensions(syncData: ISyncData): ISyncExtension[] { return JSON.parse(syncData.content); } - private getLocalExtensions(installedExtensions: ILocalExtension[]): ISyncExtensionWithVersion[] { - const disabledExtensions = this.extensionEnablementService.getDisabledExtensions(); - return installedExtensions - .map(extension => { - const { identifier, isBuiltin, manifest, preRelease } = extension; - const syncExntesion: ISyncExtensionWithVersion = { identifier, preRelease, version: manifest.version }; - if (disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier))) { - syncExntesion.disabled = true; - } - if (!isBuiltin) { - syncExntesion.installed = true; - } - try { - const keys = this.extensionStorageService.getKeysForSync({ id: identifier.id, version: manifest.version }); - if (keys) { - const extensionStorageState = this.extensionStorageService.getExtensionState(extension, true) || {}; - syncExntesion.state = Object.keys(extensionStorageState).reduce((state: IStringDictionary, key) => { - if (keys.includes(key)) { - state[key] = extensionStorageState[key]; - } - return state; - }, {}); + private getLocalExtensions(installedExtensions: ILocalExtension[]): Promise { + return this.withProfileScopedServices(async (extensionEnablementService, extensionStorageService) => { + const disabledExtensions = extensionEnablementService.getDisabledExtensions(); + return installedExtensions + .map(extension => { + const { identifier, isBuiltin, manifest, preRelease } = extension; + const syncExntesion: ISyncExtensionWithVersion = { identifier, preRelease, version: manifest.version }; + if (disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier))) { + syncExntesion.disabled = true; } - } catch (error) { - this.logService.info(`${this.syncResourceLogLabel}: Error while parsing extension state`, getErrorMessage(error)); + if (!isBuiltin) { + syncExntesion.installed = true; + } + try { + const keys = extensionStorageService.getKeysForSync({ id: identifier.id, version: manifest.version }); + if (keys) { + const extensionStorageState = extensionStorageService.getExtensionState(extension, true) || {}; + syncExntesion.state = Object.keys(extensionStorageState).reduce((state: IStringDictionary, key) => { + if (keys.includes(key)) { + state[key] = extensionStorageState[key]; + } + return state; + }, {}); + } + } catch (error) { + this.logService.info(`${this.syncResourceLogLabel}: Error while parsing extension state`, getErrorMessage(error)); + } + return syncExntesion; + }); + }); + } + + private async withProfileScopedServices(fn: (extensionEnablementService: IGlobalExtensionEnablementService, extensionStorageService: IExtensionStorageService) => Promise): Promise { + return this.userDataSyncProfilesStorageService.withProfileScopedStorageService(this.syncResource.profile, + async storageService => { + const disposables = new DisposableStore(); + const instantiationService = this.instantiationService.createChild(new ServiceCollection([IStorageService, storageService])); + const extensionEnablementService = disposables.add(instantiationService.createInstance(GlobalExtensionEnablementService)); + const extensionStorageService = disposables.add(instantiationService.createInstance(ExtensionStorageService)); + try { + return await fn(extensionEnablementService, extensionStorageService); + } finally { + disposables.dispose(); } - return syncExntesion; }); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts b/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts index a557f070ce5..d90616fef82 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts @@ -47,6 +47,11 @@ export interface IUserDataSyncProfilesStorageService { * @param target Storage target of the data */ updateStorageData(profile: IUserDataProfile, data: Map, target: StorageTarget): Promise; + + /** + * Calls a function with a storage service scoped to given profile. + */ + withProfileScopedStorageService(profile: IUserDataProfile, fn: (storageService: IStorageService) => Promise): Promise; } export abstract class AbstractUserDataSyncProfilesStorageService extends Disposable implements IUserDataSyncProfilesStorageService { @@ -62,34 +67,25 @@ export abstract class AbstractUserDataSyncProfilesStorageService extends Disposa } async readStorageData(profile: IUserDataProfile): Promise> { - // Use current storage service if the profile is same - if (this.storageService.hasScope(profile)) { - return this.getItems(this.storageService); - } - - const storageDatabase = await this.createStorageDatabase(profile); - const storageService = new StorageService(storageDatabase); - try { - await storageService.initialize(); - return this.getItems(storageService); - } finally { - storageService.dispose(); - await this.closeAndDispose(storageDatabase); - } + return this.withProfileScopedStorageService(profile, async storageService => this.getItems(storageService)); } async updateStorageData(profile: IUserDataProfile, data: Map, target: StorageTarget): Promise { - // Use current storage service if the profile is same + return this.withProfileScopedStorageService(profile, async storageService => this.writeItems(storageService, data, target)); + } + + async withProfileScopedStorageService(profile: IUserDataProfile, fn: (storageService: IStorageService) => Promise): Promise { if (this.storageService.hasScope(profile)) { - return this.writeItems(this.storageService, data, target); + return fn(this.storageService); } const storageDatabase = await this.createStorageDatabase(profile); const storageService = new StorageService(storageDatabase); try { await storageService.initialize(); - this.writeItems(storageService, data, target); + const result = await fn(storageService); await storageService.flush(); + return result; } finally { storageService.dispose(); await this.closeAndDispose(storageDatabase); From 64a49c608578e445e8811f7cd890ccc34f3e1db7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 09:14:47 +0200 Subject: [PATCH 038/599] fix errors in unit test output (#161712) --- .../extensionsActions.test.ts | 81 +++++++++++++------ .../electron-browser/extensionsViews.test.ts | 9 ++- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 84f36953148..7b468431a75 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -138,7 +138,7 @@ async function setupTest() { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', []); - instantiationService.stub(IExtensionService, >{ extensions: [], onDidChangeExtensions: Event.None, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false }); + instantiationService.stub(IExtensionService, >{ extensions: [], onDidChangeExtensions: Event.None, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false, whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); (instantiationService.get(IWorkbenchExtensionEnablementService)).reset(); instantiationService.stub(IUserDataSyncEnablementService, instantiationService.createInstance(UserDataSyncEnablementService)); @@ -783,6 +783,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -837,6 +838,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IExtensionsWorkbenchService).queryLocal() @@ -853,6 +855,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IExtensionsWorkbenchService).queryLocal() @@ -868,6 +871,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) @@ -889,6 +893,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(aLocalExtension('a'))], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None) @@ -905,6 +910,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(aLocalExtension('a'))], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None) @@ -923,6 +929,7 @@ suite('ExtensionsActions', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); return instantiationService.get(IExtensionsWorkbenchService).queryLocal() @@ -979,7 +986,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1003,7 +1011,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => true + canAddExtension: (extension) => true, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1024,7 +1033,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1047,7 +1057,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a', { version: '1.0.0' }))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); @@ -1069,7 +1080,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(local)], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => true, - canAddExtension: (extension) => true + canAddExtension: (extension) => true, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1087,7 +1099,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a', { version: '1.0.0' }))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1112,7 +1125,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a', { version: '1.0.1' }))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => true, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); @@ -1140,7 +1154,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const local = aLocalExtension('a', { version: '1.0.1' }); await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); @@ -1163,7 +1178,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); @@ -1185,7 +1201,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a', { version: '1.0.0' }))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); @@ -1205,7 +1222,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const local = aLocalExtension('a'); await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); @@ -1226,7 +1244,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const local = aLocalExtension('a'); await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); @@ -1246,7 +1265,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const local = aLocalExtension('a', { version: '1.0.1' }); await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); @@ -1271,7 +1291,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('b'))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1292,7 +1313,8 @@ suite('ReloadAction', () => { extensions: [toExtensionDescription(aLocalExtension('a', { version: '1.0.1' }))], onDidChangeExtensions: Event.None, canRemoveExtension: (extension) => false, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1320,7 +1342,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(remoteExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.set(IExtensionsWorkbenchService, workbenchService); @@ -1353,7 +1376,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(remoteExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.set(IExtensionsWorkbenchService, workbenchService); @@ -1391,7 +1415,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1429,7 +1454,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1465,7 +1491,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(localExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.set(IExtensionsWorkbenchService, workbenchService); @@ -1499,7 +1526,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(localExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1530,7 +1558,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(remoteExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1561,7 +1590,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(localExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1592,7 +1622,8 @@ suite('ReloadAction', () => { instantiationService.stub(IExtensionService, >{ extensions: [toExtensionDescription(remoteExtension)], onDidChangeExtensions: onDidChangeExtensionsEmitter.event, - canAddExtension: (extension) => false + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index d513feae320..123c8cb5676 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -48,7 +48,7 @@ import { platform } from 'vs/base/common/platform'; import { arch } from 'vs/base/common/process'; import { IProductService } from 'vs/platform/product/common/productService'; -suite('ExtensionsListView Tests', () => { +suite('ExtensionsViews Tests', () => { let instantiationService: TestInstantiationService; let testableView: ExtensionsListView; @@ -184,7 +184,8 @@ suite('ExtensionsListView Tests', () => { toExtensionDescription(localRandom), toExtensionDescription(builtInTheme), toExtensionDescription(builtInBasic) - ] + ], + whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); await (instantiationService.get(IWorkbenchExtensionEnablementService)).setEnablement([localDisabledTheme], EnablementState.DisabledGlobally); await (instantiationService.get(IWorkbenchExtensionEnablementService)).setEnablement([localDisabledLanguage], EnablementState.DisabledGlobally); @@ -398,7 +399,7 @@ suite('ExtensionsListView Tests', () => { const target = instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', allRecommendedExtensions); return testableView.show('@recommended').then(result => { - const extensionInfos: IExtensionInfo[] = target.args[0][0]; + const extensionInfos: IExtensionInfo[] = target.args[1][0]; assert.strictEqual(extensionInfos.length, allRecommendedExtensions.length); assert.strictEqual(result.length, allRecommendedExtensions.length); @@ -423,7 +424,7 @@ suite('ExtensionsListView Tests', () => { const target = instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', allRecommendedExtensions); return testableView.show('@recommended:all').then(result => { - const extensionInfos: IExtensionInfo[] = target.args[0][0]; + const extensionInfos: IExtensionInfo[] = target.args[1][0]; assert.strictEqual(extensionInfos.length, allRecommendedExtensions.length); assert.strictEqual(result.length, allRecommendedExtensions.length); From 278e668cad3742a9fd15da53bc1e6496e9802f19 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 26 Sep 2022 00:15:08 -0700 Subject: [PATCH 039/599] Invalid regular expression: /[A-Za-z0-9]{4}.c++/: Nothing to repeat (fix #161733) (#161740) --- .../services/workingCopy/common/workingCopyHistoryService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts index 07c1ae6d65a..d758a61f093 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts @@ -29,6 +29,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { SaveSource, SaveSourceRegistry } from 'vs/workbench/common/editor'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { lastOrDefault } from 'vs/base/common/arrays'; +import { escapeRegExpCharacters } from 'vs/base/common/strings'; interface ISerializedWorkingCopyHistoryModel { readonly version: number; @@ -103,7 +104,7 @@ export class WorkingCopyHistoryModel { this.workingCopyResource = workingCopyResource; this.workingCopyName = this.labelService.getUriBasenameLabel(workingCopyResource); - this.historyEntriesNameMatcher = new RegExp(`[A-Za-z0-9]{4}${extname(workingCopyResource)}`); + this.historyEntriesNameMatcher = new RegExp(`[A-Za-z0-9]{4}${escapeRegExpCharacters(extname(workingCopyResource))}`); // Update locations this.historyEntriesFolder = this.toHistoryEntriesFolder(this.historyHome, workingCopyResource); From 03ca1e0d4033f9d70717b760c3100e33ae4f9fd1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 26 Sep 2022 00:16:42 -0700 Subject: [PATCH 040/599] tests - align tests on all platforms (#161696) * web - run ipynb tests on windows too * some cleanup * run all tests * more cleanup --- scripts/test-integration.bat | 25 +------- scripts/test-integration.sh | 25 +------- scripts/test-remote-integration.bat | 95 ++++++++++++++++++++--------- scripts/test-remote-integration.sh | 27 ++------ scripts/test-web-integration.bat | 27 ++++---- scripts/test-web-integration.sh | 13 +--- 6 files changed, 94 insertions(+), 118 deletions(-) diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index feabb6dc4e8..e5b356f3dec 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -9,40 +9,21 @@ set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests :: Figure out which Electron to use for running tests if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( - :: Run out of sources: no need to compile as code.bat takes care of it chcp 65001 set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1 - echo Storing crash reports into '%VSCODECRASHDIR%'. - echo Storing log files into '%VSCODELOGSDIR%'. echo Running integration tests out of sources. ) else ( - :: Run from a built: need to compile all test extensions - :: because we run extension tests from their source folders - :: and the build bundles extensions into .build webpacked - :: call yarn gulp compile-extension:vscode-api-tests^ - :: compile-extension:vscode-colorize-tests^ - :: compile-extension:markdown-language-features^ - :: compile-extension:typescript-language-features^ - :: compile-extension:emmet^ - :: compile-extension:css-language-features-server^ - :: compile-extension:html-language-features-server^ - :: compile-extension:json-language-features-server^ - :: compile-extension:git^ - :: compile-extension:ipynb^ - :: compile-extension:configuration-editing^ - :: compile-extension-media - - :: Configuration for more verbose output set VSCODE_CLI=1 set ELECTRON_ENABLE_LOGGING=1 - echo Storing crash reports into '%VSCODECRASHDIR%'. - echo Storing log files into '%VSCODELOGSDIR%'. echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build. ) +echo Storing crash reports into '%VSCODECRASHDIR%'. +echo Storing log files into '%VSCODELOGSDIR%'. + :: Tests standalone (AMD) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 4e82d1453d7..e43ef46016c 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -20,38 +20,19 @@ cd $ROOT # Figure out which Electron to use for running tests if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] then - # Run out of sources: no need to compile as code.sh takes care of it INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" - echo "Storing crash reports into '$VSCODECRASHDIR'." - echo "Storing log files into '$VSCODELOGSDIR'." echo "Running integration tests out of sources." else - # Run from a built: need to compile all test extensions - # because we run extension tests from their source folders - # and the build bundles extensions into .build webpacked - # yarn gulp compile-extension:vscode-api-tests \ - # compile-extension:vscode-colorize-tests \ - # compile-extension:markdown-language-features \ - # compile-extension:typescript-language-features \ - # compile-extension:emmet \ - # compile-extension:css-language-features-server \ - # compile-extension:html-language-features-server \ - # compile-extension:json-language-features-server \ - # compile-extension:git \ - # compile-extension:ipynb \ - # compile-extension:configuration-editing \ - # compile-extension-media - - # Configuration for more verbose output export VSCODE_CLI=1 export ELECTRON_ENABLE_LOGGING=1 - echo "Storing crash reports into '$VSCODECRASHDIR'." - echo "Storing log files into '$VSCODELOGSDIR'." echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." fi +echo "Storing crash reports into '$VSCODECRASHDIR'." +echo "Storing log files into '$VSCODELOGSDIR'." + # Tests standalone (AMD) diff --git a/scripts/test-remote-integration.bat b/scripts/test-remote-integration.bat index a7d0719205f..e0fda5d1c4e 100644 --- a/scripts/test-remote-integration.bat +++ b/scripts/test-remote-integration.bat @@ -19,7 +19,7 @@ IF "%VSCODEUSERDATADIR%" == "" ( set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5% ) -set REMOTE_VSCODE=%AUTHORITY%%EXT_PATH% +set REMOTE_EXT_PATH=%AUTHORITY%%EXT_PATH% set VSCODECRASHDIR=%~dp0\..\.build\crashes set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests-remote set TESTRESOLVER_DATA_FOLDER=%TMP%\testresolverdatafolder-%RANDOM%-%TIME:~6,5% @@ -32,45 +32,80 @@ if "%VSCODE_REMOTE_SERVER_PATH%"=="" ( echo Using '%VSCODE_REMOTE_SERVER_PATH%' as server path ) -set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --disable-keytar --disable-inspect --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR% - :: Figure out which Electron to use for running tests if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( - echo Storing crash reports into '%VSCODECRASHDIR%' - echo Storing log files into '%VSCODELOGSDIR%' + chcp 65001 + set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat + set API_TESTS_EXTRA_ARGS_BUILT= - :: Tests in the extension host running from sources - call .\scripts\code.bat --folder-uri=%REMOTE_VSCODE%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% - if %errorlevel% neq 0 exit /b %errorlevel% - - call .\scripts\code.bat --file-uri=%REMOTE_VSCODE%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% - if %errorlevel% neq 0 exit /b %errorlevel% + echo Running integration tests out of sources. ) else ( - echo Storing crash reports into '%VSCODECRASHDIR%' - echo Storing log files into '%VSCODELOGSDIR%' - echo Using %INTEGRATION_TEST_ELECTRON_PATH% as Electron path - - :: Run from a built: need to compile all test extensions - :: because we run extension tests from their source folders - :: and the build bundles extensions into .build webpacked - :: call yarn gulp compile-extension:vscode-api-tests^ - :: compile-extension:microsoft-authentication^ - :: compile-extension:github-authentication^ - :: compile-extension:vscode-test-resolver - - :: Configuration for more verbose output set VSCODE_CLI=1 set ELECTRON_ENABLE_LOGGING=1 - set ELECTRON_ENABLE_STACK_DUMPING=1 - :: Tests in the extension host running from built version (both client and server) - call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_VSCODE%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests - if %errorlevel% neq 0 exit /b %errorlevel% + :: Extra arguments only when running against a built version + set API_TESTS_EXTRA_ARGS_BUILT=--extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests - call "%INTEGRATION_TEST_ELECTRON_PATH%" --file-uri=%REMOTE_VSCODE%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests - if %errorlevel% neq 0 exit /b %errorlevel% + echo Using %INTEGRATION_TEST_ELECTRON_PATH% as Electron path ) +echo Storing crash reports into '%VSCODECRASHDIR%' +echo Storing log files into '%VSCODELOGSDIR%' + + +:: Tests in the extension host + +set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --disable-keytar --disable-inspect --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR% + +echo. +echo ### API tests (folder) +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/vscode-api-tests --extensionTestsPath=%REMOTE_EXT_PATH%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### API tests (workspace) +call "%INTEGRATION_TEST_ELECTRON_PATH%" --file-uri=%REMOTE_EXT_PATH%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/vscode-api-tests --extensionTestsPath=%REMOTE_EXT_PATH%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### TypeScript tests +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/typescript-language-features/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/typescript-language-features --extensionTestsPath=%REMOTE_EXT_PATH%/typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Markdown tests +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/markdown-language-features/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/markdown-language-features --extensionTestsPath=%REMOTE_EXT_PATH%/markdown-language-features/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Emmet tests +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/emmet/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/emmet --extensionTestsPath=%REMOTE_EXT_PATH%/emmet/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Git tests +for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i +set GITWORKSPACE=%TEMPDIR%\git-%RANDOM% +mkdir %GITWORKSPACE% +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%%GITWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/git --extensionTestsPath=%REMOTE_EXT_PATH%/git/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Ipynb tests +set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM% +mkdir %IPYNBWORKSPACE% +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%%IPYNBWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/ipynb --extensionTestsPath=%REMOTE_EXT_PATH%/ipynb/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Configuration editing tests +set CFWORKSPACE=%TEMPDIR%\cf-%RANDOM% +mkdir %CFWORKSPACE% +call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%/%CFWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/configuration-editing --extensionTestsPath=%REMOTE_EXT_PATH%/configuration-editing/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT% +if %errorlevel% neq 0 exit /b %errorlevel% + +:: Cleanup + IF "%3" == "" ( rmdir /s /q %VSCODEUSERDATADIR% ) diff --git a/scripts/test-remote-integration.sh b/scripts/test-remote-integration.sh index 6d883f53217..8163e796645 100755 --- a/scripts/test-remote-integration.sh +++ b/scripts/test-remote-integration.sh @@ -34,40 +34,19 @@ export REMOTE_VSCODE=$AUTHORITY$EXT_PATH # Figure out which Electron to use for running tests if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] then - # Run out of sources: no need to compile as code.sh takes care of it INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" # No extra arguments when running out of sources EXTRA_INTEGRATION_TEST_ARGUMENTS="" - echo "Storing crash reports into '$VSCODECRASHDIR'." - echo "Storing log files into '$VSCODELOGSDIR'." echo "Running remote integration tests out of sources." else - # Run from a built: need to compile all test extensions - # because we run extension tests from their source folders - # and the build bundles extensions into .build webpacked - # yarn gulp compile-extension:vscode-api-tests \ - # compile-extension:vscode-test-resolver \ - # compile-extension:markdown-language-features \ - # compile-extension:typescript-language-features \ - # compile-extension:emmet \ - # compile-extension:git \ - # compile-extension:ipynb \ - # compile-extension:configuration-editing \ - # compile-extension:microsoft-authentication \ - # compile-extension:github-authentication \ - # compile-extension-media - - # Configuration for more verbose output export VSCODE_CLI=1 export ELECTRON_ENABLE_LOGGING=1 # Running from a build, we need to enable the vscode-test-resolver extension EXTRA_INTEGRATION_TEST_ARGUMENTS="--extensions-dir=$EXT_PATH --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests" - echo "Storing crash reports into '$VSCODECRASHDIR'." - echo "Storing log files into '$VSCODELOGSDIR'." echo "Running remote integration tests with $INTEGRATION_TEST_ELECTRON_PATH as build." fi @@ -91,6 +70,12 @@ fi API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --disable-keytar --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR" +echo "Storing crash reports into '$VSCODECRASHDIR'." +echo "Storing log files into '$VSCODELOGSDIR'." + + +# Tests in the extension host + echo echo "### API tests (folder)" echo diff --git a/scripts/test-web-integration.bat b/scripts/test-web-integration.bat index 7be27c00b31..700dd0a045e 100644 --- a/scripts/test-web-integration.bat +++ b/scripts/test-web-integration.bat @@ -18,20 +18,11 @@ IF "%~1" == "" ( set REMOTE_VSCODE=%AUTHORITY%%EXT_PATH% if "%VSCODE_REMOTE_SERVER_PATH%"=="" ( + chcp 65001 + echo Using remote server out of sources for integration web tests ) else ( echo Using '%VSCODE_REMOTE_SERVER_PATH%' as server path for web integration tests - - :: Run from a built: need to compile all test extensions - :: because we run extension tests from their source folders - :: and the build bundles extensions into .build webpacked - :: call yarn gulp compile-extension:vscode-api-tests^ - :: compile-extension:markdown-language-features^ - :: compile-extension:typescript-language-features^ - :: compile-extension:emmet^ - :: compile-extension:configuration-editing^ - :: compile-extension:git^ - :: compile-extension-media ) if not exist ".\test\integration\browser\out\index.js" ( @@ -39,6 +30,9 @@ if not exist ".\test\integration\browser\out\index.js" ( call yarn playwright-install ) + +:: Tests in the extension host + echo. echo ### API tests (folder) call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=.\extensions\vscode-api-tests --extensionTestsPath=.\extensions\vscode-api-tests\out\singlefolder-tests %* @@ -72,9 +66,20 @@ mkdir %GITWORKSPACE% call node .\test\integration\browser\out\index.js --workspacePath=%GITWORKSPACE% --extensionDevelopmentPath=.\extensions\git --extensionTestsPath=.\extensions\git\out\test %* if %errorlevel% neq 0 exit /b %errorlevel% +echo. +echo ### Ipynb tests +set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM% +mkdir %IPYNBWORKSPACE% +call node .\test\integration\browser\out\index.js --workspacePath=%IPYNBWORKSPACE% --extensionDevelopmentPath=.\extensions\ipynb --extensionTestsPath=.\extensions\ipynb\out\test %* +if %errorlevel% neq 0 exit /b %errorlevel% + echo. echo ### Configuration editing tests set CFWORKSPACE=%TEMPDIR%\git-%RANDOM% mkdir %CFWORKSPACE% call node .\test\integration\browser\out\index.js --workspacePath=%CFWORKSPACE% --extensionDevelopmentPath=.\extensions\configuration-editing --extensionTestsPath=.\extensions\configuration-editing\out\test %* if %errorlevel% neq 0 exit /b %errorlevel% + +popd + +endlocal diff --git a/scripts/test-web-integration.sh b/scripts/test-web-integration.sh index 95278eec0e3..0648a7f8cd8 100755 --- a/scripts/test-web-integration.sh +++ b/scripts/test-web-integration.sh @@ -15,18 +15,6 @@ then echo "Using remote server out of sources for integration web tests" else echo "Using $VSCODE_REMOTE_SERVER_PATH as server path for web integration tests" - - # Run from a built: need to compile all test extensions - # because we run extension tests from their source folders - # and the build bundles extensions into .build webpacked - # yarn gulp compile-extension:vscode-api-tests \ - # compile-extension:markdown-language-features \ - # compile-extension:typescript-language-features \ - # compile-extension:emmet \ - # compile-extension:git \ - # compile-extension:ipynb \ - # compile-extension:configuration-editing \ - # compile-extension-media fi if [ ! -e 'test/integration/browser/out/index.js' ];then @@ -34,6 +22,7 @@ if [ ! -e 'test/integration/browser/out/index.js' ];then yarn playwright-install fi + # Tests in the extension host echo From 9602b6ef70cc5ffa57bdbad5f96dbde753c23383 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 26 Sep 2022 16:23:07 +0900 Subject: [PATCH 041/599] chore: update electron@19.0.17 (#161663) From c3a60525711000ac7d07881316c62934bb26d5a9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 26 Sep 2022 09:43:48 +0200 Subject: [PATCH 042/599] restore `separator` class for Separator item (#161746) fixes https://github.com/microsoft/vscode/issues/161643 --- src/vs/base/common/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index 13db4add519..769e8039d7f 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -219,7 +219,7 @@ export class Separator implements IAction { readonly label: string = ''; readonly tooltip: string = ''; - readonly class: string = ''; + readonly class: string = 'separator'; readonly enabled: boolean = false; readonly checked: boolean = false; async run() { } From 831678f718c8e998adc40d4854d9d35d9586a09f Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 26 Sep 2022 09:47:37 +0200 Subject: [PATCH 043/599] Engineering - Update endgame notebooks (#161745) Update endgame notebooks --- .vscode/notebooks/endgame.github-issues | 2 +- .vscode/notebooks/my-endgame.github-issues | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index 0eac8b51a1b..a9a74d1af88 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"August 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"September 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 2032edb424b..4fb0550ed8d 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\r\n\r\n$MILESTONE=milestone:\"August 2022\"\r\n\r\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\n\n$MILESTONE=milestone:\"September 2022\"\n\n$MINE=assignee:@me" }, { "kind": 1, From a2317df678b41beedee30bbf9c26d57163006e5d Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 26 Sep 2022 11:13:05 +0200 Subject: [PATCH 044/599] disable/remove the fib-freeze action --- .../electron-sandbox/rendererAutoProfiler.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index fb86ebd5f9c..1e53958edc1 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -5,9 +5,9 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { generateUuid } from 'vs/base/common/uuid'; -import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +// import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +// import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -101,27 +101,27 @@ export class RendererProfiling { } -registerAction2(class SLOW extends Action2 { +// registerAction2(class SLOW extends Action2 { - constructor() { - super({ - id: 'slow.fib', - title: 'Fib(N)', - f1: true, - }); - } +// constructor() { +// super({ +// id: 'slow.fib', +// title: 'Fib(N)', +// f1: true, +// }); +// } - run(accessor: ServicesAccessor, ...args: any[]): void { - function fib(n: number): number { - if (n <= 2) { - return n; - } - return fib(n - 1) + fib(n - 2); - } +// run(accessor: ServicesAccessor, ...args: any[]): void { +// function fib(n: number): number { +// if (n <= 2) { +// return n; +// } +// return fib(n - 1) + fib(n - 2); +// } - console.log('fib(44): ', fib(44)); - } -}); +// console.log('fib(44): ', fib(44)); +// } +// }); type TelemetryEventData = { From 14288634b40d002cc68e92988534a0a0d49fde80 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 12:21:21 +0200 Subject: [PATCH 045/599] fix #161726 (#161759) --- .../contrib/extensions/browser/extensionEditor.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 6f0c73a98c1..96449b7b363 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -904,10 +904,14 @@ export class ExtensionEditor extends EditorPane { resources.push([localize('Marketplace', "Marketplace"), URI.parse(extension.url)]); } if (extension.repository) { - resources.push([localize('repository', "Repository"), URI.parse(extension.repository)]); + try { + resources.push([localize('repository', "Repository"), URI.parse(extension.repository)]); + } catch (error) {/* Ignore */ } } if (extension.url && extension.licenseUrl) { - resources.push([localize('license', "License"), URI.parse(extension.licenseUrl)]); + try { + resources.push([localize('license', "License"), URI.parse(extension.licenseUrl)]); + } catch (error) {/* Ignore */ } } if (extension.publisherUrl) { resources.push([extension.publisherDisplayName, extension.publisherUrl]); From eab981234f42194a815a62af1aeaa39d450614c8 Mon Sep 17 00:00:00 2001 From: John Murray Date: Mon, 26 Sep 2022 13:02:40 +0100 Subject: [PATCH 046/599] Allow filter widget some vertical movement (#158549) (#158583) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow filter widget some vertical movement (#158549) * Adopt PR suggestions * Use fixed vertical range instead of incurring cost of computing it. * Disable transition effect during drag, and implement vertical move with keyboard * make sure the hiding animation still works * Update src/vs/base/browser/ui/tree/abstractTree.ts Co-authored-by: João Moreno Co-authored-by: João Moreno --- src/vs/base/browser/ui/tree/abstractTree.ts | 30 +++++++++++++++++++++ src/vs/base/browser/ui/tree/media/tree.css | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index f592bca1564..3f8ae2b6737 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -700,6 +700,7 @@ class FindWidget extends Disposable { private readonly actionbar: ActionBar; private width = 0; private right = 0; + private top = 0; readonly _onDidDisable = new Emitter(); readonly onDidDisable = this._onDidDisable.event; @@ -757,11 +758,18 @@ class FindWidget extends Disposable { const startRight = this.right; const startX = e.pageX; + const startTop = this.top; + const startY = e.pageY; this.elements.grab.classList.add('grabbing'); + const transition = this.elements.root.style.transition; + this.elements.root.style.transition = 'unset'; + const update = (e: MouseEvent) => { const deltaX = e.pageX - startX; this.right = startRight - deltaX; + const deltaY = e.pageY - startY; + this.top = startTop + deltaY; this.layout(); }; @@ -769,6 +777,7 @@ class FindWidget extends Disposable { disposables.add(onWindowMouseUp.event(e => { update(e); this.elements.grab.classList.remove('grabbing'); + this.elements.root.style.transition = transition; disposables.dispose(); })); })); @@ -779,6 +788,7 @@ class FindWidget extends Disposable { this._register(onGrabKeyDown((e): any => { let right: number | undefined; + let top: number | undefined; if (e.keyCode === KeyCode.LeftArrow) { right = Number.POSITIVE_INFINITY; @@ -788,12 +798,30 @@ class FindWidget extends Disposable { right = this.right === 0 ? Number.POSITIVE_INFINITY : 0; } + if (e.keyCode === KeyCode.UpArrow) { + top = 0; + } else if (e.keyCode === KeyCode.DownArrow) { + top = Number.POSITIVE_INFINITY; + } + if (right !== undefined) { e.preventDefault(); e.stopPropagation(); this.right = right; this.layout(); } + + if (top !== undefined) { + e.preventDefault(); + e.stopPropagation(); + this.top = top; + const transition = this.elements.root.style.transition; + this.elements.root.style.transition = 'unset'; + this.layout(); + setTimeout(() => { + this.elements.root.style.transition = transition; + }, 0); + } })); this.onDidChangeValue = this.findInput.onDidChange; @@ -824,6 +852,8 @@ class FindWidget extends Disposable { this.width = width; this.right = clamp(this.right, 0, Math.max(0, width - 212)); this.elements.root.style.right = `${this.right}px`; + this.top = clamp(this.top, 0, 24); + this.elements.root.style.top = `${this.top}px`; } showMessage(message: IMessage): void { diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index bee620d57ef..9256e1e8077 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -83,7 +83,7 @@ } .monaco-tree-type-filter.disabled { - top: -40px; + top: -40px !important; } .monaco-tree-type-filter-grab { From b53b17bdd08e4eea9ada3bcd1c22b47f6bef0864 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 26 Sep 2022 14:32:12 +0200 Subject: [PATCH 047/599] collect command and timestamp, collect timestamp on long task, collect visible views, collect editors --- .../electron-sandbox/rendererAutoProfiler.ts | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index 1e53958edc1..12134bca348 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -5,12 +5,12 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { generateUuid } from 'vs/base/common/uuid'; -// import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -// import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ILogService } from 'vs/platform/log/common/log'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IViewDescriptorService } from 'vs/workbench/common/views'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITimerService } from 'vs/workbench/services/timer/browser/timerService'; @@ -24,6 +24,8 @@ export class RendererProfiling { @ILogService logService: ILogService, @ICommandService commandService: ICommandService, @ITelemetryService telemetryService: ITelemetryService, + @IViewDescriptorService viewsDescriptorService: IViewDescriptorService, + @IEditorService editorService: IEditorService, ) { timerService.whenReady().then(() => { @@ -32,8 +34,8 @@ export class RendererProfiling { const slowThreshold = (timerService.startupMetrics.timers.ellapsedRequire / 2) | 0; // Keep a record of the last events - const eventHistory = new RingBuffer(5); - this._disposables.add(commandService.onWillExecuteCommand(e => eventHistory.push(e.commandId))); + const eventHistory = new RingBuffer<{ command: string; timestamp: number }>(5); + this._disposables.add(commandService.onWillExecuteCommand(e => eventHistory.push({ command: e.commandId, timestamp: Date.now() }))); const sessionDisposables = this._disposables.add(new DisposableStore()); @@ -55,11 +57,21 @@ export class RendererProfiling { const sessionId = generateUuid(); logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); + // all visible views + const views = viewsDescriptorService.viewContainers.map(container => { + const model = viewsDescriptorService.getViewContainerModel(container); + return model.visibleViewDescriptors.map(view => view.id); + }); + + const editors = editorService.visibleEditors.map(editor => editor.typeId); // send telemetry event telemetryService.publicLog2('perf.freeze.events', { sessionId: sessionId, - events: JSON.stringify(eventHistory.values()), + timestamp: Date.now() - maxDuration, + recentCommands: JSON.stringify(eventHistory.values()), + views: JSON.stringify(views.flat()), + editors: JSON.stringify(editors), }); // start heartbeat monitoring @@ -86,7 +98,6 @@ export class RendererProfiling { obs.observe({ entryTypes: ['longtask'] }); })); - }); }); @@ -100,40 +111,22 @@ export class RendererProfiling { } } - -// registerAction2(class SLOW extends Action2 { - -// constructor() { -// super({ -// id: 'slow.fib', -// title: 'Fib(N)', -// f1: true, -// }); -// } - -// run(accessor: ServicesAccessor, ...args: any[]): void { -// function fib(n: number): number { -// if (n <= 2) { -// return n; -// } -// return fib(n - 1) + fib(n - 2); -// } - -// console.log('fib(44): ', fib(44)); -// } -// }); - - type TelemetryEventData = { sessionId: string; - events: string; + timestamp: number; + recentCommands: string; + views: string; + editors: string; }; type TelemetryEventClassification = { owner: 'jrieken'; - comment: 'A list of events that happened before a long task was reported'; - sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate samples and events' }; - events: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'List of events' }; + comment: 'Insight about what happened before/while a long task was reported'; + sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate CPU samples and events' }; + timestamp: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Unix time at which the long task approximately happened' }; + recentCommands: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Events prior to the long task' }; + views: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Visible views' }; + editors: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Visible editor' }; }; class RingBuffer { @@ -157,6 +150,6 @@ class RingBuffer { } values(): T[] { - return [...this._data.slice(this._index), this._data.slice(0, this._index)].filter(a => a !== RingBuffer._value); + return [...this._data.slice(this._index), ...this._data.slice(0, this._index)].filter(a => a !== RingBuffer._value); } } From 4caf63f62e97df8af4eb88259073dc5d2dceeff7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 26 Sep 2022 06:10:39 -0700 Subject: [PATCH 048/599] Lag/Freeze when running `workbench.action.openRecent` on not existing path (fix #161664) (#161742) * Lag/Freeze when running `workbench.action.openRecent` on not existing path (fix #161664) * use resource map --- .../platform/workspaces/common/workspaces.ts | 6 +- .../workspacesHistoryMainService.ts | 87 ++++++++++++------- 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 7bb8b5e1ec6..71e4a623f65 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -331,10 +331,10 @@ function isSerializedRecentFile(data: any): data is ISerializedRecentFile { export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined, logService: ILogService): IRecentlyOpened { const result: IRecentlyOpened = { workspaces: [], files: [] }; if (data) { - const restoreGracefully = function (entries: T[], func: (entry: T, index: number) => void) { + const restoreGracefully = function (entries: T[], onEntry: (entry: T, index: number) => void) { for (let i = 0; i < entries.length; i++) { try { - func(entries[i], i); + onEntry(entries[i], i); } catch (e) { logService.warn(`Error restoring recent entry ${JSON.stringify(entries[i])}: ${e.toString()}. Skip entry.`); } @@ -343,7 +343,7 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine const storedRecents = data as ISerializedRecentlyOpened; if (Array.isArray(storedRecents.entries)) { - restoreGracefully(storedRecents.entries, (entry) => { + restoreGracefully(storedRecents.entries, entry => { const label = entry.label; const remoteAuthority = entry.remoteAuthority; diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 7dc3f039050..2e8ebbcc496 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -23,6 +23,7 @@ import { IApplicationStorageMainService } from 'vs/platform/storage/electron-mai import { IRecent, IRecentFile, IRecentFolder, IRecentlyOpened, IRecentWorkspace, isRecentFile, isRecentFolder, isRecentWorkspace, restoreRecentlyOpened, toStoreData } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; +import { ResourceMap } from 'vs/base/common/map'; export const IWorkspacesHistoryMainService = createDecorator('workspacesHistoryMainService'); @@ -73,28 +74,28 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa //#region Workspaces History async addRecentlyOpened(recentToAdd: IRecent[]): Promise { - const workspaces: Array = []; - const files: IRecentFile[] = []; + let workspaces: Array = []; + let files: IRecentFile[] = []; for (const recent of recentToAdd) { // Workspace if (isRecentWorkspace(recent)) { - if (!this.workspacesManagementMainService.isUntitledWorkspace(recent.workspace) && this.indexOfWorkspace(workspaces, recent.workspace) === -1) { + if (!this.workspacesManagementMainService.isUntitledWorkspace(recent.workspace) && !this.containsWorkspace(workspaces, recent.workspace)) { workspaces.push(recent); } } // Folder else if (isRecentFolder(recent)) { - if (this.indexOfFolder(workspaces, recent.folderUri) === -1) { + if (!this.containsFolder(workspaces, recent.folderUri)) { workspaces.push(recent); } } // File else { - const alreadyExistsInHistory = this.indexOfFile(files, recent.fileUri) >= 0; + const alreadyExistsInHistory = this.containsFile(files, recent.fileUri); const shouldBeFiltered = recent.fileUri.scheme === Schemas.file && WorkspacesHistoryMainService.COMMON_FILES_FILTER.indexOf(basename(recent.fileUri)) >= 0; if (!alreadyExistsInHistory && !shouldBeFiltered) { @@ -108,7 +109,9 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } } - await this.addEntriesFromStorage(workspaces, files); + const mergedEntries = await this.mergeEntriesFromStorage({ workspaces, files }); + workspaces = mergedEntries.workspaces; + files = mergedEntries.files; if (workspaces.length > WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { workspaces.length = WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES; @@ -163,35 +166,53 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } async getRecentlyOpened(): Promise { - const workspaces: Array = []; - const files: IRecentFile[] = []; - - await this.addEntriesFromStorage(workspaces, files); - - return { workspaces, files }; + return this.mergeEntriesFromStorage(); } - private async addEntriesFromStorage(workspaces: Array, files: IRecentFile[]): Promise { + private async mergeEntriesFromStorage(existingEntries?: IRecentlyOpened): Promise { - // Get from storage - const recents = await this.getRecentlyOpenedFromStorage(); - for (const recent of recents.workspaces) { - const index = isRecentFolder(recent) ? this.indexOfFolder(workspaces, recent.folderUri) : this.indexOfWorkspace(workspaces, recent.workspace); - if (index >= 0) { - workspaces[index].label = workspaces[index].label || recent.label; - } else { - workspaces.push(recent); + // Build maps for more efficient lookup of existing entries that + // are passed in by storing based on workspace/file identifier + + const mapWorkspaceIdToWorkspace = new ResourceMap(uri => extUriBiasedIgnorePathCase.getComparisonKey(uri)); + if (existingEntries?.workspaces) { + for (const workspace of existingEntries.workspaces) { + mapWorkspaceIdToWorkspace.set(this.location(workspace), workspace); } } - for (const recent of recents.files) { - const index = this.indexOfFile(files, recent.fileUri); - if (index >= 0) { - files[index].label = files[index].label || recent.label; - } else { - files.push(recent); + const mapFileIdToFile = new ResourceMap(uri => extUriBiasedIgnorePathCase.getComparisonKey(uri)); + if (existingEntries?.files) { + for (const file of existingEntries.files) { + mapFileIdToFile.set(this.location(file), file); } } + + // Merge in entries from storage, preserving existing known entries + + const recentFromStorage = await this.getRecentlyOpenedFromStorage(); + for (const recentWorkspaceFromStorage of recentFromStorage.workspaces) { + const existingRecentWorkspace = mapWorkspaceIdToWorkspace.get(this.location(recentWorkspaceFromStorage)); + if (existingRecentWorkspace) { + existingRecentWorkspace.label = existingRecentWorkspace.label ?? recentWorkspaceFromStorage.label; + } else { + mapWorkspaceIdToWorkspace.set(this.location(recentWorkspaceFromStorage), recentWorkspaceFromStorage); + } + } + + for (const recentFileFromStorage of recentFromStorage.files) { + const existingRecentFile = mapFileIdToFile.get(this.location(recentFileFromStorage)); + if (existingRecentFile) { + existingRecentFile.label = existingRecentFile.label ?? recentFileFromStorage.label; + } else { + mapFileIdToFile.set(this.location(recentFileFromStorage), recentFileFromStorage); + } + } + + return { + workspaces: [...mapWorkspaceIdToWorkspace.values()], + files: [...mapFileIdToFile.values()] + }; } private async getRecentlyOpenedFromStorage(): Promise { @@ -235,16 +256,16 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa return recent.workspace.configPath; } - private indexOfWorkspace(recents: IRecent[], candidate: IWorkspaceIdentifier): number { - return recents.findIndex(recent => isRecentWorkspace(recent) && recent.workspace.id === candidate.id); + private containsWorkspace(recents: IRecent[], candidate: IWorkspaceIdentifier): boolean { + return !!recents.find(recent => isRecentWorkspace(recent) && recent.workspace.id === candidate.id); } - private indexOfFolder(recents: IRecent[], candidate: URI): number { - return recents.findIndex(recent => isRecentFolder(recent) && extUriBiasedIgnorePathCase.isEqual(recent.folderUri, candidate)); + private containsFolder(recents: IRecent[], candidate: URI): boolean { + return !!recents.find(recent => isRecentFolder(recent) && extUriBiasedIgnorePathCase.isEqual(recent.folderUri, candidate)); } - private indexOfFile(recents: IRecentFile[], candidate: URI): number { - return recents.findIndex(recent => extUriBiasedIgnorePathCase.isEqual(recent.fileUri, candidate)); + private containsFile(recents: IRecentFile[], candidate: URI): boolean { + return !!recents.find(recent => extUriBiasedIgnorePathCase.isEqual(recent.fileUri, candidate)); } //#endregion From 1a5c6ca518832ee088bbdcad1bd4852e517446b9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 06:24:49 -0700 Subject: [PATCH 049/599] Fix TestShellIntegrationAddon ctor args Fixes #161700 --- .../terminal/test/browser/xterm/shellIntegrationAddon.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts index f30df87be77..905b968d753 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts @@ -45,7 +45,7 @@ suite('ShellIntegrationAddon', () => { xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 }); const instantiationService = new TestInstantiationService(); instantiationService.stub(ILogService, NullLogService); - shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon); + shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon, true, undefined); xterm.loadAddon(shellIntegrationAddon); capabilities = shellIntegrationAddon.capabilities; }); From 33787082be84dd92af06f6e3e3bacb95ea4c94aa Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Mon, 26 Sep 2022 06:29:05 -0700 Subject: [PATCH 050/599] Enable auto-close of multi-line comments in cpp (#160357) --- extensions/cpp/language-configuration.json | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 9a88814ff35..79ef8aec28b 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -14,6 +14,7 @@ { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string", "comment"] }, { "open": "\"", "close": "\"", "notIn": ["string"] } + { "open": "/*", "close": "*/", "notIn": ["string", "comment"] }, ], "surroundingPairs": [ ["{", "}"], From a3dd303e4fef93ccf3a7068cd41004bd72302276 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 15:43:34 +0200 Subject: [PATCH 051/599] do not support installing remote extensions in a profile (#161765) --- .../remoteExtensionManagementService.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index c2e3673df9c..6320906637a 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -5,7 +5,7 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -47,13 +47,33 @@ export class NativeRemoteExtensionManagementService extends ExtensionManagementC super(channel); } + override getInstalled(type: ExtensionType | null = null, profileLocation?: URI): Promise { + if (profileLocation) { + throw new Error('Installing extensions to a specific profile is not supported in remote scenario'); + } + return super.getInstalled(type); + } + + override uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise { + if (options?.profileLocation) { + throw new Error('Installing extensions to a specific profile is not supported in remote scenario'); + } + return super.uninstall(extension, options); + } + override async install(vsix: URI, options?: InstallVSIXOptions): Promise { + if (options?.profileLocation) { + throw new Error('Installing extensions to a specific profile is not supported in remote scenario'); + } const local = await super.install(vsix, options); await this.installUIDependenciesAndPackedExtensions(local); return local; } override async installFromGallery(extension: IGalleryExtension, installOptions?: InstallOptions): Promise { + if (installOptions?.profileLocation) { + throw new Error('Installing extensions to a specific profile is not supported in remote scenario'); + } const local = await this.doInstallFromGallery(extension, installOptions); await this.installUIDependenciesAndPackedExtensions(local); return local; From 9ac5f48ff3eafae1fbb312a6081a80ff245fafff Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Mon, 26 Sep 2022 07:51:23 -0600 Subject: [PATCH 052/599] Add jsonc registration for TypeDoc config (#157362) This is supported as of TypeDoc 0.23. Since it is more commonly used than ember-cli, seems reasonable to add it here. --- extensions/json/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/json/package.json b/extensions/json/package.json index 8cb003806d4..ba3b94b8c78 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -61,7 +61,8 @@ "filenames": [ "babel.config.json", ".babelrc.json", - ".ember-cli" + ".ember-cli", + "typedoc.json" ], "configuration": "./language-configuration.json" } From cace09d0eb438575b9abf4c375710ec692aea357 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Mon, 26 Sep 2022 07:51:42 -0600 Subject: [PATCH 053/599] Add schema for typedoc.json to default jsonValidation (#157592) Add schema for typedoc.json to default jsonValidation --- extensions/typescript-language-features/package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 64b10a008ae..d050a4a931f 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -139,6 +139,10 @@ { "fileMatch": "jsconfig.*.json", "url": "./schemas/jsconfig.schema.json" + }, + { + "fileMatch": "typedoc.json", + "url": "https://typedoc.org/schema.json" } ], "configuration": { From 83248ce3741ead2606b5892274d090cfc93492ad Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Mon, 26 Sep 2022 16:00:07 +0200 Subject: [PATCH 054/599] Default to config icon for the property language (#158454) --- extensions/ini/package.json | 2 +- extensions/theme-seti/cgmanifest.json | 2 +- extensions/theme-seti/icons/seti.woff | Bin 37200 -> 37200 bytes .../theme-seti/icons/vs-seti-icon-theme.json | 26 ++++++++++-------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/extensions/ini/package.json b/extensions/ini/package.json index aa98ee3a353..0c7dda3c880 100644 --- a/extensions/ini/package.json +++ b/extensions/ini/package.json @@ -27,9 +27,9 @@ { "id": "properties", "extensions": [ + ".conf", ".properties", ".cfg", - ".conf", ".directory", ".gitattributes", ".gitconfig", diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json index 919b27b7c91..b2b36944416 100644 --- a/extensions/theme-seti/cgmanifest.json +++ b/extensions/theme-seti/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "seti-ui", "repositoryUrl": "https://github.com/jesseweed/seti-ui", - "commitHash": "2d10473b7575ec00c47eda751ea9caeec6b0b606" + "commitHash": "fd20793e5a75b350eab8d489165fb9b420df3f62" } }, "version": "0.1.0" diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff index f0e47486995b58f1484c564f76d10182211ecd47..88cb75699ed87eb3b572dd9fecbb97b8d3b714f6 100644 GIT binary patch delta 60 zcmV-C0K@;#q5{yO0+5UZA)otxv5?`3C8Mx6)$ SgMkUe0{{(T2~)F{in<1_R2_)` delta 60 zcmV-C0K@;#q5{yO0+5UZAo_j0v5?`3CF6xvv*P(}zA|t#zW|Cb+-I4y1es>O%-j#8 SI2f2fJODA93OKWtin<1)vmBrR diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index abf5c8a0a7e..b1044baf1cb 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -1575,8 +1575,6 @@ "cfm": "_coldfusion", "litcoffee": "_coffee", "config": "_config", - "cfg": "_config", - "conf": "_config", "cr": "_crystal", "ecr": "_crystal_embedded", "slang": "_crystal_embedded", @@ -1624,6 +1622,7 @@ "jade": "_jade", "class": "_java_1", "classpath": "_java", + "properties": "_java", "js.map": "_javascript", "spec.js": "_javascript_1", "test.js": "_javascript_1", @@ -1731,7 +1730,6 @@ "webp": "_image", "sublime-project": "_sublime", "sublime-workspace": "_sublime", - "fish": "_shell", "mov": "_video", "ogv": "_video", "webm": "_video", @@ -1774,7 +1772,6 @@ "direnv": "_config", "env": "_config", "static": "_config", - "editorconfig": "_config", "slugignore": "_config", "tmp": "_clock_1", "htaccess": "_config", @@ -1835,14 +1832,19 @@ "yarn.lock": "_yarn", "webpack.config.js": "_webpack", "webpack.config.cjs": "_webpack", + "webpack.config.ts": "_webpack", "webpack.config.build.js": "_webpack", "webpack.config.build.cjs": "_webpack", + "webpack.config.build.ts": "_webpack", "webpack.common.js": "_webpack", "webpack.common.cjs": "_webpack", + "webpack.common.ts": "_webpack", "webpack.dev.js": "_webpack", "webpack.dev.cjs": "_webpack", + "webpack.dev.ts": "_webpack", "webpack.prod.js": "_webpack", "webpack.prod.cjs": "_webpack", + "webpack.prod.ts": "_webpack", "license": "_license", "licence": "_license", "license.txt": "_license", @@ -1887,7 +1889,7 @@ "groovy": "_grails", "handlebars": "_mustache", "html": "_html_3", - "properties": "_java", + "properties": "_config", "java": "_java", "javascriptreact": "_react", "javascript": "_javascript", @@ -1976,8 +1978,6 @@ "cfm": "_coldfusion_light", "litcoffee": "_coffee_light", "config": "_config_light", - "cfg": "_config_light", - "conf": "_config_light", "cr": "_crystal_light", "ecr": "_crystal_embedded_light", "slang": "_crystal_embedded_light", @@ -2025,6 +2025,7 @@ "jade": "_jade_light", "class": "_java_1_light", "classpath": "_java_light", + "properties": "_java_light", "js.map": "_javascript_light", "spec.js": "_javascript_1_light", "test.js": "_javascript_1_light", @@ -2132,7 +2133,6 @@ "webp": "_image_light", "sublime-project": "_sublime_light", "sublime-workspace": "_sublime_light", - "fish": "_shell_light", "mov": "_video_light", "ogv": "_video_light", "webm": "_video_light", @@ -2175,7 +2175,6 @@ "direnv": "_config_light", "env": "_config_light", "static": "_config_light", - "editorconfig": "_config_light", "slugignore": "_config_light", "tmp": "_clock_1_light", "htaccess": "_config_light", @@ -2206,7 +2205,7 @@ "groovy": "_grails_light", "handlebars": "_mustache_light", "html": "_html_3_light", - "properties": "_java_light", + "properties": "_config_light", "java": "_java_light", "javascriptreact": "_react_light", "javascript": "_javascript_light", @@ -2314,14 +2313,19 @@ "yarn.lock": "_yarn_light", "webpack.config.js": "_webpack_light", "webpack.config.cjs": "_webpack_light", + "webpack.config.ts": "_webpack_light", "webpack.config.build.js": "_webpack_light", "webpack.config.build.cjs": "_webpack_light", + "webpack.config.build.ts": "_webpack_light", "webpack.common.js": "_webpack_light", "webpack.common.cjs": "_webpack_light", + "webpack.common.ts": "_webpack_light", "webpack.dev.js": "_webpack_light", "webpack.dev.cjs": "_webpack_light", + "webpack.dev.ts": "_webpack_light", "webpack.prod.js": "_webpack_light", "webpack.prod.cjs": "_webpack_light", + "webpack.prod.ts": "_webpack_light", "license": "_license_light", "licence": "_license_light", "license.txt": "_license_light", @@ -2344,5 +2348,5 @@ "npm-debug.log": "_npm_ignored_light" } }, - "version": "https://github.com/jesseweed/seti-ui/commit/2d10473b7575ec00c47eda751ea9caeec6b0b606" + "version": "https://github.com/jesseweed/seti-ui/commit/fd20793e5a75b350eab8d489165fb9b420df3f62" } \ No newline at end of file From d1f20dbf2d0a331e5e7def66e2843d9a758e6e32 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 07:01:42 -0700 Subject: [PATCH 055/599] Update xterm - Optimize critical I/O path for input latency xtermjs/xterm.js#4145 - Add PriorityTaskQueue xtermjs/xterm.js#4144 - Use the browser's IdleDeadline to determine max task time xtermjs/xterm.js#4143 - Defer paused renderer resize to idle callback xtermjs/xterm.js#4142 - Do char atlas warmup via new IdleTaskQueue xtermjs/xterm.js#4141 - Share rgba vars throughout Color.ts, fast setTheme parseColor xtermjs/xterm.js#4140 - Optimize contexts for reading frequently xtermjs/xterm.js#4137 - Fix width of upper 1/8 block char xtermjs/xterm.js#4134 Fixes #161323 --- package.json | 8 ++++---- remote/package.json | 8 ++++---- remote/web/package.json | 4 ++-- remote/web/yarn.lock | 16 ++++++++-------- remote/yarn.lock | 32 ++++++++++++++++---------------- yarn.lock | 32 ++++++++++++++++---------------- 6 files changed, 50 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index 9957d764a7f..6aef60a69eb 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.1", + "xterm": "5.1.0-beta.10", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", - "xterm-addon-serialize": "0.9.0-beta.1", + "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.2", - "xterm-headless": "5.1.0-beta.1", + "xterm-addon-webgl": "0.14.0-beta.8", + "xterm-headless": "5.1.0-beta.10", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index c6d2d2547ad..399771595e0 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.1", + "xterm": "5.1.0-beta.10", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", - "xterm-addon-serialize": "0.9.0-beta.1", + "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.2", - "xterm-headless": "5.1.0-beta.1", + "xterm-addon-webgl": "0.14.0-beta.8", + "xterm-headless": "5.1.0-beta.10", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index d7e6c49c66f..ced3eb18679 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,10 +11,10 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.1", + "xterm": "5.1.0-beta.10", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.2" + "xterm-addon-webgl": "0.14.0-beta.8" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index c9a0cd1bacf..72a9a2160ac 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -83,12 +83,12 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.2: - version "0.14.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.2.tgz#832c31b52b78fb67a65bbd23c9fb850caceb43ae" - integrity sha512-1ccbkJiUZ5ojnoAEJsbdV0jMZaYSnZ02wfV8yBU243u6TTgvCzZ7nq5BR9bT+5K/ESFWiekobfybxHwuYnylmQ== +xterm-addon-webgl@0.14.0-beta.8: + version "0.14.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" + integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm@5.1.0-beta.1: - version "5.1.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.1.tgz#a6617c6887066d166632d1e69b6eb83a179d8b63" - integrity sha512-ml7bqjO23bh4yu7qXKogXtCy4SbDTV21rfDXUvLPPaxrlQus6NoN1byy1eFH4ONWpv5ZHGeItRdQ/X00et9Pcw== +xterm@5.1.0-beta.10: + version "5.1.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" + integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== diff --git a/remote/yarn.lock b/remote/yarn.lock index 7b384ed44b9..f1b96db5bb3 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -798,30 +798,30 @@ xterm-addon-search@0.11.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.1.tgz#fe7178d70246cde73550447c5524672575467499" integrity sha512-fKj8KnnhH1nC4oZpKsgnhtgxkTctoa9kGLMpTJjsNzFu0VvXvLGIRezTPI75UEIQdEdaxcwB7/aKelQTO+72LA== -xterm-addon-serialize@0.9.0-beta.1: - version "0.9.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.9.0-beta.1.tgz#44a8047ec85abe4db232acc58c53355dd314bf6d" - integrity sha512-jVkpU5GC728ko0k190o+M1xubMkhRolKj18160rxlZhd0Sm/1yHUtFneC9pYSsLypynd3Te5LnZnHfEgVmka4g== +xterm-addon-serialize@0.9.0-beta.2: + version "0.9.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.9.0-beta.2.tgz#2f37ba57cabcdbf6dfe56bce8209de04dcfaa8ef" + integrity sha512-oCRHXdlrlzcNmxRxHJlYq6FiJlgQDXft62DcE+WY7Y7R5rjPB8ahrSQHBwjc3ZIK0GRL8fRReuwxL1+Jy4Dt4Q== xterm-addon-unicode11@0.5.0-beta.1: version "0.5.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.2: - version "0.14.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.2.tgz#832c31b52b78fb67a65bbd23c9fb850caceb43ae" - integrity sha512-1ccbkJiUZ5ojnoAEJsbdV0jMZaYSnZ02wfV8yBU243u6TTgvCzZ7nq5BR9bT+5K/ESFWiekobfybxHwuYnylmQ== +xterm-addon-webgl@0.14.0-beta.8: + version "0.14.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" + integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.1: - version "5.1.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.1.tgz#badec2e97e47aa44267a4de2c1b42b4d23ad49a2" - integrity sha512-V3G7l4pN6/HW//vKXryOCdDXVKdrQTQmtHEqkZ8waD68cJdeMdIoGYJuzavd5rHpxCqm/KR5O8ztI41jridong== +xterm-headless@5.1.0-beta.10: + version "5.1.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.10.tgz#2a747a1fa96a877c26aea3311b0a62ddae7e2578" + integrity sha512-tRoXL1e87XOIuZ5yIjK43q3x9/MqZ+K24Na7UTl+AqmkXjb5svXfShMV3x8HiNAyxcrnL/MXNilfLoniQGacIA== -xterm@5.1.0-beta.1: - version "5.1.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.1.tgz#a6617c6887066d166632d1e69b6eb83a179d8b63" - integrity sha512-ml7bqjO23bh4yu7qXKogXtCy4SbDTV21rfDXUvLPPaxrlQus6NoN1byy1eFH4ONWpv5ZHGeItRdQ/X00et9Pcw== +xterm@5.1.0-beta.10: + version "5.1.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" + integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index 99c9297fccf..d85a254fc80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11638,30 +11638,30 @@ xterm-addon-search@0.11.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.1.tgz#fe7178d70246cde73550447c5524672575467499" integrity sha512-fKj8KnnhH1nC4oZpKsgnhtgxkTctoa9kGLMpTJjsNzFu0VvXvLGIRezTPI75UEIQdEdaxcwB7/aKelQTO+72LA== -xterm-addon-serialize@0.9.0-beta.1: - version "0.9.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.9.0-beta.1.tgz#44a8047ec85abe4db232acc58c53355dd314bf6d" - integrity sha512-jVkpU5GC728ko0k190o+M1xubMkhRolKj18160rxlZhd0Sm/1yHUtFneC9pYSsLypynd3Te5LnZnHfEgVmka4g== +xterm-addon-serialize@0.9.0-beta.2: + version "0.9.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.9.0-beta.2.tgz#2f37ba57cabcdbf6dfe56bce8209de04dcfaa8ef" + integrity sha512-oCRHXdlrlzcNmxRxHJlYq6FiJlgQDXft62DcE+WY7Y7R5rjPB8ahrSQHBwjc3ZIK0GRL8fRReuwxL1+Jy4Dt4Q== xterm-addon-unicode11@0.5.0-beta.1: version "0.5.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.2: - version "0.14.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.2.tgz#832c31b52b78fb67a65bbd23c9fb850caceb43ae" - integrity sha512-1ccbkJiUZ5ojnoAEJsbdV0jMZaYSnZ02wfV8yBU243u6TTgvCzZ7nq5BR9bT+5K/ESFWiekobfybxHwuYnylmQ== +xterm-addon-webgl@0.14.0-beta.8: + version "0.14.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" + integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.1: - version "5.1.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.1.tgz#badec2e97e47aa44267a4de2c1b42b4d23ad49a2" - integrity sha512-V3G7l4pN6/HW//vKXryOCdDXVKdrQTQmtHEqkZ8waD68cJdeMdIoGYJuzavd5rHpxCqm/KR5O8ztI41jridong== +xterm-headless@5.1.0-beta.10: + version "5.1.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.10.tgz#2a747a1fa96a877c26aea3311b0a62ddae7e2578" + integrity sha512-tRoXL1e87XOIuZ5yIjK43q3x9/MqZ+K24Na7UTl+AqmkXjb5svXfShMV3x8HiNAyxcrnL/MXNilfLoniQGacIA== -xterm@5.1.0-beta.1: - version "5.1.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.1.tgz#a6617c6887066d166632d1e69b6eb83a179d8b63" - integrity sha512-ml7bqjO23bh4yu7qXKogXtCy4SbDTV21rfDXUvLPPaxrlQus6NoN1byy1eFH4ONWpv5ZHGeItRdQ/X00et9Pcw== +xterm@5.1.0-beta.10: + version "5.1.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" + integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== y18n@^3.2.1: version "3.2.2" From afdf3fd60b120c2d77e8edba68a207be64c3c478 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 26 Sep 2022 16:16:10 +0200 Subject: [PATCH 056/599] [folding] skip line number change test when restoring state #159032 (#161768) --- src/vs/editor/contrib/folding/browser/folding.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 8ed4b79072b..4f1e00e9223 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -197,7 +197,7 @@ export class FoldingController extends Disposable implements IEditorContribution if (!model || !this._isEnabled || model.isTooLargeForTokenization() || !this.hiddenRangeModel) { return; } - if (!state || state.lineCount !== model.getLineCount()) { + if (!state) { return; } From d1479b595c2ad0d8b7d7ad836ca29cd5113effb0 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 07:24:11 -0700 Subject: [PATCH 057/599] iterate through all providers before returning (#161649) --- .../browser/terminalBaseContextualActions.ts | 6 +-- .../browser/xterm/contextualActionAddon.ts | 33 +++++++------ .../browser/contextualActionAddon.test.ts | 47 +++++++++++++++++-- 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts index 8e2344fe159..153626e44de 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts @@ -14,9 +14,9 @@ export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.{4,}/; export const GitSimilarOutputRegex = /most similar command is\s+([^\s]{3,})/; -export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)\s+|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; -export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)\s+/; -export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s+remote:\s+(https:.+pull.+)\s+/; +export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; +export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; +export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s+remote:\s+(https:.+pull.+)/; export function gitSimilarCommand(): ITerminalContextualActionOptions { return { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts index f8d407b4fc2..abc6b021419 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts @@ -152,23 +152,22 @@ export function getMatchActions(command: ITerminalCommand, actionOptions: Map { - await a.run(); - if (a.commandToRunInTerminal) { - onDidRequestRerunCommand?.fire({ command: a.commandToRunInTerminal, addNewLine: a.addNewLine }); - } - }, - tooltip: a.tooltip - }); + if (actions) { + for (const a of actions) { + matchActions.push({ + id: a.id, + label: a.label, + class: a.class, + enabled: a.enabled, + run: async () => { + await a.run(); + if (a.commandToRunInTerminal) { + onDidRequestRerunCommand?.fire({ command: a.commandToRunInTerminal, addNewLine: a.addNewLine }); + } + }, + tooltip: a.tooltip + }); + } } } } diff --git a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts index d317f678d19..686b0e053cd 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts @@ -117,7 +117,7 @@ suite('ContextualActionAddon', () => { strictEqual(getMatchActions(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); }); }); - test.skip('returns actions', () => { + test('returns actions', () => { assertMatchOptions(getMatchActions(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); }); }); @@ -127,7 +127,7 @@ suite('ContextualActionAddon', () => { const output = `fatal: The current branch test22 has no upstream branch. To push the current branch and set the remote as upstream, use - git push --set-upstream origin test22 `; + git push --set-upstream origin test22`; const exitCode = 128; const actions = [ { @@ -151,7 +151,7 @@ suite('ContextualActionAddon', () => { strictEqual(getMatchActions(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); }); }); - suite('returns undefined when', () => { + suite('returns actions when', () => { test('expected unix exit code', () => { assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); }); @@ -204,6 +204,47 @@ suite('ContextualActionAddon', () => { }); }); }); + suite('gitPush - multiple providers', () => { + const expectedMap = new Map(); + const command = `git push`; + const output = `fatal: The current branch test22 has no upstream branch. + To push the current branch and set the remote as upstream, use + + git push --set-upstream origin test22`; + const exitCode = 128; + const actions = [ + { + id: 'terminal.gitPush', + label: 'Git push test22', + run: true, + tooltip: 'Git push test22', + enabled: true + } + ]; + setup(() => { + const pushCommand = gitPushSetUpstream(); + const prCommand = gitCreatePr(openerService); + contextualActionAddon.registerCommandFinishedListener(pushCommand); + contextualActionAddon.registerCommandFinishedListener(prCommand); + expectedMap.set(pushCommand.commandLineMatcher.toString(), [pushCommand, prCommand]); + }); + suite('returns undefined when', () => { + test('output does not match', () => { + strictEqual(getMatchActions(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); + }); + test('command does not match', () => { + strictEqual(getMatchActions(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); + }); + }); + suite('returns actions when', () => { + test('expected unix exit code', () => { + assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); + }); + test('matching exit status', () => { + assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); + }); + }); + }); }); function createCommand(command: string, output: string, outputMatcher?: RegExp | string, exitCode?: number): ITerminalCommand { From 38939c5eaa74937c706b41719b2c01dc284326e2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 07:28:25 -0700 Subject: [PATCH 058/599] Enforce all properties on output matchers This enforces output matchers will always have an anchor, offset and length as otherwise the matcher will search every line which could be thousands of lines. This also runs the free port issue only on a failed command, we can amend the xterm.js script to exit with error if needed to support this as it should do that anyway. Fixes #161758 --- .../contrib/terminal/browser/terminal.ts | 22 ++++++++++++-- .../browser/terminalBaseContextualActions.ts | 30 ++++++++++++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 0b2bda0942d..984098cd483 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -935,11 +935,27 @@ export interface ICommandAction extends IAction { addNewLine?: boolean; } +/** + * A matcher that runs on a sub-section of a terminal command's output + */ export interface ITerminalOutputMatcher { + /** + * A string or regex to match against the unwrapped line. + */ lineMatcher: string | RegExp; - anchor?: 'top' | 'bottom'; - offset?: number; - length?: number; + /** + * Which side of the output to anchor the {@link offset} and {@link length} against. + */ + anchor: 'top' | 'bottom'; + /** + * How far from either the top or the bottom of the butter to start matching against. + */ + offset: number; + /** + * The number of rows to match against, this should be as small as possible for performance + * reasons. + */ + length: number; } export interface IXtermTerminal { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts index 8e2344fe159..f45541d0346 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts @@ -21,7 +21,12 @@ export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on export function gitSimilarCommand(): ITerminalContextualActionOptions { return { commandLineMatcher: GitCommandLineRegex, - outputMatcher: { lineMatcher: GitSimilarOutputRegex, anchor: 'bottom' }, + outputMatcher: { + lineMatcher: GitSimilarOutputRegex, + anchor: 'bottom', + offset: 0, + length: 3 + }, actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Run git ${matchResult.outputMatch[1]}` : ``, exitStatus: false, getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { @@ -45,7 +50,14 @@ export function freePort(terminalInstance?: Partial): ITermin return { actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '', commandLineMatcher: AnyCommandLineRegex, - outputMatcher: !isWindows ? { lineMatcher: FreePortOutputRegex, anchor: 'bottom' } : undefined, + // TODO: Support free port on Windows https://github.com/microsoft/vscode/issues/161775 + outputMatcher: isWindows ? undefined : { + lineMatcher: FreePortOutputRegex, + anchor: 'bottom', + offset: 0, + length: 20 + }, + exitStatus: false, getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { const port = matchResult?.outputMatch?.[1]; if (!port) { @@ -69,7 +81,12 @@ export function gitPushSetUpstream(): ITerminalContextualActionOptions { return { actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Git push ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, - outputMatcher: { lineMatcher: GitPushOutputRegex, anchor: 'bottom' }, + outputMatcher: { + lineMatcher: GitPushOutputRegex, + anchor: 'bottom', + offset: 0, + length: 5 + }, exitStatus: false, getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { const branch = matchResult?.outputMatch?.[1]; @@ -94,7 +111,12 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalContextualA return { actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Create PR for ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, - outputMatcher: { lineMatcher: GitCreatePrOutputRegex, anchor: 'bottom' }, + outputMatcher: { + lineMatcher: GitCreatePrOutputRegex, + anchor: 'bottom', + offset: 0, + length: 5 + }, exitStatus: true, getActions: (matchResult: ContextualMatchResult, command?: ITerminalCommand) => { if (!command) { From ae8cf2186e8893b251085ceaab19d427c8ae88a0 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 26 Sep 2022 16:31:08 +0200 Subject: [PATCH 059/599] The properties language uses a Java icon in the Seti theme (#161770) The properties language uses a Java icon in the Seti theme. Fixes #158453 --- extensions/theme-seti/build/update-icon-theme.js | 8 ++++++-- extensions/theme-seti/icons/vs-seti-icon-theme.json | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index c55af7ab7fe..ab2a1c81e81 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -47,7 +47,11 @@ const inheritIconFromLanguage = { "postcss": 'css', "django-html": 'html', "blade": 'php' -} +}; + +const ignoreExtAssociation = { + "properties": true +}; const FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo @@ -399,7 +403,7 @@ exports.update = function () { if (!nonBuiltInLanguages[lang] && !inheritIconFromLanguage[lang]) { for (let i2 = 0; i2 < exts.length; i2++) { // remove the extension association, unless it is different from the preferred - if (ext2Def[exts[i2]] === preferredDef) { + if (ext2Def[exts[i2]] === preferredDef || ignoreExtAssociation[exts[i2]]) { delete ext2Def[exts[i2]]; } } diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index b1044baf1cb..f5b78299680 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -1622,7 +1622,6 @@ "jade": "_jade", "class": "_java_1", "classpath": "_java", - "properties": "_java", "js.map": "_javascript", "spec.js": "_javascript_1", "test.js": "_javascript_1", @@ -2025,7 +2024,6 @@ "jade": "_jade_light", "class": "_java_1_light", "classpath": "_java_light", - "properties": "_java_light", "js.map": "_javascript_light", "spec.js": "_javascript_1_light", "test.js": "_javascript_1_light", From fe4cf3da0cf34d1c25324289158264c416924196 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 16:34:46 +0200 Subject: [PATCH 060/599] fix context (#161772) --- .../workbench/contrib/userDataSync/browser/userDataSyncViews.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts index 1e10f688e2f..6ba7ca6f86d 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts @@ -345,7 +345,7 @@ abstract class UserDataSyncActivityViewDataProvider implements ITreeViewDataProv description: fromNow(syncResourceHandle.created, true), themeIcon: FolderThemeIcon, syncResourceHandle, - contextValue: `sync-resource-${syncResourceHandle.syncResource}` + contextValue: `sync-resource-${syncResourceHandle.syncResource.syncResource}` }; }); } From 8985f5f61acd4eb96666acc8f9fda04bc0c8634a Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 26 Sep 2022 16:43:26 +0200 Subject: [PATCH 061/599] Fix initial size doc (#161774) --- src/vs/workbench/api/browser/viewsExtensionPoint.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 62e6a51a57c..92b4f91954d 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -162,9 +162,9 @@ const viewDescriptor: IJSONSchema = { localize('vscode.extension.contributes.view.initialState.collapsed', "The view will show in the view container, but will be collapsed.") ] }, - size: { + initialSize: { type: 'number', - description: localize('vscode.extension.contributs.view.size', "The size of the view. Using a number will behave like the css 'flex' property, and the size will set the initial size when the view is first shown. In the side bar, this is the height of the view."), + description: localize('vscode.extension.contributs.view.size', "The initial size of the view. The size will behave like the css 'flex' property, and will set the initial size when the view is first shown. In the side bar, this is the height of the view. This value is only respected when the same extension owns both the view and the view container."), } } }; From 816cd663e748fb78348bd09569345887e77704b4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 07:48:40 -0700 Subject: [PATCH 062/599] Include applicationName in zsh shell integration folder name Fixes #159182 --- src/vs/platform/terminal/node/ptyHostMain.ts | 2 +- src/vs/platform/terminal/node/ptyService.ts | 4 +- .../terminal/node/terminalEnvironment.ts | 7 +- .../platform/terminal/node/terminalProcess.ts | 27 +------ .../test/node/terminalEnvironment.test.ts | 76 ++++++++++--------- 5 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts index 3de63e7d9e6..a1fa938db10 100644 --- a/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -44,7 +44,7 @@ delete process.env.VSCODE_RECONNECT_GRACE_TIME; delete process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME; delete process.env.VSCODE_RECONNECT_SCROLLBACK; -const ptyService = new PtyService(lastPtyId, logService, reconnectConstants); +const ptyService = new PtyService(lastPtyId, logService, productService, reconnectConstants); server.registerChannel(TerminalIpcChannels.PtyHost, ProxyChannel.fromService(ptyService)); process.once('exit', () => { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 282bf02ff66..4b23e3c42b7 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -28,6 +28,7 @@ import { ErrorNoTelemetry } from 'vs/base/common/errors'; import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon'; import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings'; import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { IProductService } from 'vs/platform/product/common/productService'; type WorkspaceId = string; @@ -64,6 +65,7 @@ export class PtyService extends Disposable implements IPtyService { constructor( private _lastPtyId: number, private readonly _logService: ILogService, + private readonly _productService: IProductService, private readonly _reconnectConstants: IReconnectConstants ) { super(); @@ -244,7 +246,7 @@ export class PtyService extends Disposable implements IPtyService { throw new Error('Attempt to create a process when attach object was provided'); } const id = ++this._lastPtyId; - const process = new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, options, this._logService); + const process = new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, options, this._logService, this._productService); process.onProcessData(event => this._onProcessData.fire({ id, event })); const processLaunchOptions: IPersistentTerminalProcessLaunchConfig = { env, diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index 4663e733489..48165362275 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -13,6 +13,7 @@ import { format } from 'vs/base/common/strings'; import { isString } from 'vs/base/common/types'; import * as pfs from 'vs/base/node/pfs'; import { ILogService } from 'vs/platform/log/common/log'; +import { IProductService } from 'vs/platform/product/common/productService'; import { IShellLaunchConfig, ITerminalEnvironment, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; export function getWindowsBuildNumber(): number { @@ -105,7 +106,8 @@ export function getShellIntegrationInjection( shellLaunchConfig: IShellLaunchConfig, options: ITerminalProcessOptions['shellIntegration'], env: ITerminalEnvironment | undefined, - logService: ILogService + logService: ILogService, + productService: IProductService ): IShellIntegrationConfigInjection | undefined { // Shell integration arg injection is disabled when: // - The global setting is disabled @@ -184,8 +186,9 @@ export function getShellIntegrationInjection( } newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot); + // Move .zshrc into $ZDOTDIR as the way to activate the script - const zdotdir = path.join(os.tmpdir(), `${os.userInfo().username}-vscode-zsh`); + const zdotdir = path.join(os.tmpdir(), `${os.userInfo().username}-${productService.applicationName}-zsh`); envMixin['ZDOTDIR'] = zdotdir; const userZdotdir = env?.ZDOTDIR ?? os.homedir() ?? `~`; // NOTE: When vscode is started from the integrated terminal, the environment variables are taken over. diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 366d57b4d5f..253b8dc7192 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -6,17 +6,16 @@ import { exec } from 'child_process'; import { promises as fs } from 'fs'; import type * as pty from 'node-pty'; -import { tmpdir } from 'os'; import { timeout } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { FileAccess } from 'vs/base/common/network'; import * as path from 'vs/base/common/path'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { Promises } from 'vs/base/node/pfs'; import { localize } from 'vs/nls'; import { ILogService } from 'vs/platform/log/common/log'; +import { IProductService } from 'vs/platform/product/common/productService'; import { FlowControlConstants, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap as IProcessPropertyMap, ProcessPropertyType, TerminalShellType, IProcessReadyEvent, ITerminalProcessOptions, PosixShellType } from 'vs/platform/terminal/common/terminal'; import { ChildProcessMonitor } from 'vs/platform/terminal/node/childProcessMonitor'; import { findExecutable, getShellIntegrationInjection, getWindowsBuildNumber, IShellIntegrationConfigInjection } from 'vs/platform/terminal/node/terminalEnvironment'; @@ -145,7 +144,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess */ private readonly _executableEnv: IProcessEnvironment, private readonly _options: ITerminalProcessOptions, - @ILogService private readonly _logService: ILogService + @ILogService private readonly _logService: ILogService, + @IProductService private readonly _productService: IProductService ) { super(); let name: string; @@ -201,7 +201,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess let injection: IShellIntegrationConfigInjection | undefined; if (this._options.shellIntegration.enabled) { - injection = getShellIntegrationInjection(this.shellLaunchConfig, this._options.shellIntegration, this._ptyOptions.env, this._logService); + injection = getShellIntegrationInjection(this.shellLaunchConfig, this._options.shellIntegration, this._ptyOptions.env, this._logService, this._productService); if (injection) { this._onDidChangeProperty.fire({ type: ProcessPropertyType.UsedShellIntegrationInjection, value: true }); if (injection.envMixin) { @@ -228,25 +228,6 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - // Handle zsh shell integration - Set $ZDOTDIR to a temp dir and create $ZDOTDIR/.zshrc - if (this.shellLaunchConfig.env?.['_ZDOTDIR'] === '1') { - const zdotdir = path.join(tmpdir(), 'vscode-zsh'); - await fs.mkdir(zdotdir, { recursive: true }); - const source = path.join(path.dirname(FileAccess.asFileUri('', require).fsPath), 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh'); - // TODO: Does filesToCopy make this unnecessary now? - try { - await fs.copyFile(source, path.join(zdotdir, '.zshrc')); - } catch { - // Swallow error, this should only happen when multiple users are on the same - // machine. Since the shell integration scripts rarely change, plus the other user - // should be using the same version of the server in this case, assume the script is - // fine if copy fails and swallow the error. - } - this._ptyOptions.env = this._ptyOptions.env || {}; - this._ptyOptions.env['ZDOTDIR'] = zdotdir; - delete this._ptyOptions.env['_ZDOTDIR']; - } - try { await this.setupPtyProcess(this.shellLaunchConfig, this._ptyOptions, injection); return undefined; diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index 742de1a9de6..873aaaf8a41 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -6,6 +6,7 @@ import { deepStrictEqual, ok, strictEqual } from 'assert'; import { homedir, userInfo } from 'os'; import { NullLogService } from 'vs/platform/log/common/log'; +import { IProductService } from 'vs/platform/product/common/productService'; import { ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; import { getShellIntegrationInjection, IShellIntegrationConfigInjection } from 'vs/platform/terminal/node/terminalEnvironment'; @@ -14,14 +15,15 @@ const disabledProcessOptions: ITerminalProcessOptions['shellIntegration'] = { en const pwshExe = process.platform === 'win32' ? 'pwsh.exe' : 'pwsh'; const repoRoot = process.platform === 'win32' ? process.cwd()[0].toLowerCase() + process.cwd().substring(1) : process.cwd(); const logService = new NullLogService(); +const productService = { applicationName: 'vscode' } as IProductService; const defaultEnvironment = {}; suite('platform - terminalEnvironment', () => { suite('getShellIntegrationInjection', () => { suite('should not enable', () => { test('when isFeatureTerminal or when no executable is provided', () => { - ok(!getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, enabledProcessOptions, defaultEnvironment, logService)); - ok(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: false }, enabledProcessOptions, defaultEnvironment, logService)); + ok(!getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, enabledProcessOptions, defaultEnvironment, logService, productService)); + ok(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: false }, enabledProcessOptions, defaultEnvironment, logService, productService)); }); }); @@ -41,21 +43,21 @@ suite('platform - terminalEnvironment', () => { } }); test('when undefined, []', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: [] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: undefined }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: [] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: undefined }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); suite('when no logo', () => { test('array - case insensitive', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NoLogo'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NOLOGO'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-nol'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NOL'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NoLogo'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NOLOGO'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-nol'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-NOL'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); test('string - case insensitive', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NoLogo' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NOLOGO' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-nol' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NOL' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NoLogo' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NOLOGO' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-nol' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-NOL' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); }); }); @@ -72,23 +74,23 @@ suite('platform - terminalEnvironment', () => { } }); test('when array contains no logo and login', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); test('when string', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-l' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-l' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); }); suite('should not modify args', () => { test('when shell integration is disabled', () => { - strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); - strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-l' }, disabledProcessOptions, defaultEnvironment, logService), undefined); - strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: undefined }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); + strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-l' }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); + strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: undefined }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); test('when using unrecognized arg', () => { - strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo', '-i'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo', '-i'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); test('when using unrecognized arg (string)', () => { - strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-i' }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: pwshExe, args: '-i' }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); }); }); @@ -128,54 +130,54 @@ suite('platform - terminalEnvironment', () => { ok(result.filesToCopy[3].source.match(expectedSources[3])); } test('when undefined, []', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, defaultEnvironment, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, defaultEnvironment, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1); - const result2 = getShellIntegrationInjection({ executable: 'zsh', args: undefined }, enabledProcessOptions, defaultEnvironment, logService); + const result2 = getShellIntegrationInjection({ executable: 'zsh', args: undefined }, enabledProcessOptions, defaultEnvironment, logService, productService); deepStrictEqual(result2?.newArgs, ['-i']); assertIsEnabled(result2); }); suite('should incorporate login arg', () => { test('when array', () => { - const result = getShellIntegrationInjection({ executable: 'zsh', args: ['-l'] }, enabledProcessOptions, defaultEnvironment, logService); + const result = getShellIntegrationInjection({ executable: 'zsh', args: ['-l'] }, enabledProcessOptions, defaultEnvironment, logService, productService); deepStrictEqual(result?.newArgs, ['-il']); assertIsEnabled(result); }); }); suite('should not modify args', () => { test('when shell integration is disabled', () => { - strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); - strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: undefined }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: undefined }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); test('when using unrecognized arg', () => { - strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: ['-l', '-fake'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'zsh', args: ['-l', '-fake'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); }); suite('should incorporate global ZDOTDIR env variable', () => { test('when custom ZDOTDIR', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1, customZdotdir); }); test('when undefined', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1); }); }); suite('should incorporate global USER_ZDOTDIR env variable', () => { test('when custom ZDOTDIR and USER_ZDOTDIR is undefined', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1, customZdotdir); }); test('when custom ZDOTDIR and USER_ZDOTDIR', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir, USER_ZDOTDIR: customUserZdotdir }, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir, USER_ZDOTDIR: customUserZdotdir }, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1, customUserZdotdir); }); test('when undefined', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService); + const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService, productService); deepStrictEqual(result1?.newArgs, ['-i']); assertIsEnabled(result1, homedir()); }); @@ -194,9 +196,9 @@ suite('platform - terminalEnvironment', () => { VSCODE_INJECTION: '1' } }); - deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: [] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: '' }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); - deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: undefined }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: [] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: '' }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: undefined }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); suite('should set login env variable and not modify args', () => { const enabledExpectedResult = Object.freeze({ @@ -210,16 +212,16 @@ suite('platform - terminalEnvironment', () => { } }); test('when array', () => { - deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l'] }, enabledProcessOptions, defaultEnvironment, logService), enabledExpectedResult); + deepStrictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l'] }, enabledProcessOptions, defaultEnvironment, logService, productService), enabledExpectedResult); }); }); suite('should not modify args', () => { test('when shell integration is disabled', () => { - strictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); - strictEqual(getShellIntegrationInjection({ executable: 'bash', args: undefined }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'bash', args: undefined }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); test('when custom array entry', () => { - strictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l', '-i'] }, disabledProcessOptions, defaultEnvironment, logService), undefined); + strictEqual(getShellIntegrationInjection({ executable: 'bash', args: ['-l', '-i'] }, disabledProcessOptions, defaultEnvironment, logService, productService), undefined); }); }); }); From 2f1126ca78d126e95eb96acfac2ee5965bb0d3cf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 26 Sep 2022 16:49:26 +0200 Subject: [PATCH 063/599] tweak command center rendering (#161773) --- .../parts/titlebar/commandCenterControl.ts | 1 + .../parts/titlebar/media/titlebarpart.css | 30 ++++++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts index 8986a0879ac..b281f030a55 100644 --- a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts @@ -72,6 +72,7 @@ export class CommandCenterControl { // label: just workspace name and optional decorations const label = this._getLabel(); const labelElement = document.createElement('span'); + labelElement.classList.add('search-label'); labelElement.innerText = label; reset(left, searchIcon, labelElement); diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 654b1fc7eb7..47f2e8a396a 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -100,21 +100,6 @@ display: none; } -.monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.quickopen { - display: flex; - color: var(--vscode-commandCenter-foreground); - background-color: var(--vscode-commandCenter-background); - border: 1px solid var(--vscode-commandCenter-border); - flex-direction: row; - justify-content: center; - overflow: hidden; -} - -.monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.quickopen:HOVER { - color: var(--vscode-commandCenter-activeForeground); - background-color: var(--vscode-commandCenter-activeBackground); -} - .monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.command-center { display: flex; align-items: stretch; @@ -127,16 +112,19 @@ border-bottom-left-radius: 6px; border-top-right-radius: 6px; border-bottom-right-radius: 6px; + + + width: 38vw; + max-width: 600px; } .monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.command-center .left { display: inline-flex; justify-content: center; - - /* width */ - width: 38vw; - max-width: 600px; - min-width: 32px; + width: 100%; + margin: auto; + overflow: hidden; + text-overflow: ellipsis; } .monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.command-center .left .search-icon { @@ -152,7 +140,7 @@ .monaco-workbench .part.titlebar>.titlebar-container>.window-title>.command-center .action-item.command-center .right { margin-left: auto; - padding: 2px 3px 0 0; + padding: 2px 2px 0 0; width: 16px; flex-shrink: 0; } From 01c22d9977c0dd9f0bb8dbd361ff2b7d6d04232c Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 26 Sep 2022 10:51:18 -0400 Subject: [PATCH 064/599] Move Edit Sessions commands and settings out of `experimental` namespace (#161739) Move edit sessions commands and settings out of `experimental` namespace --- .../api/common/extHostApiCommands.ts | 2 +- .../browser/editSessions.contribution.ts | 71 ++++++++++--------- .../browser/editSessionsStorageService.ts | 2 +- .../editSessions/browser/editSessionsViews.ts | 4 +- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 8f3c18a769f..db6bdefe028 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -439,7 +439,7 @@ const newCommands: ApiCommand[] = [ ), // --- continue edit session new ApiCommand( - 'vscode.experimental.editSession.continue', '_workbench.experimental.editSessions.actions.continueEditSession', 'Continue the current edit session in a different workspace', + 'vscode.experimental.editSession.continue', '_workbench.editSessions.actions.continueEditSession', 'Continue the current edit session in a different workspace', [ApiCommandArgument.Uri.with('workspaceUri', 'The target workspace to continue the current edit session in')], ApiCommandResult.Void ) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 73008f88f9c..013743d904a 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -59,19 +59,19 @@ registerSingleton(IEditSessionsLogService, EditSessionsLogService, false); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false); const continueWorkingOnCommand: IAction2Options = { - id: '_workbench.experimental.editSessions.actions.continueEditSession', + id: '_workbench.editSessions.actions.continueEditSession', title: { value: localize('continue working on', "Continue Working On..."), original: 'Continue Working On...' }, precondition: WorkspaceFolderCountContext.notEqualsTo('0'), f1: true }; const openLocalFolderCommand: IAction2Options = { - id: '_workbench.experimental.editSessions.actions.continueEditSession.openLocalFolder', + id: '_workbench.editSessions.actions.continueEditSession.openLocalFolder', title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' }, category: EDIT_SESSION_SYNC_CATEGORY, precondition: IsWebContext }; const showOutputChannelCommand: IAction2Options = { - id: 'workbench.experimental.editSessions.actions.showOutputChannel', + id: 'workbench.editSessions.actions.showOutputChannel', title: { value: localize('show log', 'Show Log'), original: 'Show Log' }, category: EDIT_SESSION_SYNC_CATEGORY }; @@ -81,12 +81,10 @@ const resumingProgressOptions = { title: `[${localize('resuming edit session window', 'Resuming edit session...')}](command:${showOutputChannelCommand.id})` }; const queryParamName = 'editSessionId'; -const experimentalSettingName = 'workbench.experimental.editSessions.enabled'; -const useEditSessionsWithContinueOn = 'workbench.experimental.editSessions.continueOn'; +const useEditSessionsWithContinueOn = 'workbench.editSessions.continueOn'; export class EditSessionsContribution extends Disposable implements IWorkbenchContribution { - private registered = false; private continueEditSessionOptions: ContinueEditSessionItem[] = []; private readonly shouldShowViewsContext: IContextKey; @@ -117,12 +115,6 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.autoResumeEditSession(); - this.configurationService.onDidChangeConfiguration((e) => { - if (e.affectsConfiguration(experimentalSettingName)) { - this.registerActions(); - } - }); - this.registerActions(); this.registerViews(); this.registerContributedEditSessionOptions(); @@ -146,8 +138,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo if (this.environmentService.editSessionId !== undefined) { await this.resumeEditSession(this.environmentService.editSessionId).finally(() => this.environmentService.editSessionId = undefined); } else if ( - this.configurationService.getValue('workbench.experimental.editSessions.enabled') === true && - this.configurationService.getValue('workbench.experimental.editSessions.autoResume') === 'onReload' && + this.configurationService.getValue('workbench.editSessions.autoResume') === 'onReload' && this.editSessionsStorageService.isSignedIn ) { // Attempt to resume edit session based on edit workspace identifier @@ -187,11 +178,6 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } private registerActions() { - if (this.registered || this.configurationService.getValue(experimentalSettingName) !== true) { - this.logService.info(`Skipping registering edit sessions actions as edit sessions are currently disabled. Set ${experimentalSettingName} to enable edit sessions.`); - return; - } - this.registerContinueEditSessionAction(); this.registerResumeLatestEditSessionAction(); @@ -201,8 +187,6 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerShowEditSessionViewAction(); this.registerShowEditSessionOutputChannelAction(); - - this.registered = true; } private registerShowEditSessionOutputChannelAction() { @@ -290,7 +274,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this._register(registerAction2(class ResumeLatestEditSessionAction extends Action2 { constructor() { super({ - id: 'workbench.experimental.editSessions.actions.resumeLatest', + id: 'workbench.editSessions.actions.resumeLatest', title: { value: localize('resume latest.v2', "Resume Latest Edit Session"), original: 'Resume Latest Edit Session' }, category: EDIT_SESSION_SYNC_CATEGORY, f1: true, @@ -316,7 +300,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this._register(registerAction2(class StoreLatestEditSessionAction extends Action2 { constructor() { super({ - id: 'workbench.experimental.editSessions.actions.storeCurrent', + id: 'workbench.editSessions.actions.storeCurrent', title: { value: localize('store current.v2', "Store Current Edit Session"), original: 'Store Current Edit Session' }, category: EDIT_SESSION_SYNC_CATEGORY, f1: true, @@ -781,23 +765,28 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'default': 'off', 'markdownDescription': localize('autoStore', "Controls whether to automatically store an available edit session for the current workspace."), }, - 'workbench.experimental.editSessions.enabled': { - 'type': 'boolean', - 'tags': ['experimental', 'usesOnlineServices'], - 'default': true, - 'markdownDescription': localize('editSessionsEnabled', "Controls whether to display cloud-enabled actions to store and resume uncommitted changes when switching between web, desktop, or devices."), - }, - 'workbench.experimental.editSessions.autoResume': { + 'workbench.editSessions.autoResume': { enum: ['onReload', 'off'], enumDescriptions: [ localize('autoResume.onReload', "Automatically resume available edit session on window reload."), localize('autoResume.off', "Never attempt to resume an edit session.") ], 'type': 'string', - 'tags': ['experimental', 'usesOnlineServices'], + 'tags': ['usesOnlineServices'], 'default': 'onReload', 'markdownDescription': localize('autoResume', "Controls whether to automatically resume an available edit session for the current workspace."), }, + 'workbench.editSessions.continueOn': { + enum: ['prompt', 'off'], + enumDescriptions: [ + localize('continueOn.promptForAuth', 'Prompt the user to sign in to store edit sessions with Continue Working On.'), + localize('continueOn.off', 'Do not use edit sessions with Continue Working On unless the user has already turned on edit sessions.') + ], + type: 'string', + tags: ['usesOnlineServices'], + default: 'prompt', + markdownDescription: localize('continueOn', 'Controls whether to prompt the user to store edit sessions when using Continue Working On.') + }, 'workbench.experimental.editSessions.continueOn': { enum: ['prompt', 'off'], enumDescriptions: [ @@ -807,7 +796,25 @@ Registry.as(ConfigurationExtensions.Configuration).regis type: 'string', tags: ['experimental', 'usesOnlineServices'], default: 'prompt', + markdownDeprecationMessage: localize('continueOnDeprecated', 'This setting is deprecated in favor of {0}.', '`#workbench.experimental.continueOn#`'), markdownDescription: localize('continueOn', 'Controls whether to prompt the user to store edit sessions when using Continue Working On.') - } + }, + 'workbench.experimental.editSessions.enabled': { + 'type': 'boolean', + 'tags': ['experimental', 'usesOnlineServices'], + 'default': true, + 'markdownDeprecationMessage': localize('editSessionsEnabledDeprecated', "This setting is deprecated as Edit Sessions are no longer experimental. Please see {0} and {1} for configuring behavior related to Edit Sessions.", '`#workbench.editSessions.autoResume#`', '`#workbench.editSessions.continueOn#`') + }, + 'workbench.experimental.editSessions.autoResume': { + enum: ['onReload', 'off'], + enumDescriptions: [ + localize('autoResume.onReload', "Automatically resume available edit session on window reload."), + localize('autoResume.off', "Never attempt to resume an edit session.") + ], + 'type': 'string', + 'tags': ['experimental', 'usesOnlineServices'], + 'default': 'onReload', + 'markdownDeprecationMessage': localize('autoResumeDeprecated', "This setting is deprecated in favor of {0}.", '`#workbench.editSessions.autoResume#`') + }, } }); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts index fdce08d7082..d995c8df6ca 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts @@ -293,7 +293,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes quickpick.onDidTriggerItemButton(async (e) => { if (e.button.tooltip === configureContinueOnPreference.tooltip) { - await this.commandService.executeCommand('workbench.action.openSettings', 'workbench.experimental.editSessions.continueOn'); + await this.commandService.executeCommand('workbench.action.openSettings', 'workbench.editSessions.continueOn'); } }); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index feba1d9df63..7a70b872e41 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts @@ -90,7 +90,7 @@ export class EditSessionsDataViews extends Disposable { async run(accessor: ServicesAccessor, handle: TreeViewItemHandleArg): Promise { const editSessionId = URI.parse(handle.$treeItemHandle).path.substring(1); const commandService = accessor.get(ICommandService); - await commandService.executeCommand('workbench.experimental.editSessions.actions.resumeLatest', editSessionId); + await commandService.executeCommand('workbench.editSessions.actions.resumeLatest', editSessionId); await treeView.refresh(); } }); @@ -106,7 +106,7 @@ export class EditSessionsDataViews extends Disposable { async run(accessor: ServicesAccessor, handle: TreeViewItemHandleArg): Promise { const commandService = accessor.get(ICommandService); - await commandService.executeCommand('workbench.experimental.editSessions.actions.storeCurrent'); + await commandService.executeCommand('workbench.editSessions.actions.storeCurrent'); await treeView.refresh(); } }); From 91b9c4cf3269a29e997fb6e0e780290d6f19b43f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 17:05:36 +0200 Subject: [PATCH 065/599] do not delete extensions not installed by VS Code (#161781) --- .../sharedProcess/contrib/extensionsCleaner.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index a49cc156f35..7da094c5965 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -96,7 +96,7 @@ class ProfileExtensionsCleaner extends Disposable { private async uninstallExtensionsNotInProfiles(): Promise { const installed = await this.extensionManagementService.getAllUserInstalled(); - const toUninstall = installed.filter(installedExtension => !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version))); + const toUninstall = installed.filter(installedExtension => installedExtension.installedTimestamp /* Installed by VS Code */ && !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version))); if (toUninstall.length) { await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); } @@ -169,7 +169,7 @@ class ProfileExtensionsCleaner extends Disposable { private async uninstallExtensions(extensionsToRemove: { identifier: IExtensionIdentifier; version: string }[]): Promise { const installed = await this.extensionManagementService.getAllUserInstalled(); - const toUninstall = installed.filter(installedExtension => extensionsToRemove.some(e => this.getKey(installedExtension.identifier, installedExtension.manifest.version) === this.getKey(e.identifier, e.version))); + const toUninstall = installed.filter(installedExtension => installedExtension.installedTimestamp /* Installed by VS Code */ && extensionsToRemove.some(e => this.getKey(installedExtension.identifier, installedExtension.manifest.version) === this.getKey(e.identifier, e.version))); if (toUninstall.length) { await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); } From 3d17ff38296d795c95c066759684fc31382e4ec6 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 08:12:57 -0700 Subject: [PATCH 066/599] for login shells, reset `zdotdir` to user's always (#161657) --- .../terminal/node/terminalEnvironment.ts | 5 +---- .../test/node/terminalEnvironment.test.ts | 18 ------------------ .../browser/media/shellIntegration-login.zsh | 8 ++++---- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index 4663e733489..d1884b8c3ab 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -188,10 +188,7 @@ export function getShellIntegrationInjection( const zdotdir = path.join(os.tmpdir(), `${os.userInfo().username}-vscode-zsh`); envMixin['ZDOTDIR'] = zdotdir; const userZdotdir = env?.ZDOTDIR ?? os.homedir() ?? `~`; - // NOTE: When vscode is started from the integrated terminal, the environment variables are taken over. - // The ZDOTDIR variable is oriented to os.tmpdir(), so we cannot reuse. - // Therefore, we use USER_ZDOTDIR variable that is inherited. - envMixin['USER_ZDOTDIR'] = env?.USER_ZDOTDIR ?? userZdotdir; + envMixin['USER_ZDOTDIR'] = userZdotdir; const filesToCopy: IShellIntegrationConfigInjection['filesToCopy'] = []; filesToCopy.push({ source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh'), diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index 742de1a9de6..2ce4d1864e9 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -99,7 +99,6 @@ suite('platform - terminalEnvironment', () => { const username = userInfo().username; const expectedDir = new RegExp(`.+\/${username}-vscode-zsh`); const customZdotdir = '/custom/zsh/dotdir'; - const customUserZdotdir = '/custom/zsh/user_dotdir'; const expectedDests = [ new RegExp(`.+\/${username}-vscode-zsh\/\.zshrc`), new RegExp(`.+\/${username}-vscode-zsh\/\.zprofile`), @@ -163,23 +162,6 @@ suite('platform - terminalEnvironment', () => { assertIsEnabled(result1); }); }); - suite('should incorporate global USER_ZDOTDIR env variable', () => { - test('when custom ZDOTDIR and USER_ZDOTDIR is undefined', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir }, logService); - deepStrictEqual(result1?.newArgs, ['-i']); - assertIsEnabled(result1, customZdotdir); - }); - test('when custom ZDOTDIR and USER_ZDOTDIR', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, { ...defaultEnvironment, ZDOTDIR: customZdotdir, USER_ZDOTDIR: customUserZdotdir }, logService); - deepStrictEqual(result1?.newArgs, ['-i']); - assertIsEnabled(result1, customUserZdotdir); - }); - test('when undefined', () => { - const result1 = getShellIntegrationInjection({ executable: 'zsh', args: [] }, enabledProcessOptions, undefined, logService); - deepStrictEqual(result1?.newArgs, ['-i']); - assertIsEnabled(result1, homedir()); - }); - }); }); }); suite('bash', () => { diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh index a0e118f7adb..128bd648616 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh @@ -2,8 +2,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # --------------------------------------------------------------------------------------------- -if [[ $options[norcs] = off && -o "login" && -f $USER_ZDOTDIR/.zlogin ]]; then - VSCODE_ZDOTDIR=$ZDOTDIR - ZDOTDIR=$USER_ZDOTDIR - . $USER_ZDOTDIR/.zlogin + +ZDOTDIR=$USER_ZDOTDIR +if [[ $options[norcs] = off && -o "login" && -f $ZDOTDIR/.zlogin ]]; then + . $ZDOTDIR/.zlogin fi From 1dd67592e120d916a8963903babaf0fae74440c5 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 26 Sep 2022 11:18:12 -0400 Subject: [PATCH 067/599] Ask for edit sessions auth when coming from Continue On (#160843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ask for edit sessions auth when coming from Continue On * Only append `continueOn` query param if there is an edit session * Persist continueOn for new windows * Don't double prompt to sign in * Add badge if user didn't sign in * Add logging and dev commands * Log more info * More logging * 🤔 * Cleanup * Actually check for pending edit sessions * More cleanup * Update test --- src/vs/code/electron-main/app.ts | 8 +++ src/vs/platform/environment/common/argv.ts | 1 + .../environment/common/environment.ts | 1 + .../environment/common/environmentService.ts | 8 +++ src/vs/platform/environment/node/argv.ts | 1 + .../windows/electron-main/windowImpl.ts | 1 + .../electron-main/windowsMainService.ts | 1 + .../browser/editSessions.contribution.ts | 51 +++++++++++++++++-- .../browser/editSessionsStorageService.ts | 9 ++++ .../editSessions/common/editSessions.ts | 2 + .../test/browser/editSessions.test.ts | 4 +- 11 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 2e57bc75e9f..ff67487cd1c 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -918,6 +918,14 @@ export class CodeApplication extends Disposable { // or if no window is open (macOS only) shouldOpenInNewWindow ||= isMacintosh && windowsMainService.getWindowCount() === 0; + // Pass along whether the application is being opened via a Continue On flow + const continueOn = params.get('continueOn'); + if (continueOn !== null) { + environmentService.continueOn = continueOn ?? undefined; + params.delete('continueOn'); + uri = uri.with({ query: params.toString() }); + } + // Check for URIs to open in window const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri); logService.trace('app#handleURL: windowOpenableFromProtocolLink = ', windowOpenableFromProtocolLink); diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index 73754ba6042..b72a87576f6 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -90,6 +90,7 @@ export interface NativeParsedArgs { 'logsPath'?: string; '__enable-file-policy'?: boolean; editSessionId?: string; + continueOn?: string; 'locate-shell-integration-path'?: string; 'profile'?: string; 'profile-temp'?: boolean; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index c740ddf77f6..38045ace24e 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -65,6 +65,7 @@ export interface IEnvironmentService { sync: 'on' | 'off' | undefined; // --- continue edit session + continueOn?: string; editSessionId?: string; editSessionsLogResource: URI; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index d90cbc60fef..82b280f08d3 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -247,6 +247,14 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron editSessionId: string | undefined = this.args['editSessionId']; + get continueOn(): string | undefined { + return this.args['continueOn']; + } + + set continueOn(value: string | undefined) { + this.args['continueOn'] = value; + } + get args(): NativeParsedArgs { return this._args; } constructor( diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index d5167a39273..15be1bcf6f6 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -129,6 +129,7 @@ export const OPTIONS: OptionDescriptions> = { 'logsPath': { type: 'string' }, '__enable-file-policy': { type: 'boolean' }, 'editSessionId': { type: 'string' }, + 'continueOn': { type: 'string' }, 'locate-shell-integration-path': { type: 'string', args: ['bash', 'pwsh', 'zsh', 'fish'] }, 'enable-coi': { type: 'boolean' }, diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index c7ce131f8b1..73067506f69 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -973,6 +973,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { configuration.isInitialStartup = false; // since this is a reload configuration.policiesData = this.policyService.serialize(); // set policies data again + configuration.continueOn = this.environmentMainService.continueOn; configuration.profiles = { all: this.userDataProfilesService.profiles, profile: this.profile || this.userDataProfilesService.defaultProfile diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 4f1f9d43384..b6893d0611f 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -1367,6 +1367,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic accessibilitySupport: app.accessibilitySupportEnabled, colorScheme: this.themeMainService.getColorScheme(), policiesData: this.policyService.serialize(), + continueOn: this.environmentMainService.continueOn, }; let window: ICodeWindow | undefined; diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 013743d904a..146864b176f 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -54,6 +54,8 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IOutputService } from 'vs/workbench/services/output/common/output'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { sha1Hex } from 'vs/base/browser/hash'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; registerSingleton(IEditSessionsLogService, EditSessionsLogService, false); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false); @@ -89,6 +91,9 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo private readonly shouldShowViewsContext: IContextKey; + private static APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn'; + private accountsMenuBadgeDisposable = this._register(new MutableDisposable()); + constructor( @IEditSessionsStorageService private readonly editSessionsStorageService: IEditSessionsStorageService, @IFileService private readonly fileService: IFileService, @@ -109,7 +114,9 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo @ICommandService private commandService: ICommandService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IFileDialogService private readonly fileDialogService: IFileDialogService, - @ILifecycleService private readonly lifecycleService: ILifecycleService + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IStorageService private readonly storageService: IStorageService, + @IActivityService private readonly activityService: IActivityService, ) { super(); @@ -123,6 +130,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this._register(this.fileService.registerProvider(EditSessionsFileSystemProvider.SCHEMA, new EditSessionsFileSystemProvider(this.editSessionsStorageService))); this.lifecycleService.onWillShutdown((e) => e.join(this.autoStoreEditSession(), { id: 'autoStoreEditSession', label: localize('autoStoreEditSession', 'Storing current edit session...') })); + this._register(this.editSessionsStorageService.onDidSignIn(() => this.updateAccountsMenuBadge())); } private autoResumeEditSession() { @@ -136,21 +144,58 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.telemetryService.publicLog2('editSessions.continue.resume'); if (this.environmentService.editSessionId !== undefined) { + this.logService.info(`Resuming edit session, reason: found editSessionId ${this.environmentService.editSessionId} in environment service...`); await this.resumeEditSession(this.environmentService.editSessionId).finally(() => this.environmentService.editSessionId = undefined); } else if ( this.configurationService.getValue('workbench.editSessions.autoResume') === 'onReload' && this.editSessionsStorageService.isSignedIn ) { + this.logService.info('Resuming edit session, reason: edit sessions enabled...'); // Attempt to resume edit session based on edit workspace identifier // Note: at this point if the user is not signed into edit sessions, // we don't want them to be prompted to sign in and should just return early await this.resumeEditSession(undefined, true); + } else { + // The application has previously launched via a protocol URL Continue On flow + const hasApplicationLaunchedFromContinueOnFlow = this.storageService.getBoolean(EditSessionsContribution.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, StorageScope.APPLICATION, false); + + if ((this.environmentService.continueOn !== undefined) && + !this.editSessionsStorageService.isSignedIn && + // and user has not yet been prompted to sign in on this machine + hasApplicationLaunchedFromContinueOnFlow === false + ) { + this.storageService.store(EditSessionsContribution.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, true, StorageScope.APPLICATION, StorageTarget.MACHINE); + await this.editSessionsStorageService.initialize(true); + if (this.editSessionsStorageService.isSignedIn) { + await this.resumeEditSession(undefined, true); + } else { + this.updateAccountsMenuBadge(); + } + // store the fact that we prompted the user + } else if (!this.editSessionsStorageService.isSignedIn && + // and user has been prompted to sign in on this machine + hasApplicationLaunchedFromContinueOnFlow === true + ) { + // display a badge in the accounts menu but do not prompt the user to sign in again + this.updateAccountsMenuBadge(); + // attempt a resume if we are in a pending state and the user just signed in + this._register(this.editSessionsStorageService.onDidSignIn(async () => this.resumeEditSession(undefined, true))); + } } performance.mark('code/didResumeEditSessionFromIdentifier'); }); } + private updateAccountsMenuBadge() { + if (this.editSessionsStorageService.isSignedIn) { + return this.accountsMenuBadgeDisposable.clear(); + } + + const badge = new NumberBadge(1, () => localize('check for pending edit sessions', 'Check for pending edit sessions')); + this.accountsMenuBadgeDisposable.value = this.activityService.showAccountsActivity({ badge, priority: 1 }); + } + private async autoStoreEditSession() { if (this.configurationService.getValue('workbench.experimental.editSessions.autoStore') === 'onShutdown') { await this.progressService.withProgress({ @@ -252,7 +297,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo if (ref !== undefined && uri !== 'noDestinationUri') { const encodedRef = encodeURIComponent(ref); uri = uri.with({ - query: uri.query.length > 0 ? (uri.query + `&${queryParamName}=${encodedRef}`) : `${queryParamName}=${encodedRef}` + query: uri.query.length > 0 ? (uri.query + `&${queryParamName}=${encodedRef}&continueOn=1`) : `${queryParamName}=${encodedRef}&continueOn=1` }); // Open the URI diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts index d995c8df6ca..7637ef73355 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts @@ -27,6 +27,7 @@ import { isWeb } from 'vs/base/common/platform'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { Codicon } from 'vs/base/common/codicons'; import { IUserDataSyncMachinesService, UserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; +import { Emitter } from 'vs/base/common/event'; type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } }; type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider }; @@ -50,6 +51,11 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes return this.existingSessionId !== undefined; } + private _didSignIn = new Emitter(); + get onDidSignIn() { + return this._didSignIn.event; + } + constructor( @IFileService private readonly fileService: IFileService, @IStorageService private readonly storageService: IStorageService, @@ -162,6 +168,9 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes } this.initialized = await this.doInitialize(fromContinueOn); this.signedInContext.set(this.initialized); + if (this.initialized) { + this._didSignIn.fire(); + } return this.initialized; } diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index b0afa0d9e63..f9b84cf5bc0 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -12,6 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { ILogService } from 'vs/platform/log/common/log'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync'; +import { Event } from 'vs/base/common/event'; export const EDIT_SESSION_SYNC_CATEGORY: ILocalizedString = { original: 'Edit Sessions', @@ -23,6 +24,7 @@ export interface IEditSessionsStorageService { _serviceBrand: undefined; readonly isSignedIn: boolean; + readonly onDidSignIn: Event; initialize(fromContinueOn: boolean): Promise; read(ref: string | undefined): Promise<{ ref: string; editSession: EditSession } | undefined>; diff --git a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts index d88a15bafe1..a766a535095 100644 --- a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -66,7 +66,9 @@ suite('Edit session sync', () => { override onWillShutdown = Event.None; }); instantiationService.stub(INotificationService, new TestNotificationService()); - instantiationService.stub(IEditSessionsStorageService, new class extends mock() { }); + instantiationService.stub(IEditSessionsStorageService, new class extends mock() { + override onDidSignIn = Event.None; + }); instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(ISCMService, SCMService); instantiationService.stub(IEnvironmentService, TestEnvironmentService); From bae6133cb862b883d8a66c77fb28903a0563d078 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 18:48:02 +0200 Subject: [PATCH 068/599] represent default profile (#161799) --- .../browser/parts/activitybar/activitybarPart.ts | 2 +- .../userDataProfile/common/userDataProfileService.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 1981ce23cc9..6e51d7a9257 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -1064,7 +1064,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart } private get profilesVisibilityPreference(): boolean { - return this.userDataProfilesService.profiles.length > 1 && !this.userDataProfileService.currentProfile.isDefault && this.storageService.getBoolean(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, true); + return this.storageService.getBoolean(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, this.userDataProfilesService.profiles.length > 1); } private set profilesVisibilityPreference(value: boolean) { diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts index 8b34656b973..63b78ba06b7 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts @@ -4,11 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { Promises } from 'vs/base/common/async'; +import { Codicon } from 'vs/base/common/codicons'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +const defaultUserDataProfileIcon = registerIcon('defaultSettingsProfiles-icon', Codicon.settings, localize('settingsProfilesIcon', 'Icon for Default Settings Profiles.')); + export class UserDataProfileService extends Disposable implements IUserDataProfileService { readonly _serviceBrand: undefined; @@ -65,6 +70,9 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi } getShortName(profile: IUserDataProfile): string { + if (profile.isDefault) { + return `$(${defaultUserDataProfileIcon.id})`; + } if (profile.shortName) { return profile.shortName; } From 0b1c344d5df888f20d69c5770562badf22b3fbce Mon Sep 17 00:00:00 2001 From: Benjamin Simmonds <44439583+benibenj@users.noreply.github.com> Date: Mon, 26 Sep 2022 18:48:53 +0200 Subject: [PATCH 069/599] Push action required extensions to the top and allow to ignore updates (#161577) * Ignore updates * smal fixes * Dropdown for editor * fixes * Test fixes * debounce --- .../extensions/browser/extensionEditor.ts | 5 +- .../extensions/browser/extensionsActions.ts | 51 ++++++++++++++----- .../extensions/browser/extensionsList.ts | 5 +- .../extensions/browser/extensionsViewlet.ts | 4 +- .../extensions/browser/extensionsViews.ts | 22 +++++++- .../browser/extensionsWorkbenchService.ts | 18 +++++++ .../contrib/extensions/common/extensions.ts | 2 + .../extensionsActions.test.ts | 21 ++++++-- .../electron-browser/extensionsViews.test.ts | 37 ++++++++++++-- 9 files changed, 134 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 96449b7b363..33ac92c4aed 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -29,7 +29,7 @@ import { UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, - InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction + InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, SkipUpdateAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -322,7 +322,8 @@ export class ExtensionEditor extends EditorPane { const actions = [ this.instantiationService.createInstance(ReloadAction), this.instantiationService.createInstance(ExtensionStatusLabelAction), - this.instantiationService.createInstance(UpdateAction), + this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '', + [[this.instantiationService.createInstance(UpdateAction)], [this.instantiationService.createInstance(SkipUpdateAction)]]), this.instantiationService.createInstance(SetColorThemeAction), this.instantiationService.createInstance(SetFileIconThemeAction), this.instantiationService.createInstance(SetProductIconThemeAction), diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 634dd88be4e..ffcefca9cbd 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -802,18 +802,18 @@ export class UninstallAction extends ExtensionAction { } } -export class UpdateAction extends ExtensionAction { +abstract class AbstractUpdateAction extends ExtensionAction { private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} prominent update`; - private static readonly DisabledClass = `${UpdateAction.EnabledClass} disabled`; + private static readonly DisabledClass = `${AbstractUpdateAction.EnabledClass} disabled`; private readonly updateThrottler = new Throttler(); constructor( - @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, - @IInstantiationService private readonly instantiationService: IInstantiationService, + id: string, label: string | undefined, + protected readonly extensionsWorkbenchService: IExtensionsWorkbenchService, ) { - super(`extensions.update`, '', UpdateAction.DisabledClass, false); + super(id, label, AbstractUpdateAction.DisabledClass, false); this.update(); } @@ -824,7 +824,6 @@ export class UpdateAction extends ExtensionAction { private async computeAndUpdateEnablement(): Promise { this.enabled = false; this.class = UpdateAction.DisabledClass; - this.label = this.getLabel(); if (!this.extension) { return; @@ -838,8 +837,17 @@ export class UpdateAction extends ExtensionAction { const isInstalled = this.extension.state === ExtensionState.Installed; this.enabled = canInstall && isInstalled && this.extension.outdated; - this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass; - this.label = this.getLabel(this.extension); + this.class = this.enabled ? AbstractUpdateAction.EnabledClass : AbstractUpdateAction.DisabledClass; + } +} + +export class UpdateAction extends AbstractUpdateAction { + + constructor( + @IExtensionsWorkbenchService override readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IInstantiationService protected readonly instantiationService: IInstantiationService, + ) { + super(`extensions.update`, localize('update', "Update"), extensionsWorkbenchService); } override async run(): Promise { @@ -858,15 +866,30 @@ export class UpdateAction extends ExtensionAction { this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, extension.latestVersion, InstallOperation.Update, undefined, err).run(); } } +} - private getLabel(extension?: IExtension): string { - if (!extension?.outdated) { - return localize('updateAction', "Update"); +export class SkipUpdateAction extends AbstractUpdateAction { + + constructor( + @IExtensionsWorkbenchService override readonly extensionsWorkbenchService: IExtensionsWorkbenchService + ) { + super(`extensions.ignoreUpdates`, localize('ignoreUpdates', "Ignore Updates"), extensionsWorkbenchService); + } + + override update() { + super.update(); + if (this.extension) { + this._checked = this.extensionsWorkbenchService.isExtensionIgnoresUpdates(this.extension); } - if (extension.outdatedTargetPlatform) { - return localize('updateToTargetPlatformVersion', "Update to {0} version", TargetPlatformToString(extension.gallery!.properties.targetPlatform)); + } + + override async run(): Promise { + if (!this.extension) { + return; } - return localize('updateToLatestVersion', "Update to {0}", extension.latestVersion); + alert(localize('ignoreExtensionUpdate', "Ignoring {0} updates", this.extension.displayName)); + const newIgnoresAutoUpdates = !this.extensionsWorkbenchService.isExtensionIgnoresUpdates(this.extension); + this.extensionsWorkbenchService.setExtensionIgnoresUpdate(this.extension, newIgnoresAutoUpdates); } } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 931710ee3d5..7c9a3c17f22 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { Event } from 'vs/base/common/event'; import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +import { ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, SkipUpdateAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions'; @@ -120,7 +120,8 @@ export class Renderer implements IPagedRenderer { this.instantiationService.createInstance(ExtensionStatusLabelAction), this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, true), reloadAction, - this.instantiationService.createInstance(UpdateAction), + this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '', + [[this.instantiationService.createInstance(UpdateAction)], [this.instantiationService.createInstance(SkipUpdateAction)]]), this.instantiationService.createInstance(InstallDropdownAction), this.instantiationService.createInstance(InstallingLabelAction), this.instantiationService.createInstance(SetLanguageAction), diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index fb9c4ee55ab..106da39d421 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -800,14 +800,14 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService ) { super(); - this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this)); + this._register(Event.debounce(extensionsWorkbenchService.onChange, () => undefined, 100, undefined, undefined, this._store)(this.onServiceChange, this)); } private onServiceChange(): void { this.badgeHandle.clear(); const extensionsReloadRequired = this.extensionsWorkbenchService.installed.filter(e => e.reloadRequiredStatus !== undefined); - const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) && !extensionsReloadRequired.includes(e) ? 1 : 0), 0); + const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) && !this.extensionsWorkbenchService.isExtensionIgnoresUpdates(e) && !extensionsReloadRequired.includes(e) ? 1 : 0), 0); const newBadgeNumber = outdated + extensionsReloadRequired.length; if (newBadgeNumber > 0) { let msg = ''; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index ec3821e1885..d812d8b2a0f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -521,7 +521,8 @@ export class ExtensionsListView extends ViewPane { result = this.sortExtensions(result, options); } else { const runningExtensionsById = runningExtensions.reduce((result, e) => { result.set(ExtensionIdentifier.toKey(e.identifier.value), e); return result; }, new Map()); - result = result.sort((e1, e2) => { + + const defaultSort = (e1: IExtension, e2: IExtension) => { const running1 = runningExtensionsById.get(ExtensionIdentifier.toKey(e1.identifier.id)); const isE1Running = !!running1 && this.extensionManagementServerService.getExtensionManagementServer(toExtension(running1)) === e1.server; const running2 = runningExtensionsById.get(ExtensionIdentifier.toKey(e2.identifier.id)); @@ -544,7 +545,24 @@ export class ExtensionsListView extends ViewPane { return e1.displayName.localeCompare(e2.displayName); } return isE1Running ? -1 : 1; + }; + + const outdated: IExtension[] = []; + const reloadRequired: IExtension[] = []; + const noActionRequired: IExtension[] = []; + result.forEach(e => { + if (e.outdated && !this.extensionsWorkbenchService.isExtensionIgnoresUpdates(e)) { + outdated.push(e); + } + else if (e.reloadRequiredStatus) { + reloadRequired.push(e); + } + else { + noActionRequired.push(e); + } }); + + result = [...outdated.sort(defaultSort), ...reloadRequired.sort(defaultSort), ...noActionRequired.sort(defaultSort)]; } return result; } @@ -663,7 +681,7 @@ export class ExtensionsListView extends ViewPane { private filterRecentlyUpdatedExtensions(local: IExtension[], query: Query, options: IQueryOptions): IExtension[] { let { value, categories } = this.parseCategories(query.value); const currentTime = Date.now(); - local = local.filter(e => !e.isBuiltin && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView.RECENT_UPDATE_DURATION); + local = local.filter(e => !e.isBuiltin && !e.outdated && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView.RECENT_UPDATE_DURATION); value = value.replace(/@recentlyUpdated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase(); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 4dda6675f73..10fd6d93e31 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -1770,6 +1770,24 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } } + setExtensionIgnoresUpdate(extension: IExtension, ignoreAutoUpate: boolean): void { + const extensionKey = new ExtensionKey(extension.identifier, extension.version); + if (ignoreAutoUpate) { + this.ignoreAutoUpdate(extensionKey); + } + else if (this.isAutoUpdateIgnored(extensionKey)) { + this.ignoredAutoUpdateExtensions = this.ignoredAutoUpdateExtensions.filter(extensionId => extensionId !== extensionKey.toString()); + } + else { + return; + } + this._onChange.fire(extension); + } + + isExtensionIgnoresUpdates(extension: IExtension): boolean { + return this.isAutoUpdateIgnored(new ExtensionKey(extension.identifier, extension.version)); + } + private isAutoUpdateIgnored(extensionKey: ExtensionKey): boolean { return this.ignoredAutoUpdateExtensions.indexOf(extensionKey.toString()) !== -1; } diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 9b6ca4e0345..14312e367c6 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -111,6 +111,8 @@ export interface IExtensionsWorkbenchService { canSetLanguage(extension: IExtension): boolean; setLanguage(extension: IExtension): Promise; setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise; + setExtensionIgnoresUpdate(extension: IExtension, ignoreAutoUpate: boolean): void; + isExtensionIgnoresUpdates(extension: IExtension): boolean; open(extension: IExtension, options?: IExtensionEditorOptions): Promise; checkForUpdates(): Promise; getExtensionStatus(extension: IExtension): IExtensionsStatus | undefined; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 7b468431a75..caabf67a2eb 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -415,11 +415,22 @@ suite('ExtensionsActions', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.stubPromise(IExtensionGalleryService, 'getCompatibleExtension', gallery); instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', [gallery]); - await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None); - const promise = Event.toPromise(testObject.onDidChange); - installEvent.fire({ identifier: local.identifier, source: gallery }); - await promise; - assert.ok(!testObject.enabled); + await new Promise(c => { + testObject.onDidChange(() => { + if (testObject.enabled) { + c(); + } + }); + instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None); + }); + await new Promise(c => { + testObject.onDidChange(() => { + if (!testObject.enabled) { + c(); + } + }); + installEvent.fire({ identifier: local.identifier, source: gallery }); + }); }); test('Test ManageExtensionAction when there is no extension', () => { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 123c8cb5676..cab7fda0f66 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -47,6 +47,7 @@ import { Schemas } from 'vs/base/common/network'; import { platform } from 'vs/base/common/platform'; import { arch } from 'vs/base/common/process'; import { IProductService } from 'vs/platform/product/common/productService'; +import { CancellationToken } from 'vs/base/common/cancellation'; suite('ExtensionsViews Tests', () => { @@ -58,13 +59,15 @@ suite('ExtensionsViews Tests', () => { didUninstallEvent: Emitter; const localEnabledTheme = aLocalExtension('first-enabled-extension', { categories: ['Themes', 'random'] }, { installedTimestamp: 123456 }); - const localEnabledLanguage = aLocalExtension('second-enabled-extension', { categories: ['Programming languages'] }, { installedTimestamp: Date.now() }); + const localEnabledLanguage = aLocalExtension('second-enabled-extension', { categories: ['Programming languages'], version: '1.0.0' }, { installedTimestamp: Date.now() }); const localDisabledTheme = aLocalExtension('first-disabled-extension', { categories: ['themes'] }, { installedTimestamp: 234567 }); const localDisabledLanguage = aLocalExtension('second-disabled-extension', { categories: ['programming languages'] }, { installedTimestamp: Date.now() - 50000 }); const localRandom = aLocalExtension('random-enabled-extension', { categories: ['random'] }, { installedTimestamp: 345678 }); const builtInTheme = aLocalExtension('my-theme', { contributes: { themes: ['my-theme'] } }, { type: ExtensionType.System, installedTimestamp: 222 }); const builtInBasic = aLocalExtension('my-lang', { contributes: { grammars: [{ language: 'my-language' }] } }, { type: ExtensionType.System, installedTimestamp: 666666 }); + const galleryEnabledLanguage = aGalleryExtension(localEnabledLanguage.manifest.name, { ...localEnabledLanguage.manifest, version: '1.0.1', identifier: localDisabledLanguage.identifier }); + const workspaceRecommendationA = aGalleryExtension('workspace-recommendation-A'); const workspaceRecommendationB = aGalleryExtension('workspace-recommendation-B'); const configBasedRecommendationA = aGalleryExtension('configbased-recommendation-A'); @@ -100,7 +103,8 @@ suite('ExtensionsViews Tests', () => { async getInstalled() { return []; }, async canInstall() { return true; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, - async getTargetPlatform() { return getTargetPlatform(platform, arch); } + async getTargetPlatform() { return getTargetPlatform(platform, arch); }, + async updateMetadata(local) { return local; } }); instantiationService.stub(IRemoteAgentService, RemoteAgentService); instantiationService.stub(IContextKeyService, new MockContextKeyService()); @@ -165,8 +169,9 @@ suite('ExtensionsViews Tests', () => { setup(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localEnabledTheme, localEnabledLanguage, localRandom, localDisabledTheme, localDisabledLanguage, builtInTheme, builtInBasic]); instantiationService.stubPromise(IExtensionManagementService, 'getExtensgetExtensionsControlManifestionsReport', {}); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); - instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', []); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(galleryEnabledLanguage)); + instantiationService.stubPromise(IExtensionGalleryService, 'getCompatibleExtension', galleryEnabledLanguage); + instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', [galleryEnabledLanguage]); instantiationService.stubPromise(IExperimentService, 'getExperimentsByType', []); instantiationService.stub(IViewDescriptorService, { @@ -185,6 +190,7 @@ suite('ExtensionsViews Tests', () => { toExtensionDescription(builtInTheme), toExtensionDescription(builtInBasic) ], + canAddExtension: (extension) => true, whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); await (instantiationService.get(IWorkbenchExtensionEnablementService)).setEnablement([localDisabledTheme], EnablementState.DisabledGlobally); @@ -242,6 +248,29 @@ suite('ExtensionsViews Tests', () => { }); }); + test('Test default view actions required sorting', async () => { + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const extension = (await workbenchService.queryLocal()).find(ex => ex.identifier === localEnabledLanguage.identifier); + + await new Promise(c => { + const disposable = workbenchService.onChange(() => { + if (extension?.outdated) { + disposable.dispose(); + c(); + } + }); + instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None); + }); + + const result = await testableView.show('@installed'); + assert.strictEqual(result.length, 5, 'Unexpected number of results for @installed query'); + const actual = [result.get(0).name, result.get(1).name, result.get(2).name, result.get(3).name, result.get(4).name]; + const expected = [localEnabledLanguage.manifest.name, localEnabledTheme.manifest.name, localRandom.manifest.name, localDisabledTheme.manifest.name, localDisabledLanguage.manifest.name]; + for (let i = 0; i < result.length; i++) { + assert.strictEqual(actual[i], expected[i], 'Unexpected extension for @installed query with outadted extension.'); + } + }); + test('Test installed query results', async () => { await testableView.show('@installed').then(result => { assert.strictEqual(result.length, 5, 'Unexpected number of results for @installed query'); From b8a7485526864d7c5dbfe209a74b7a5cc2932c61 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 26 Sep 2022 09:49:53 -0700 Subject: [PATCH 070/599] Fix markdown preview refresh from disk (#161800) Fixes #149974 --- extensions/markdown-language-features/src/preview/preview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/src/preview/preview.ts b/extensions/markdown-language-features/src/preview/preview.ts index 26f94614ad8..51348bd7128 100644 --- a/extensions/markdown-language-features/src/preview/preview.ts +++ b/extensions/markdown-language-features/src/preview/preview.ts @@ -158,7 +158,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { this._register(watcher.onDidChange(uri => { if (this.isPreviewOf(uri)) { // Only use the file system event when VS Code does not already know about the file - if (!vscode.workspace.textDocuments.some(doc => doc.uri.toString() !== uri.toString())) { + if (!vscode.workspace.textDocuments.some(doc => doc.uri.toString() === uri.toString())) { this.refresh(); } } From b42e424308d651d928ef37ba6846f2ff572cb141 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 26 Sep 2022 18:56:31 +0200 Subject: [PATCH 071/599] tweak name to reset all menu hiding (#161801) --- src/vs/platform/actions/common/menuResetAction.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/actions/common/menuResetAction.ts b/src/vs/platform/actions/common/menuResetAction.ts index 84ee76e2b91..c482594103a 100644 --- a/src/vs/platform/actions/common/menuResetAction.ts +++ b/src/vs/platform/actions/common/menuResetAction.ts @@ -14,8 +14,8 @@ export class MenuHiddenStatesReset extends Action2 { super({ id: 'menu.resetHiddenStates', title: { - value: localize('title', 'Reset Hidden Menus'), - original: 'Reset Hidden Menus' + value: localize('title', 'Reset All Menus'), + original: 'Reset All Menus' }, category: localize('cat', 'View'), f1: true From 811fbff6b67cf2f3735e6e7add84817a6d581949 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 19:05:38 +0200 Subject: [PATCH 072/599] show the profiles menu like other menus (#161803) --- .../parts/activitybar/activitybarActions.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index bee1974abd0..6eb949476b5 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -37,8 +37,7 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { ViewContainerLocation } from 'vs/workbench/common/views'; import { IPaneCompositePart } from 'vs/workbench/browser/parts/paneCompositePart'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IUserDataProfileService, MANAGE_PROFILES_ACTION_ID, PROFILES_CATEGORY } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { IUserDataProfileService, ManageProfilesSubMenu, PROFILES_CATEGORY } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; export class ViewContainerActivityAction extends ActivityAction { @@ -186,6 +185,7 @@ class MenuActivityActionViewItem extends AbstractGlobalActivityActionViewItem { private readonly menuId: MenuId, action: ActivityAction, contextMenuActionsProvider: () => IAction[], + icon: boolean, colors: (theme: IColorTheme) => ICompositeBarColors, hoverOptions: IActivityHoverOptions, @IThemeService themeService: IThemeService, @@ -197,7 +197,7 @@ class MenuActivityActionViewItem extends AbstractGlobalActivityActionViewItem { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IKeybindingService keybindingService: IKeybindingService, ) { - super(action, contextMenuActionsProvider, { draggable: false, colors, icon: true, hasPopup: true, hoverOptions }, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); + super(action, contextMenuActionsProvider, { draggable: false, colors, icon, hasPopup: true, hoverOptions }, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); } protected async run(): Promise { @@ -245,7 +245,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { @IKeybindingService keybindingService: IKeybindingService, @ICredentialsService private readonly credentialsService: ICredentialsService, ) { - super(MenuId.AccountsContext, action, contextMenuActionsProvider, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); + super(MenuId.AccountsContext, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); } protected override async resolveMainMenuActions(accountsMenu: IMenu, disposables: DisposableStore): Promise { @@ -340,7 +340,7 @@ export interface IProfileActivity extends IActivity { readonly icon: boolean; } -export class ProfilesActivityActionViewItem extends AbstractGlobalActivityActionViewItem { +export class ProfilesActivityActionViewItem extends MenuActivityActionViewItem { static readonly PROFILES_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showProfiles'; @@ -350,7 +350,6 @@ export class ProfilesActivityActionViewItem extends AbstractGlobalActivityAction colors: (theme: IColorTheme) => ICompositeBarColors, hoverOptions: IActivityHoverOptions, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, - @ICommandService private readonly commandService: ICommandService, @IStorageService private readonly storageService: IStorageService, @IThemeService themeService: IThemeService, @IHoverService hoverService: IHoverService, @@ -361,11 +360,7 @@ export class ProfilesActivityActionViewItem extends AbstractGlobalActivityAction @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IKeybindingService keybindingService: IKeybindingService, ) { - super(action, contextMenuActionsProvider, { draggable: false, colors, icon: (action.activity).icon, hasPopup: true, hoverOptions }, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); - } - - protected run(): Promise { - return this.commandService.executeCommand(MANAGE_PROFILES_ACTION_ID); + super(ManageProfilesSubMenu, action, contextMenuActionsProvider, (action.activity).icon, colors, hoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); } protected override async resolveContextMenuActions(disposables: DisposableStore): Promise { @@ -401,7 +396,7 @@ export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IKeybindingService keybindingService: IKeybindingService, ) { - super(MenuId.GlobalActivity, action, contextMenuActionsProvider, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); + super(MenuId.GlobalActivity, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); } } From 2b0d08baa5b068be5908fd4013cb21d46d620f27 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 19:41:38 +0200 Subject: [PATCH 073/599] show the current short name in the input (#161812) --- .../contrib/userDataProfile/browser/userDataProfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index a196b4d7018..90b0029d1f7 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -181,7 +181,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements const profile = that.userDataProfileService.currentProfile; const shortName = await quickInputService.input({ - value: profile.shortName, + value: that.userDataProfileService.getShortName(profile), title: localize('change short name', "Change Short Name..."), validateInput: async (value: string) => { if (profile.shortName !== value && !ThemeIcon.fromString(value) && charCount(value) > 2) { From cfe012588aa636208b93b06f43d09910d45ec33a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 11:07:18 -0700 Subject: [PATCH 074/599] skip test on windows (#161794) fix #161793 --- .../browser/contextualActionAddon.test.ts | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts index 686b0e053cd..a8413116d28 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual } from 'assert'; +import { isWindows } from 'vs/base/common/platform'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -83,10 +84,11 @@ suite('ContextualActionAddon', () => { }); }); }); - suite('freePort', () => { - const expected = new Map(); - const portCommand = `yarn start dev`; - const output = `yarn run v1.22.17 + if (!isWindows) { + suite('freePort', () => { + const expected = new Map(); + const portCommand = `yarn start dev`; + const output = `yarn run v1.22.17 warning ../../package.json: No license field Error: listen EADDRINUSE: address already in use 0.0.0.0:3000 at Server.setupListenHandle [as _listen2] (node:net:1315:16) @@ -100,27 +102,29 @@ suite('ContextualActionAddon', () => { } error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.`; - const actionOptions = [{ - id: 'terminal.freePort', - label: 'Free port 3000', - run: true, - tooltip: 'Free port 3000', - enabled: true - }]; - setup(() => { - const command = freePort(terminalInstance); - expected.set(command.commandLineMatcher.toString(), [command]); - contextualActionAddon.registerCommandFinishedListener(command); - }); - suite('returns undefined when', () => { - test('output does not match', () => { - strictEqual(getMatchActions(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); + const actionOptions = [{ + id: 'terminal.freePort', + label: 'Free port 3000', + run: true, + tooltip: 'Free port 3000', + enabled: true + }]; + setup(() => { + const command = freePort(terminalInstance); + expected.set(command.commandLineMatcher.toString(), [command]); + contextualActionAddon.registerCommandFinishedListener(command); + }); + suite('returns undefined when', () => { + test('output does not match', () => { + strictEqual(getMatchActions(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); + }); + }); + test('returns actions', () => { + assertMatchOptions(getMatchActions(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); }); }); - test('returns actions', () => { - assertMatchOptions(getMatchActions(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); - }); - }); + } + suite('gitPushSetUpstream', () => { const expectedMap = new Map(); const command = `git push`; From d23eed799e7418ed287b147ce1fb1a98775404a4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 20:10:04 +0200 Subject: [PATCH 075/599] enable syncing profiles (#161814) - remove settings flag --- src/vs/platform/userDataSync/common/userDataSyncService.ts | 5 ++--- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index f33f1406558..85acc352626 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -92,7 +92,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ @IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService, @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IProductService private readonly productService: IProductService, - @IConfigurationService private readonly configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, ) { super(); @@ -421,7 +420,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return isUndefined(result) ? null : result; } - if (this.environmentService.isBuilt && !(this.productService.enableSyncingProfiles && this.configurationService.getValue('settingsSync.enableSyncingProfiles'))) { + if (this.environmentService.isBuilt && !this.productService.enableSyncingProfiles) { return null; } @@ -593,7 +592,7 @@ class ProfileSynchronizer extends Disposable { if (!this._profile.isDefault) { return; } - if (this.environmentService.isBuilt && !(this.productService.enableSyncingProfiles && this.configurationService.getValue('settingsSync.enableSyncingProfiles'))) { + if (this.environmentService.isBuilt && !this.productService.enableSyncingProfiles) { this.logService.debug('Skipping profiles sync'); return; } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 023bf17fe4c..58295101d2f 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -609,7 +609,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: SyncResource.GlobalState, label: getSyncAreaLabel(SyncResource.GlobalState), }]; - if (!this.environmentService.isBuilt || (this.productService.enableSyncingProfiles && this.configurationService.getValue('settingsSync.enableSyncingProfiles'))) { + if (!this.environmentService.isBuilt || this.productService.enableSyncingProfiles) { result.push({ id: SyncResource.Profiles, label: getSyncAreaLabel(SyncResource.Profiles), From 29e985eca0713c8458ae8349c1742d6fb75719e4 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 26 Sep 2022 11:10:54 -0700 Subject: [PATCH 076/599] rev vscode-nls to version that doesn't ask for vscode-nls-web-data (#161819) ref #161297 --- extensions/configuration-editing/package.json | 2 +- extensions/configuration-editing/yarn.lock | 8 ++++---- extensions/debug-auto-launch/package.json | 2 +- extensions/debug-auto-launch/yarn.lock | 8 ++++---- extensions/debug-server-ready/package.json | 2 +- extensions/debug-server-ready/yarn.lock | 8 ++++---- extensions/extension-editing/package.json | 2 +- extensions/extension-editing/yarn.lock | 8 ++++---- extensions/git-base/package.json | 2 +- extensions/git-base/yarn.lock | 8 ++++---- extensions/git/package.json | 2 +- extensions/git/yarn.lock | 8 ++++---- extensions/github-authentication/package.json | 2 +- extensions/github-authentication/yarn.lock | 8 ++++---- extensions/github/package.json | 2 +- extensions/github/yarn.lock | 8 ++++---- extensions/grunt/package.json | 2 +- extensions/grunt/yarn.lock | 8 ++++---- extensions/gulp/package.json | 2 +- extensions/gulp/yarn.lock | 8 ++++---- extensions/image-preview/package.json | 2 +- extensions/image-preview/yarn.lock | 8 ++++---- extensions/jake/package.json | 2 +- extensions/jake/yarn.lock | 8 ++++---- extensions/markdown-language-features/package.json | 2 +- .../markdown-language-features/server/package.json | 2 +- extensions/markdown-language-features/server/yarn.lock | 2 +- extensions/markdown-language-features/yarn.lock | 8 ++++---- extensions/merge-conflict/package.json | 2 +- extensions/merge-conflict/yarn.lock | 8 ++++---- extensions/microsoft-authentication/package.json | 2 +- extensions/microsoft-authentication/yarn.lock | 8 ++++---- extensions/npm/package.json | 2 +- extensions/npm/yarn.lock | 8 ++++---- extensions/php-language-features/package.json | 2 +- extensions/php-language-features/yarn.lock | 8 ++++---- extensions/references-view/package.json | 2 +- extensions/references-view/yarn.lock | 8 ++++---- extensions/shared.webpack.config.js | 10 ---------- extensions/simple-browser/package.json | 2 +- extensions/simple-browser/yarn.lock | 8 ++++---- extensions/typescript-language-features/package.json | 2 +- extensions/typescript-language-features/yarn.lock | 8 ++++---- 43 files changed, 102 insertions(+), 112 deletions(-) diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index a124a0432e6..641b3ca5669 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "jsonc-parser": "^2.2.1", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "capabilities": { "virtualWorkspaces": true, diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index e8272098f1e..5bb8132d373 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -12,7 +12,7 @@ jsonc-parser@^2.2.1: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc" integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index 80ea639b5f3..6f330276ddc 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -33,7 +33,7 @@ ] }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/debug-auto-launch/yarn.lock +++ b/extensions/debug-auto-launch/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 3b570124452..09cd096bff3 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -150,7 +150,7 @@ ] }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/debug-server-ready/yarn.lock +++ b/extensions/debug-server-ready/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index add192a06c0..fb50d9163b4 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -29,7 +29,7 @@ "jsonc-parser": "^2.2.1", "markdown-it": "^12.3.2", "parse5": "^3.0.2", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "contributes": { "jsonValidation": [ diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index 3aa5397f837..2d5b4e2f835 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -67,7 +67,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/git-base/package.json b/extensions/git-base/package.json index 1c7daa3b4b9..f4ac7fa32f4 100644 --- a/extensions/git-base/package.json +++ b/extensions/git-base/package.json @@ -100,7 +100,7 @@ ] }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/git-base/yarn.lock b/extensions/git-base/yarn.lock index 0cd0d3ce8f2..efe3c44327d 100644 --- a/extensions/git-base/yarn.lock +++ b/extensions/git-base/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" integrity sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/git/package.json b/extensions/git/package.json index 3bc3a7b4af7..db43d24b5f2 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -2779,7 +2779,7 @@ "file-type": "16.5.4", "jschardet": "3.0.0", "picomatch": "2.3.1", - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "vscode-uri": "^2.0.0", "which": "^1.3.0" }, diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 502b35d9c38..b5a79f3f238 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -186,10 +186,10 @@ util-deprecate@^1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-uri@^2.0.0: version "2.0.0" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 35a95e4354d..7e4f7dde431 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -65,7 +65,7 @@ "node-fetch": "2.6.7", "uuid": "8.1.0", "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "vscode-tas-client": "^0.1.47" }, "devDependencies": { diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index 6ebb79992dc..330255ba858 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -143,10 +143,10 @@ uuid@8.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-tas-client@^0.1.47: version "0.1.47" diff --git a/extensions/github/package.json b/extensions/github/package.json index 1b21d4b52a1..a262e352a11 100644 --- a/extensions/github/package.json +++ b/extensions/github/package.json @@ -135,7 +135,7 @@ "dependencies": { "@octokit/rest": "19.0.4", "tunnel": "^0.0.6", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/github/yarn.lock b/extensions/github/yarn.lock index c199d2f7553..8db5da00683 100644 --- a/extensions/github/yarn.lock +++ b/extensions/github/yarn.lock @@ -152,10 +152,10 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 245fd717f8c..0f5e605bcf9 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:grunt" }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 062dc4a788f..41c23eb1145 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:gulp" }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index 03c2784a533..a3bc0dc4f82 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -102,7 +102,7 @@ }, "dependencies": { "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "repository": { "type": "git", diff --git a/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock index 61a6bb946db..a9af1f07de4 100644 --- a/extensions/image-preview/yarn.lock +++ b/extensions/image-preview/yarn.lock @@ -46,7 +46,7 @@ "@microsoft/1ds-core-js" "^3.2.3" "@microsoft/1ds-post-js" "^3.2.3" -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 5ffa78e3981..4e6a94a8b24 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:jake" }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/jake/yarn.lock +++ b/extensions/jake/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 49c00bf6154..605ee9c1429 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -586,7 +586,7 @@ "morphdom": "^2.6.1", "picomatch": "^2.3.1", "vscode-languageclient": "^8.0.2", - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json index c38c618f05d..f6a832c69ce 100644 --- a/extensions/markdown-language-features/server/package.json +++ b/extensions/markdown-language-features/server/package.json @@ -14,7 +14,7 @@ "vscode-languageserver-textdocument": "^1.0.5", "vscode-languageserver-types": "^3.17.1", "vscode-markdown-languageservice": "^0.1.0-alpha.10", - "vscode-nls": "^5.0.1", + "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index 00347dd2bd8..65426cb72a5 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -53,7 +53,7 @@ vscode-markdown-languageservice@^0.1.0-alpha.10: vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-nls@^5.0.1: +vscode-nls@^5.0.1, vscode-nls@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 5ffe3ff4b82..6bd778ed899 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -258,10 +258,10 @@ vscode-nls@^5.0.1: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 978341508f8..caba136ce52 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -166,7 +166,7 @@ } }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index 90475ddc7e0..8b8c7a6c15b 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index 07f803a5930..8bf6cd70855 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -62,7 +62,7 @@ "stream": "0.0.2", "uuid": "^8.2.0", "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "repository": { "type": "git", diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index 6706f6a4aae..8d01670e906 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -198,10 +198,10 @@ uuid@^8.2.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e" integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 9cc9ac5dedb..cae1fd7eab1 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -22,7 +22,7 @@ "jsonc-parser": "^2.2.1", "minimatch": "^3.0.4", "request-light": "^0.5.7", - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "which": "^2.0.2", "which-pm": "^2.0.0" }, diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index 3479f1c58b6..bfd3b4b3de1 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -192,10 +192,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== which-pm@^2.0.0: version "2.0.0" diff --git a/extensions/php-language-features/package.json b/extensions/php-language-features/package.json index 8782b3d83b4..dd7f6445d1a 100644 --- a/extensions/php-language-features/package.json +++ b/extensions/php-language-features/package.json @@ -74,7 +74,7 @@ "watch": "npx gulp watch-extension:php-language-features" }, "dependencies": { - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "which": "^2.0.2" }, "devDependencies": { diff --git a/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock index 62c8b33e55d..baafbeb7ca3 100644 --- a/extensions/php-language-features/yarn.lock +++ b/extensions/php-language-features/yarn.lock @@ -17,10 +17,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== which@^2.0.2: version "2.0.2" diff --git a/extensions/references-view/package.json b/extensions/references-view/package.json index 4176cda3d1a..d3fcadcbffd 100644 --- a/extensions/references-view/package.json +++ b/extensions/references-view/package.json @@ -407,7 +407,7 @@ "watch": "npx gulp watch-extension:references-view" }, "dependencies": { - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/references-view/yarn.lock b/extensions/references-view/yarn.lock index 76eaba8dd6f..1661be7c5d2 100644 --- a/extensions/references-view/yarn.lock +++ b/extensions/references-view/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.33.tgz#566713b1b626f781c5c58fe3531307283e00720c" integrity sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/shared.webpack.config.js b/extensions/shared.webpack.config.js index a8f24c1a572..8be35296ddf 100644 --- a/extensions/shared.webpack.config.js +++ b/extensions/shared.webpack.config.js @@ -113,15 +113,6 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi test: /\.ts$/, exclude: /node_modules/, use: [ - // TODO: bring this back once vscode-nls-dev supports browser - // { - // // vscode-nls-dev loader: - // // * rewrite nls-calls - // loader: 'vscode-nls-dev/lib/webpack-loader', - // options: { - // base: path.join(extConfig.context, 'src') - // } - // }, { // configure TypeScript loader: // * enable sources maps for end-to-end source maps @@ -137,7 +128,6 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi }, externals: { 'vscode': 'commonjs vscode', // ignored because it doesn't exist, - 'vscode-nls-web-data': 'commonjs vscode-nls-web-data', // ignored because this is injected by the webworker extension host 'applicationinsights-native-metrics': 'commonjs applicationinsights-native-metrics', // ignored because we don't ship native module '@opentelemetry/tracing': 'commonjs @opentelemetry/tracing' // ignored because we don't ship this module }, diff --git a/extensions/simple-browser/package.json b/extensions/simple-browser/package.json index fe3f4de2a5f..2db456cb387 100644 --- a/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -68,7 +68,7 @@ }, "dependencies": { "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.1.0" + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/vscode-webview": "^1.57.0", diff --git a/extensions/simple-browser/yarn.lock b/extensions/simple-browser/yarn.lock index 32215e9059b..97902582dea 100644 --- a/extensions/simple-browser/yarn.lock +++ b/extensions/simple-browser/yarn.lock @@ -56,7 +56,7 @@ vscode-codicons@^0.0.14: resolved "https://registry.yarnpkg.com/vscode-codicons/-/vscode-codicons-0.0.14.tgz#e0d05418e2e195564ff6f6a2199d70415911c18f" integrity sha512-6CEH5KT9ct5WMw7n5dlX7rB8ya4CUI2FSq1Wk36XaW+c5RglFtAanUV0T+gvZVVFhl/WxfjTvFHq06Hz9c1SLA== -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index d050a4a931f..3ce0e33921c 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -38,7 +38,7 @@ "@vscode/extension-telemetry": "0.6.2", "jsonc-parser": "^2.2.1", "semver": "5.5.1", - "vscode-nls": "^5.1.0", + "vscode-nls": "^5.2.0", "vscode-tas-client": "^0.1.63", "vscode-uri": "^3.0.3" }, diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index 08e22bf4c15..89f3521b9b6 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -85,10 +85,10 @@ tas-client@0.1.58: dependencies: axios "^0.26.1" -vscode-nls@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" - integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== vscode-tas-client@^0.1.63: version "0.1.63" From ed48c7bd5baacedeb1753405754a02a9bbe2ac9c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 20:13:08 +0200 Subject: [PATCH 077/599] add create temp profile action to create picker (#161810) --- .../browser/userDataProfileActions.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts index dbdb4fea927..49ece437ba0 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts @@ -141,6 +141,9 @@ registerAction2(class CreateProfileAction extends Action2 { }, { id: CreateEmptyProfileAction.ID, label: CreateEmptyProfileAction.TITLE.value, + }, { + id: CreateTransientProfileAction.ID, + label: CreateTransientProfileAction.TITLE.value, }], { hideInput: true, canPickMany: false, title: localize('create settings profile', "{0}: Create...", PROFILES_CATEGORY) }); if (pick) { return commandService.executeCommand(pick.id); @@ -148,24 +151,28 @@ registerAction2(class CreateProfileAction extends Action2 { } }); -registerAction2(class CreateTransientProfileAction extends Action2 { +class CreateTransientProfileAction extends Action2 { + static readonly ID = 'workbench.profiles.actions.createTemporaryProfile'; + static readonly TITLE = { + value: localize('create temporary profile', "Create a Temporary Settings Profile"), + original: 'Create a Temporary Settings Profile' + }; constructor() { super({ - id: 'workbench.profiles.actions.createTemporaryProfile', - title: { - value: localize('create temporary profile', "Create a Temporary Settings Profile"), - original: 'Create a Temporary Settings Profile' - }, + id: CreateTransientProfileAction.ID, + title: CreateTransientProfileAction.TITLE, category: PROFILES_CATEGORY, f1: true, - precondition: PROFILES_ENABLEMENT_CONTEXT + precondition: PROFILES_ENABLEMENT_CONTEXT, }); } async run(accessor: ServicesAccessor) { return accessor.get(IUserDataProfileManagementService).createAndEnterTransientProfile(); } -}); +} + +registerAction2(CreateTransientProfileAction); export class RenameProfileAction extends Action2 { static readonly ID = 'workbench.profiles.actions.renameProfile'; From ff9e92cce27b337c2bbc8161468ea9940ec0e826 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Fri, 23 Sep 2022 13:32:36 -0700 Subject: [PATCH 078/599] fix: propagate log level to client --- src/vs/server/node/webClientServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/server/node/webClientServer.ts b/src/vs/server/node/webClientServer.ts index 433e12a7b15..e57259fc731 100644 --- a/src/vs/server/node/webClientServer.ts +++ b/src/vs/server/node/webClientServer.ts @@ -302,7 +302,7 @@ export class WebClientServer { const workbenchWebConfiguration = { remoteAuthority, _wrapWebWorkerExtHostInIframe, - developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined }, + developmentOptions: { enableSmokeTestDriver: this._environmentService.args['enable-smoke-test-driver'] ? true : undefined, logLevel: this._logService.getLevel() }, settingsSyncOptions: !this._environmentService.isBuilt && this._environmentService.args['enable-sync'] ? { enabled: true } : undefined, enableWorkspaceTrust: !this._environmentService.args['disable-workspace-trust'], folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']), From e2207cb8559a71c375a520de1338a9dac47543f3 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Mon, 26 Sep 2022 11:44:36 -0700 Subject: [PATCH 079/599] fix search unit tests using FileMatch createInstance (#161817) fix search unit test createInstance --- .../workbench/contrib/search/test/browser/searchActions.test.ts | 2 +- .../workbench/contrib/search/test/browser/searchViewlet.test.ts | 2 +- .../workbench/contrib/search/test/common/searchResult.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts index 623a2b6f972..c76c3469563 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts @@ -124,7 +124,7 @@ suite('Search Actions', () => { resource: URI.file('somepath' + ++counter), results: [] }; - return instantiationService.createInstance(FileMatch, null, null, null, null, rawMatch); + return instantiationService.createInstance(FileMatch, null, null, null, null, rawMatch, null); } function aMatch(fileMatch: FileMatch): Match { diff --git a/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts b/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts index 41a1754d7c0..d003bb48d85 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts @@ -168,7 +168,7 @@ suite('Search - Viewlet', () => { resource: createFileUriFromPathFromRoot(path), results: lineMatches }; - return instantiation.createInstance(FileMatch, null, null, null, parentFolder, rawMatch); + return instantiation.createInstance(FileMatch, null, null, null, parentFolder, rawMatch, parentFolder); } function aFolderMatch(path: string, index: number, parent?: SearchResult): FolderMatch { diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index 15ed87adcce..d9d8bcf32dd 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -471,7 +471,7 @@ suite('SearchResult', () => { resource: URI.file('/' + path), results: lineMatches }; - return instantiationService.createInstance(FileMatch, null, null, null, searchResult, rawMatch); + return instantiationService.createInstance(FileMatch, null, null, null, searchResult, rawMatch, searchResult); } function aSearchResult(): SearchResult { From 1a76ad9c8b03cd7d5a38e03d94facfd989471619 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 11:44:43 -0700 Subject: [PATCH 080/599] Allow free port to run on any command (single char+) --- .../contrib/terminal/browser/terminalBaseContextualActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts index ac913f849d1..f1749d995a0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts @@ -12,7 +12,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; -export const AnyCommandLineRegex = /.{4,}/; +export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /most similar command is\s+([^\s]{3,})/; export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; From ed1f954ae95e6ebb59863a18e40fab637edbc7af Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 12:05:30 -0700 Subject: [PATCH 081/599] update initialText in reused terminal before showing it (#161818) --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index c17ac12ef00..9f1e4c7ec18 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1709,6 +1709,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Print initialText if specified if (shell.initialText) { + this._shellLaunchConfig.initialText = shell.initialText; await new Promise(r => this._writeInitialText(xterm, r)); } From 6bbdabb960d38d24c151c53dab434ffea72a9cea Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 12:06:56 -0700 Subject: [PATCH 082/599] contextual action -> quick fix (#161638) --- .../contrib/terminal/browser/terminal.ts | 22 +++---- .../terminal/browser/terminalActions.ts | 2 +- .../terminal/browser/terminalInstance.ts | 24 +++---- ...s.ts => terminalQuickFixBuiltinActions.ts} | 32 +++++----- ...textualActionAddon.ts => quickFixAddon.ts} | 62 +++++++++--------- ...ionAddon.test.ts => quickFixAddon.test.ts} | 64 +++++++++---------- 6 files changed, 101 insertions(+), 105 deletions(-) rename src/vs/workbench/contrib/terminal/browser/{terminalBaseContextualActions.ts => terminalQuickFixBuiltinActions.ts} (75%) rename src/vs/workbench/contrib/terminal/browser/xterm/{contextualActionAddon.ts => quickFixAddon.ts} (75%) rename src/vs/workbench/contrib/terminal/test/browser/{contextualActionAddon.test.ts => quickFixAddon.test.ts} (71%) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 984098cd483..1b47d3e9cd8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -19,7 +19,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IEditableData } from 'vs/workbench/common/views'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; -import { IContextualAction } from 'vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon'; +import { ITerminalQuickFix } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IMarker } from 'xterm'; @@ -459,7 +459,7 @@ export interface ITerminalInstance { readonly statusList: ITerminalStatusList; - contextualActions: IContextualAction | undefined; + quickFix: ITerminalQuickFix | undefined; readonly findWidget: Lazy; @@ -912,25 +912,25 @@ export interface ITerminalInstance { openRecentLink(type: 'localFile' | 'url'): Promise; /** - * Registers contextual action listeners + * Registers quick fix providers */ - registerContextualActions(...options: ITerminalContextualActionOptions[]): void; + registerQuickFixProvider(...options: ITerminalQuickFixOptions[]): void; freePortKillProcess(port: string): Promise; } -export interface ITerminalContextualActionOptions { - actionName: string | DynamicActionName; +export interface ITerminalQuickFixOptions { + quickFixLabel: string | DynamicQuickFixLabel; commandLineMatcher: string | RegExp; outputMatcher?: ITerminalOutputMatcher; - getActions: ContextualActionCallback; + getQuickFixes: QuickFixCallback; exitStatus?: boolean; } -export type ContextualMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null }; -export type DynamicActionName = (matchResult: ContextualMatchResult) => string; -export type ContextualActionCallback = (matchResult: ContextualMatchResult, command: ITerminalCommand) => ICommandAction[] | undefined; +export type QuickFixMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null }; +export type DynamicQuickFixLabel = (matchResult: QuickFixMatchResult) => string; +export type QuickFixCallback = (matchResult: QuickFixMatchResult, command: ITerminalCommand) => ITerminalQuickFixAction[] | undefined; -export interface ICommandAction extends IAction { +export interface ITerminalQuickFixAction extends IAction { commandToRunInTerminal?: string; addNewLine?: boolean; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 1103c1a71ac..8cfc44e4247 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -159,7 +159,7 @@ export function registerTerminalActions() { }); } async run(accessor: ServicesAccessor) { - accessor.get(ITerminalService).activeInstance?.contextualActions?.showQuickFixMenu(); + accessor.get(ITerminalService).activeInstance?.quickFix?.showMenu(); } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 9f1e4c7ec18..543b6bc1514 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -60,9 +60,9 @@ import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/brows import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager'; import { TerminalLinkQuickpick } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick'; -import { IRequestAddInstanceToGroupEvent, ITerminalContextualActionOptions, ITerminalExternalLinkProvider, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { IRequestAddInstanceToGroupEvent, ITerminalQuickFixOptions, ITerminalExternalLinkProvider, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; -import { gitSimilarCommand, gitCreatePr, gitPushSetUpstream, freePort } from 'vs/workbench/contrib/terminal/browser/terminalBaseContextualActions'; +import { gitSimilarCommand, gitCreatePr, gitPushSetUpstream, freePort } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; @@ -74,7 +74,7 @@ import { TypeAheadAddon } from 'vs/workbench/contrib/terminal/browser/terminalTy import { getTerminalResourcesFromDragEvent, getTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri'; import { EnvironmentVariableInfoWidget } from 'vs/workbench/contrib/terminal/browser/widgets/environmentVariableInfoWidget'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager'; -import { ContextualActionAddon, IContextualAction } from 'vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon'; +import { ITerminalQuickFix, TerminalQuickFixAddon } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { LineDataEventAddon } from 'vs/workbench/contrib/terminal/browser/xterm/lineDataEventAddon'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/xterm/navigationModeAddon'; import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; @@ -207,7 +207,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _target?: TerminalLocation | undefined; private _disableShellIntegrationReporting: boolean | undefined; private _usedShellIntegrationInjection: boolean = false; - private _contextualActionAddon: ContextualActionAddon | undefined; + private _quickFixAddon: TerminalQuickFixAddon | undefined; readonly capabilities = new TerminalCapabilityStoreMultiplexer(); readonly statusList: ITerminalStatusList; @@ -216,7 +216,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { * Enables opening the contextual actions, if any, that are available * and registering of command finished listeners */ - get contextualActions(): IContextualAction | undefined { return this._contextualActionAddon; } + get quickFix(): ITerminalQuickFix | undefined { return this._quickFixAddon; } readonly findWidget: Lazy; @@ -610,9 +610,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return undefined; } - registerContextualActions(...actionOptions: ITerminalContextualActionOptions[]): void { - for (const actionOption of actionOptions) { - this.contextualActions?.registerCommandFinishedListener(actionOption); + registerQuickFixProvider(...options: ITerminalQuickFixOptions[]): void { + for (const actionOption of options) { + this.quickFix?.registerCommandFinishedListener(actionOption); } } @@ -728,10 +728,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const xterm = this._scopedInstantiationService.createInstance(XtermTerminal, Terminal, this._configHelper, this._cols, this._rows, this.target || TerminalLocation.Panel, this.capabilities, this.disableShellIntegrationReporting); this.xterm = xterm; - this._contextualActionAddon = this._scopedInstantiationService.createInstance(ContextualActionAddon, this.capabilities); - this.xterm?.raw.loadAddon(this._contextualActionAddon); - this.registerContextualActions(gitSimilarCommand(), gitCreatePr(this._openerService), gitPushSetUpstream(), freePort(this)); - this._register(this._contextualActionAddon.onDidRequestRerunCommand((e) => this.sendText(e.command, e.addNewLine || false))); + this._quickFixAddon = this._scopedInstantiationService.createInstance(TerminalQuickFixAddon, this.capabilities); + this.xterm?.raw.loadAddon(this._quickFixAddon); + this.registerQuickFixProvider(gitSimilarCommand(), gitCreatePr(this._openerService), gitPushSetUpstream(), freePort(this)); + this._register(this._quickFixAddon.onDidRequestRerunCommand((e) => this.sendText(e.command, e.addNewLine || false))); const lineDataEventAddon = new LineDataEventAddon(); this.xterm.raw.loadAddon(lineDataEventAddon); this.updateAccessibilitySupport(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts similarity index 75% rename from src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts rename to src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index ac913f849d1..af93014472b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalBaseContextualActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -7,7 +7,7 @@ import { IAction } from 'vs/base/common/actions'; import { isWindows } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { ContextualMatchResult, ICommandAction, ITerminalContextualActionOptions, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { QuickFixMatchResult, ITerminalQuickFixAction, ITerminalQuickFixOptions, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; export const GitCommandLineRegex = /git/; @@ -18,19 +18,19 @@ export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\ export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s+remote:\s+(https:.+pull.+)/; -export function gitSimilarCommand(): ITerminalContextualActionOptions { +export function gitSimilarCommand(): ITerminalQuickFixOptions { return { commandLineMatcher: GitCommandLineRegex, + quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Run git ${matchResult.outputMatch[1]}` : ``, outputMatcher: { lineMatcher: GitSimilarOutputRegex, anchor: 'bottom', offset: 0, length: 3 }, - actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Run git ${matchResult.outputMatch[1]}` : ``, exitStatus: false, - getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { - const actions: ICommandAction[] = []; + getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { + const actions: ITerminalQuickFixAction[] = []; const fixedCommand = matchResult?.outputMatch?.[1]; if (!fixedCommand) { return; @@ -46,9 +46,9 @@ export function gitSimilarCommand(): ITerminalContextualActionOptions { } }; } -export function freePort(terminalInstance?: Partial): ITerminalContextualActionOptions { +export function freePort(terminalInstance?: Partial): ITerminalQuickFixOptions { return { - actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '', + quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '', commandLineMatcher: AnyCommandLineRegex, // TODO: Support free port on Windows https://github.com/microsoft/vscode/issues/161775 outputMatcher: isWindows ? undefined : { @@ -58,12 +58,12 @@ export function freePort(terminalInstance?: Partial): ITermin length: 20 }, exitStatus: false, - getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { + getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { const port = matchResult?.outputMatch?.[1]; if (!port) { return; } - const actions: ICommandAction[] = []; + const actions: ITerminalQuickFixAction[] = []; const label = localize("terminal.freePort", "Free port {0}", port); actions.push({ class: undefined, tooltip: label, id: 'terminal.freePort', label, enabled: true, @@ -77,9 +77,9 @@ export function freePort(terminalInstance?: Partial): ITermin } }; } -export function gitPushSetUpstream(): ITerminalContextualActionOptions { +export function gitPushSetUpstream(): ITerminalQuickFixOptions { return { - actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Git push ${matchResult.outputMatch[1]}` : '', + quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Git push ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, outputMatcher: { lineMatcher: GitPushOutputRegex, @@ -88,12 +88,12 @@ export function gitPushSetUpstream(): ITerminalContextualActionOptions { length: 5 }, exitStatus: false, - getActions: (matchResult: ContextualMatchResult, command: ITerminalCommand) => { + getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { const branch = matchResult?.outputMatch?.[1]; if (!branch) { return; } - const actions: ICommandAction[] = []; + const actions: ITerminalQuickFixAction[] = []; const label = localize("terminal.gitPush", "Git push {0}", branch); command.command = `git push --set-upstream origin ${branch}`; actions.push({ @@ -107,9 +107,9 @@ export function gitPushSetUpstream(): ITerminalContextualActionOptions { }; } -export function gitCreatePr(openerService: IOpenerService): ITerminalContextualActionOptions { +export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOptions { return { - actionName: (matchResult: ContextualMatchResult) => matchResult.outputMatch ? `Create PR for ${matchResult.outputMatch[1]}` : '', + quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Create PR for ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, outputMatcher: { lineMatcher: GitCreatePrOutputRegex, @@ -118,7 +118,7 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalContextualA length: 5 }, exitStatus: true, - getActions: (matchResult: ContextualMatchResult, command?: ITerminalCommand) => { + getQuickFixes: (matchResult: QuickFixMatchResult, command?: ITerminalCommand) => { if (!command) { return; } diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts similarity index 75% rename from src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts rename to src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index abc6b021419..8b4cd8735f0 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -10,30 +10,26 @@ import { ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from ' import type { ITerminalAddon } from 'xterm-headless'; import * as dom from 'vs/base/browser/dom'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ICommandAction, ITerminalContextualActionOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalQuickFixAction, ITerminalQuickFixOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Terminal, IDecoration } from 'xterm'; import { IAction } from 'vs/base/common/actions'; -export interface IContextualAction { - /** - * Shows the quick fix menu - */ - showQuickFixMenu(): void; - +export interface ITerminalQuickFix { + showMenu(): void; /** * Registers a listener on onCommandFinished scoped to a particular command or regular * expression and provides a callback to be executed for commands that match. */ - registerCommandFinishedListener(options: ITerminalContextualActionOptions): void; + registerCommandFinishedListener(options: ITerminalQuickFixOptions): void; } -export interface IContextualActionAdddon extends IContextualAction { +export interface ITerminalQuickFixAddon extends ITerminalQuickFix { onDidRequestRerunCommand: Event<{ command: string; addNewLine?: boolean }>; } -export class ContextualActionAddon extends Disposable implements ITerminalAddon, IContextualActionAdddon { +export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, ITerminalQuickFixAddon { private readonly _onDidRequestRerunCommand = new Emitter<{ command: string; addNewLine?: boolean }>(); readonly onDidRequestRerunCommand = this._onDidRequestRerunCommand.event; @@ -43,9 +39,9 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, private _decorationMarkerIds = new Set(); - private _commandListeners: Map = new Map(); + private _commandListeners: Map = new Map(); - private _matchActions: ICommandAction[] | undefined; + private _quickFixes: ITerminalQuickFixAction[] | undefined; private _decoration: IDecoration | undefined; @@ -68,11 +64,11 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, this._terminal = terminal; } - showQuickFixMenu(): void { + showMenu(): void { this._currentQuickFixElement?.click(); } - registerCommandFinishedListener(options: ITerminalContextualActionOptions): void { + registerCommandFinishedListener(options: ITerminalQuickFixOptions): void { const matcherKey = options.commandLineMatcher.toString(); const currentOptions = this._commandListeners.get(matcherKey) || []; currentOptions.push(options); @@ -92,15 +88,15 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, this._register(commandDetection.onCommandFinished(async command => { this._decoration?.dispose(); this._decoration = undefined; - this._matchActions = getMatchActions(command, this._commandListeners, this._onDidRequestRerunCommand); + this._quickFixes = getQuickFixes(command, this._commandListeners, this._onDidRequestRerunCommand); })); // The buffer is not ready by the time command finish // is called. Add the decoration on command start using the actions, if any, // from the last command this._register(commandDetection.onCommandStarted(() => { - if (this._matchActions) { + if (this._quickFixes) { this._registerContextualDecoration(); - this._matchActions = undefined; + this._quickFixes = undefined; } })); } @@ -113,7 +109,7 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, if (!marker) { return; } - const actions = this._matchActions; + const actions = this._quickFixes; const decoration = this._terminal.registerDecoration({ marker, layer: 'top' }); this._decoration = decoration; decoration?.onRender((e: HTMLElement) => { @@ -134,8 +130,8 @@ export class ContextualActionAddon extends Disposable implements ITerminalAddon, } } -export function getMatchActions(command: ITerminalCommand, actionOptions: Map, onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }>): IAction[] | undefined { - const matchActions: IAction[] = []; +export function getQuickFixes(command: ITerminalCommand, actionOptions: Map, onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }>): IAction[] | undefined { + const actions: IAction[] = []; const newCommand = command.command; for (const options of actionOptions.values()) { for (const actionOption of options) { @@ -151,25 +147,25 @@ export function getMatchActions(command: ITerminalCommand, actionOptions: Map { - await a.run(); - if (a.commandToRunInTerminal) { - onDidRequestRerunCommand?.fire({ command: a.commandToRunInTerminal, addNewLine: a.addNewLine }); + await quickFix.run(); + if (quickFix.commandToRunInTerminal) { + onDidRequestRerunCommand?.fire({ command: quickFix.commandToRunInTerminal, addNewLine: quickFix.addNewLine }); } }, - tooltip: a.tooltip + tooltip: quickFix.tooltip }); } } } } - return matchActions.length === 0 ? undefined : matchActions; + return actions.length === 0 ? undefined : actions; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts similarity index 71% rename from src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts rename to src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index a8413116d28..6ea4fb09962 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/contextualActionAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -14,13 +14,13 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; -import { ICommandAction, ITerminalInstance, ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalBaseContextualActions'; -import { ContextualActionAddon, getMatchActions } from 'vs/workbench/contrib/terminal/browser/xterm/contextualActionAddon'; +import { ITerminalQuickFixAction, ITerminalInstance, ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; +import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { Terminal } from 'xterm'; -suite('ContextualActionAddon', () => { - let contextualActionAddon: ContextualActionAddon; +suite('QuickFixAddon', () => { + let quickFixAddon: TerminalQuickFixAddon; let terminalInstance: Pick; let commandDetection: CommandDetectionCapability; let openerService: OpenerService; @@ -41,8 +41,8 @@ suite('ContextualActionAddon', () => { terminalInstance = { async freePortKillProcess(port: string): Promise { } } as Pick; - contextualActionAddon = instantiationService.createInstance(ContextualActionAddon, capabilities); - xterm.loadAddon(contextualActionAddon); + quickFixAddon = instantiationService.createInstance(TerminalQuickFixAddon, capabilities); + xterm.loadAddon(quickFixAddon); }); suite('registerCommandFinishedListener & getMatchActions', () => { suite('gitSimilarCommand', async () => { @@ -65,22 +65,22 @@ suite('ContextualActionAddon', () => { setup(() => { const command = gitSimilarCommand(); expectedMap.set(command.commandLineMatcher.toString(), [command]); - contextualActionAddon.registerCommandFinishedListener(command); + quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getMatchActions(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap), undefined); }); test('command does not match', () => { - strictEqual(getMatchActions(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap), undefined); }); }); suite('returns undefined when', () => { test('expected unix exit code', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap), actions); }); test('matching exit status', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap), actions); }); }); }); @@ -112,15 +112,15 @@ suite('ContextualActionAddon', () => { setup(() => { const command = freePort(terminalInstance); expected.set(command.commandLineMatcher.toString(), [command]); - contextualActionAddon.registerCommandFinishedListener(command); + quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getMatchActions(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); + strictEqual(getQuickFixes(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); }); }); test('returns actions', () => { - assertMatchOptions(getMatchActions(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); + assertMatchOptions(getQuickFixes(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); }); }); } @@ -145,22 +145,22 @@ suite('ContextualActionAddon', () => { setup(() => { const command = gitPushSetUpstream(); expectedMap.set(command.commandLineMatcher.toString(), [command]); - contextualActionAddon.registerCommandFinishedListener(command); + quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getMatchActions(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); }); test('command does not match', () => { - strictEqual(getMatchActions(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); }); test('matching exit status', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); }); }); }); @@ -188,22 +188,22 @@ suite('ContextualActionAddon', () => { setup(() => { const command = gitCreatePr(openerService); expectedMap.set(command.commandLineMatcher.toString(), [command]); - contextualActionAddon.registerCommandFinishedListener(command); + quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getMatchActions(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); }); test('command does not match', () => { - strictEqual(getMatchActions(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); }); test('failure exit status', () => { - strictEqual(getMatchActions(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap), actions); }); }); }); @@ -228,24 +228,24 @@ suite('ContextualActionAddon', () => { setup(() => { const pushCommand = gitPushSetUpstream(); const prCommand = gitCreatePr(openerService); - contextualActionAddon.registerCommandFinishedListener(pushCommand); - contextualActionAddon.registerCommandFinishedListener(prCommand); + quickFixAddon.registerCommandFinishedListener(pushCommand); + quickFixAddon.registerCommandFinishedListener(prCommand); expectedMap.set(pushCommand.commandLineMatcher.toString(), [pushCommand, prCommand]); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getMatchActions(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); }); test('command does not match', () => { - strictEqual(getMatchActions(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); }); test('matching exit status', () => { - assertMatchOptions(getMatchActions(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); }); }); }); @@ -267,7 +267,7 @@ function createCommand(command: string, output: string, outputMatcher?: RegExp | }; } -function assertMatchOptions(actual: ICommandAction[] | undefined, expected: { id: string; label: string; run: boolean; tooltip: string; enabled: boolean }[]): void { +function assertMatchOptions(actual: ITerminalQuickFixAction[] | undefined, expected: { id: string; label: string; run: boolean; tooltip: string; enabled: boolean }[]): void { strictEqual(actual?.length, expected.length); let index = 0; for (const i of actual) { From 9ccd1bec74ffd9adff24e3a9c2ec3b980a2d3ddd Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 12:07:15 -0700 Subject: [PATCH 083/599] don't try shell integration for winpty (#161821) fix #160419 --- src/vs/platform/terminal/node/terminalEnvironment.ts | 4 ++-- src/vs/platform/terminal/node/terminalProcess.ts | 2 +- .../terminal/test/node/terminalEnvironment.test.ts | 11 +++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index 5e7b1f2d93f..9ff09c4322e 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -104,7 +104,7 @@ export interface IShellIntegrationConfigInjection { */ export function getShellIntegrationInjection( shellLaunchConfig: IShellLaunchConfig, - options: ITerminalProcessOptions['shellIntegration'], + options: Pick, env: ITerminalEnvironment | undefined, logService: ILogService, productService: IProductService @@ -113,7 +113,7 @@ export function getShellIntegrationInjection( // - The global setting is disabled // - There is no executable (not sure what script to run) // - The terminal is used by a feature like tasks or debugging - if (!options.enabled || !shellLaunchConfig.executable || shellLaunchConfig.isFeatureTerminal || shellLaunchConfig.hideFromUser || shellLaunchConfig.ignoreShellIntegration) { + if (!options.shellIntegration.enabled || !shellLaunchConfig.executable || shellLaunchConfig.isFeatureTerminal || shellLaunchConfig.hideFromUser || shellLaunchConfig.ignoreShellIntegration || (isWindows && !options.windowsEnableConpty)) { return undefined; } diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 253b8dc7192..9a670fda3e8 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -201,7 +201,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess let injection: IShellIntegrationConfigInjection | undefined; if (this._options.shellIntegration.enabled) { - injection = getShellIntegrationInjection(this.shellLaunchConfig, this._options.shellIntegration, this._ptyOptions.env, this._logService, this._productService); + injection = getShellIntegrationInjection(this.shellLaunchConfig, { shellIntegration: this._options.shellIntegration, windowsEnableConpty: this._options.windowsEnableConpty }, this._ptyOptions.env, this._logService, this._productService); if (injection) { this._onDidChangeProperty.fire({ type: ProcessPropertyType.UsedShellIntegrationInjection, value: true }); if (injection.envMixin) { diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index f48c05e2fe2..3ddda6e00d7 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -5,13 +5,15 @@ import { deepStrictEqual, ok, strictEqual } from 'assert'; import { homedir, userInfo } from 'os'; +import { isWindows } from 'vs/base/common/platform'; import { NullLogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; import { getShellIntegrationInjection, IShellIntegrationConfigInjection } from 'vs/platform/terminal/node/terminalEnvironment'; -const enabledProcessOptions: ITerminalProcessOptions['shellIntegration'] = { enabled: true }; -const disabledProcessOptions: ITerminalProcessOptions['shellIntegration'] = { enabled: false }; +const enabledProcessOptions: Pick = { shellIntegration: { enabled: true }, windowsEnableConpty: true }; +const disabledProcessOptions: Pick = { shellIntegration: { enabled: false }, windowsEnableConpty: true }; +const winptyProcessOptions: Pick = { shellIntegration: { enabled: true }, windowsEnableConpty: false }; const pwshExe = process.platform === 'win32' ? 'pwsh.exe' : 'pwsh'; const repoRoot = process.platform === 'win32' ? process.cwd()[0].toLowerCase() + process.cwd().substring(1) : process.cwd(); const logService = new NullLogService(); @@ -25,6 +27,11 @@ suite('platform - terminalEnvironment', () => { ok(!getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: true }, enabledProcessOptions, defaultEnvironment, logService, productService)); ok(getShellIntegrationInjection({ executable: pwshExe, args: ['-l', '-NoLogo'], isFeatureTerminal: false }, enabledProcessOptions, defaultEnvironment, logService, productService)); }); + if (isWindows) { + test('when on windows with conpty false', () => { + ok(!getShellIntegrationInjection({ executable: pwshExe, args: ['-l'], isFeatureTerminal: false }, winptyProcessOptions, defaultEnvironment, logService, productService)); + }); + } }); suite('pwsh', () => { From 045bed876d43c50635bbab06dbf71ee8de5c8a3b Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 26 Sep 2022 12:13:05 -0700 Subject: [PATCH 084/599] Fixes #161725 (#161826) --- .../electron-sandbox/localization.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts index cc72bb49812..3adcf5734b8 100644 --- a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts +++ b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts @@ -123,11 +123,11 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo const loc = manifest && manifest.contributes && manifest.contributes.localizations && manifest.contributes.localizations.filter(x => x.languageId.toLowerCase() === locale)[0]; const languageName = loc ? (loc.languageName || locale) : locale; const languageDisplayName = loc ? (loc.localizedLanguageName || loc.languageName || locale) : locale; - const translationsFromPack: any = translation && translation.contents ? translation.contents['vs/workbench/contrib/localization/electron-sandbox/minimalTranslations'] : {}; + const translationsFromPack: { [key: string]: string } = translation?.contents?.['vs/workbench/contrib/localization/electron-sandbox/minimalTranslations'] ?? {}; const promptMessageKey = extensionToInstall ? 'installAndRestartMessage' : 'showLanguagePackExtensions'; const useEnglish = !translationsFromPack[promptMessageKey]; - const translations: any = {}; + const translations: { [key: string]: string } = {}; Object.keys(minimumTranslatedStrings).forEach(key => { if (!translationsFromPack[key] || useEnglish) { translations[key] = minimumTranslatedStrings[key].replace('{0}', languageName); From bcbf0d81275f2a5fa9df2acacb0fbf3ab64a6c24 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 26 Sep 2022 12:15:12 -0700 Subject: [PATCH 085/599] Fix NotebookEditorModel#isResolved. Fix #161049. (#161829) --- src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 362123693b2..34479ba1115 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -473,7 +473,7 @@ export class SimpleNotebookEditorModel extends EditorModel implements INotebookE } override isResolved(): this is IResolvedNotebookEditorModel { - return Boolean(this._workingCopy); + return Boolean(this._workingCopy?.model?.notebookModel); } isDirty(): boolean { From 34d8743176b9cd7e0b7a747f171249f17d2f2cf0 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 26 Sep 2022 21:24:02 +0200 Subject: [PATCH 086/599] Improves merge editor code-lens (#161830) * Disable diff projection * Improves merge editor code-lens --- .../browser/mergeEditorInputModel.ts | 5 +- .../browser/view/conflictActions.ts | 312 ++++++++++++ .../browser/view/editors/codeEditorView.ts | 5 - .../view/editors/inputCodeEditorView.ts | 146 ------ .../view/editors/resultCodeEditorView.ts | 162 +------ .../browser/view/media/mergeEditor.css | 43 ++ .../mergeEditor/browser/view/mergeEditor.ts | 445 +++++++++++------- .../browser/view/scrollSynchronizer.ts | 102 ++-- 8 files changed, 694 insertions(+), 526 deletions(-) create mode 100644 src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index 4ef67a9d65a..1d0580d8e6b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -23,7 +23,6 @@ import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeDiffComputer } from 'vs/workbench/contrib/mergeEditor/browser/model/diffComputer'; import { InputData, MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel'; -import { ProjectedDiffComputer } from 'vs/workbench/contrib/mergeEditor/browser/model/projectedDocumentDiffProvider'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileEditorModel, ITextFileSaveOptions, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -109,7 +108,7 @@ export class TempFileMergeEditorModeFactory implements IMergeEditorInputModelFac input2Data, temporaryResultModel, this._instantiationService.createInstance(MergeDiffComputer, diffProvider), - this._instantiationService.createInstance(MergeDiffComputer, this._instantiationService.createInstance(ProjectedDiffComputer, diffProvider)), + this._instantiationService.createInstance(MergeDiffComputer, diffProvider), { resetResult: true, } @@ -312,7 +311,7 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa input2Data, result.object.textEditorModel, this._instantiationService.createInstance(MergeDiffComputer, diffProvider), - this._instantiationService.createInstance(MergeDiffComputer, this._instantiationService.createInstance(ProjectedDiffComputer, diffProvider)), + this._instantiationService.createInstance(MergeDiffComputer, diffProvider), { resetResult: true } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts new file mode 100644 index 00000000000..f42b282024d --- /dev/null +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -0,0 +1,312 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { h, $, reset, createStyleSheet, isInShadowDOM } from 'vs/base/browser/dom'; +import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; +import { hash } from 'vs/base/common/hash'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { autorun, derived, IObservable, transaction } from 'vs/base/common/observable'; +import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { EditorOption, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { localize } from 'vs/nls'; +import { ModifiedBaseRange, ModifiedBaseRangeState } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; +import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; + +export class ConflictActionsFactory extends Disposable { + private id = 0; + private readonly _styleClassName: string; + private readonly _styleElement: HTMLStyleElement; + + constructor(private readonly _editor: ICodeEditor) { + super(); + + this._register(this._editor.onDidChangeConfiguration((e) => { + if (e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.codeLensFontSize) || e.hasChanged(EditorOption.codeLensFontFamily)) { + this._updateLensStyle(); + } + })); + + this._styleClassName = '_conflictActionsFactory_' + hash(this._editor.getId()).toString(16); + this._styleElement = createStyleSheet( + isInShadowDOM(this._editor.getContainerDomNode()) + ? this._editor.getContainerDomNode() + : undefined + ); + + this._register(toDisposable(() => { + this._styleElement.remove(); + })); + + this._updateLensStyle(); + } + + private _updateLensStyle(): void { + + const { codeLensHeight, fontSize } = this._getLayoutInfo(); + const fontFamily = this._editor.getOption(EditorOption.codeLensFontFamily); + const editorFontInfo = this._editor.getOption(EditorOption.fontInfo); + + const fontFamilyVar = `--codelens-font-family${this._styleClassName}`; + const fontFeaturesVar = `--codelens-font-features${this._styleClassName}`; + + let newStyle = ` + .${this._styleClassName} { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; padding-right: ${Math.round(fontSize * 0.5)}px; font-feature-settings: var(${fontFeaturesVar}) } + .monaco-workbench .${this._styleClassName} span.codicon { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; } + `; + if (fontFamily) { + newStyle += `${this._styleClassName} { font-family: var(${fontFamilyVar}), ${EDITOR_FONT_DEFAULTS.fontFamily}}`; + } + this._styleElement.textContent = newStyle; + this._editor.getContainerDomNode().style.setProperty(fontFamilyVar, fontFamily ?? 'inherit'); + this._editor.getContainerDomNode().style.setProperty(fontFeaturesVar, editorFontInfo.fontFeatureSettings); + } + + private _getLayoutInfo() { + const lineHeightFactor = Math.max(1.3, this._editor.getOption(EditorOption.lineHeight) / this._editor.getOption(EditorOption.fontSize)); + let fontSize = this._editor.getOption(EditorOption.codeLensFontSize); + if (!fontSize || fontSize < 5) { + fontSize = (this._editor.getOption(EditorOption.fontSize) * .9) | 0; + } + return { + fontSize, + codeLensHeight: (fontSize * lineHeightFactor) | 0, + }; + } + + createContentWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IContentWidget { + + function command(title: string, action: () => Promise): IContentWidgetAction { + return { + text: title, + action + }; + } + + const items = derived('items', reader => { + const state = viewModel.model.getState(modifiedBaseRange).read(reader); + const handled = viewModel.model.isHandled(modifiedBaseRange).read(reader); + const model = viewModel.model; + + const result: IContentWidgetAction[] = []; + + const inputData = inputNumber === 1 ? viewModel.model.input1 : viewModel.model.input2; + const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + + if (!modifiedBaseRange.isConflicting && handled && !showNonConflictingChanges) { + return []; + } + + const otherInputNumber = inputNumber === 1 ? 2 : 1; + + if (!state.conflicting && !state.isInputIncluded(inputNumber)) { + result.push( + !state.isInputIncluded(inputNumber) + ? command(localize('accept', "$(pass) Accept {0}", inputData.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(inputNumber, true), + true, + tx + ); + }); + }) + : command(localize('remove', "$(error) Remove ${0}", inputData.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(inputNumber, false), + true, + tx + ); + }); + }), + ); + + if (modifiedBaseRange.canBeCombined && state.isEmpty) { + result.push( + state.input1 && state.input2 + ? command(localize('removeBoth', "$(error) Remove Both"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + ModifiedBaseRangeState.default, + true, + tx + ); + }); + }) + : command(localize('acceptBoth', "$(pass) Accept Both"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state + .withInputValue(inputNumber, true) + .withInputValue(otherInputNumber, true), + true, + tx + ); + }); + }), + ); + } + } + return result; + }); + return new ActionsContentWidget((this.id++).toString(), this._styleClassName, lineNumber, items); + } + + createResultWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange): IContentWidget { + + function command(title: string, action: () => Promise): IContentWidgetAction { + return { + text: title, + action + }; + } + + const items = derived('items', reader => { + const state = viewModel.model.getState(modifiedBaseRange).read(reader); + const model = viewModel.model; + + const result: IContentWidgetAction[] = []; + + const stateLabel = ((state: ModifiedBaseRangeState): string => { + if (state.conflicting) { + return localize('manualResolution', "Manual Resolution"); + } else if (state.isEmpty) { + return localize('noChangesAccepted', 'No Changes Accepted'); + } else { + const labels = []; + if (state.input1) { + labels.push(model.input1.title); + } + if (state.input2) { + labels.push(model.input2.title); + } + if (state.input2First) { + labels.reverse(); + } + return `${labels.join(' + ')}`; + } + })(state); + + result.push({ + text: stateLabel, + action: async () => { }, + }); + + + const stateToggles: IContentWidgetAction[] = []; + if (state.input1) { + result.push(command(localize('remove', "$(error) Remove ${0}", model.input1.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(1, false), + true, + tx + ); + }); + }), + ); + } + if (state.input2) { + result.push(command(localize('remove', "$(error) Remove ${0}", model.input2.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(2, false), + true, + tx + ); + }); + }), + ); + } + if (state.input2First) { + stateToggles.reverse(); + } + result.push(...stateToggles); + + + + if (state.conflicting) { + result.push( + command(localize('resetToBase', "$(error) Reset to base"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + ModifiedBaseRangeState.default, + true, + tx + ); + }); + }) + ); + } + return result; + }); + return new ActionsContentWidget((this.id++).toString(), this._styleClassName, lineNumber, items); + } +} + + +interface IContentWidgetAction { + text: string; + hover?: string; + action: () => Promise; +} + +class ActionsContentWidget extends Disposable implements IContentWidget { + private readonly _domNode = h('div.merge-editor-conflict-actions').root; + + constructor( + private readonly id: string, + className: string, + private readonly lineNumber: number, + items: IObservable, + ) { + super(); + + this._domNode.classList.add(className); + + this._register(autorun('update commands', (reader) => { + const i = items.read(reader); + this.setState(i); + })); + } + + private setState(items: IContentWidgetAction[]) { + const children: HTMLElement[] = []; + let isFirst = true; + for (const item of items) { + if (isFirst) { + isFirst = false; + } else { + children.push($('span', undefined, '\u00a0|\u00a0')); + } + const title = renderLabelWithIcons(item.text); + children.push($('a', { title: item.hover, role: 'button', onclick: () => item.action() }, ...title)); + } + + reset(this._domNode, ...children); + } + + getId(): string { + return this.id; + } + + getDomNode(): HTMLElement { + return this._domNode; + } + + getPosition(): IContentWidgetPosition | null { + return { + position: { lineNumber: this.lineNumber, column: 1, }, + preference: [ContentWidgetPositionPreference.BELOW], + }; + } +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index 27b27b276fc..0a57fa548a9 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -64,11 +64,6 @@ export abstract class CodeEditorView extends Disposable { () => /** @description checkboxesVisible */ this.configurationService.getValue('mergeEditor.showCheckboxes') ?? true ); - protected readonly codeLensesVisible = observableFromEvent( - this.configurationService.onDidChangeConfiguration, - () => /** @description codeLensesVisible */ this.configurationService.getValue('mergeEditor.showCodeLenses') ?? false - ); - public readonly editor = this.instantiationService.createInstance( CodeEditorWidget, this.htmlElements.editor, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index 9ad16bf2105..f8ff9b1055b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -8,21 +8,16 @@ import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { Codicon } from 'vs/base/common/codicons'; -import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; import { autorun, autorunWithStore, derived, IObservable, ISettableObservable, ITransaction, observableValue, transaction } from 'vs/base/common/observable'; import { noBreakWhitespace } from 'vs/base/common/strings'; import { isDefined } from 'vs/base/common/types'; -import { URI } from 'vs/base/common/uri'; import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; -import { CodeLens, CodeLensProvider, Command } from 'vs/editor/common/languages'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; -import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { CodeLensContribution } from 'vs/editor/contrib/codelens/browser/codelensController'; import { localize } from 'vs/nls'; import { MenuId } from 'vs/platform/actions/common/actions'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -65,14 +60,6 @@ export class InputCodeEditorView extends CodeEditorView { }, 'update checkboxes') ); - this._register( - autorunWithStore((reader, store) => { - if (this.codeLensesVisible.read(reader)) { - store.add(instantiationService.createInstance(CodeLensPart, this)); - } - }, 'update code lens part') - ); - this._register( createSelectionsAutorun(this, (baseRange, viewModel) => viewModel.model.translateBaseRangeToInput(this.inputNumber, baseRange) @@ -216,143 +203,10 @@ export class InputCodeEditorView extends CodeEditorView { }); protected override getEditorContributions(): IEditorContributionDescription[] | undefined { - if (this.codeLensesVisible.get()) { - return undefined; - } return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); } } -class CodeLensPart extends Disposable { - public static commandCounter = 0; - - constructor( - inputCodeEditorView: InputCodeEditorView, - @ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService, - ) { - super(); - - const codeLensCommandId = `mergeEditor.codeLensCommandInput${CodeLensPart.commandCounter++}`; - this._register(CommandsRegistry.registerCommand(codeLensCommandId, (accessor, arg) => { - arg(); - })); - - function command(title: string, callback: () => Promise): Command { - return { - title, - id: codeLensCommandId, - arguments: [callback], - }; - } - - const codeLenses = derived<{ codeLenses: CodeLens[]; uri: URI } | undefined>('codeLenses', reader => { - const viewModel = inputCodeEditorView.viewModel.read(reader); - if (!viewModel) { - return undefined; - } - const model = viewModel.model; - const inputData = inputCodeEditorView.inputNumber === 1 ? viewModel.model.input1 : viewModel.model.input2; - - const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); - - return { - codeLenses: viewModel.model.modifiedBaseRanges.read(reader).flatMap(r => { - const range = r.getInputRange(inputCodeEditorView.inputNumber).toRange(); - - const handled = model.isHandled(r).read(reader); - const state = model.getState(r).read(reader); - const result: CodeLens[] = []; - - if (!r.isConflicting && handled && !showNonConflictingChanges) { - return []; - } - - if (!state.conflicting && !state.isInputIncluded(inputCodeEditorView.inputNumber)) { - result.push( - { - range, - command: - !state.isInputIncluded(inputCodeEditorView.inputNumber) - ? command(`$(pass) Accept ${inputData.title}`, async () => { - transaction((tx) => { - model.setState( - r, - state.withInputValue(inputCodeEditorView.inputNumber, true), - true, - tx - ); - }); - }) - : command(`$(error) Remove ${inputData.title}`, async () => { - transaction((tx) => { - model.setState( - r, - state.withInputValue(inputCodeEditorView.inputNumber, false), - true, - tx - ); - }); - }), - } - ); - - if (r.canBeCombined && state.isEmpty) { - result.push({ - range, - command: - state.input1 && state.input2 - ? command(`$(error) Remove Both`, async () => { - transaction((tx) => { - model.setState( - r, - ModifiedBaseRangeState.default, - true, - tx - ); - }); - }) - : command(`$(pass) Accept Both`, async () => { - transaction((tx) => { - model.setState( - r, - state - .withInputValue(inputCodeEditorView.inputNumber, true) - .withInputValue(inputCodeEditorView.otherInputNumber, true), - true, - tx - ); - }); - }), - }); - } - } - if (result.length === 0) { - result.push({ - range: range, - command: command(` `, async () => { }) - }); - } - return result; - }), - uri: inputData.textModel.uri - }; - }); - - const codeLensProvider: CodeLensProvider = { - onDidChange: Event.map(Event.fromObservable(codeLenses), () => codeLensProvider), - async provideCodeLenses(model, token) { - const result = codeLenses.get(); - if (!result || result.uri.toString() !== model.uri.toString()) { - return { lenses: [], dispose: () => { } }; - } - return { lenses: result.codeLenses, dispose: () => { } }; - } - }; - - this._register(languageFeaturesService.codeLensProvider.register({ pattern: '**/*' }, codeLensProvider)); - } -} - export class ModifiedBaseRangeGutterItemModel implements IGutterItemInfo { private readonly model = this.viewModel.model; public readonly range = this.baseRange.getInputRange(this.inputNumber); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index 82c2ff6d315..eb56c55a996 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -7,23 +7,17 @@ import { reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { CompareResult } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; -import { Event } from 'vs/base/common/event'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { autorun, autorunWithStore, derived, IObservable, transaction } from 'vs/base/common/observable'; -import { URI } from 'vs/base/common/uri'; -import { CodeLens, CodeLensProvider, Command } from 'vs/editor/common/languages'; +import { toDisposable } from 'vs/base/common/lifecycle'; +import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; -import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { localize } from 'vs/nls'; import { MenuId } from 'vs/platform/actions/common/actions'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { MergeMarkersController } from 'vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController'; import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange'; -import { ModifiedBaseRangeState } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; import { applyObservableDecorations, join } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors'; import { EditorGutter } from 'vs/workbench/contrib/mergeEditor/browser/view/editorGutter'; @@ -49,14 +43,6 @@ export class ResultCodeEditorView extends CodeEditorView { this._register(new MergeMarkersController(this.editor, this.viewModel)); - this._register( - autorunWithStore((reader, store) => { - if (this.codeLensesVisible.read(reader)) { - store.add(instantiationService.createInstance(CodeLensPart, this)); - } - }, 'update code lens part') - ); - this.htmlElements.gutterDiv.style.width = '5px'; this._register( @@ -219,147 +205,3 @@ export class ResultCodeEditorView extends CodeEditorView { return result; }); } - -class CodeLensPart extends Disposable { - public static commandCounter = 0; - - constructor( - resultCodeEditorView: ResultCodeEditorView, - @ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService, - ) { - super(); - - const codeLensCommandId = `mergeEditor.codeLensCommandResult${CodeLensPart.commandCounter++}`; - this._register(CommandsRegistry.registerCommand(codeLensCommandId, (accessor, arg) => { - arg(); - })); - - function command(title: string, callback: () => Promise): Command { - return { - title, - id: codeLensCommandId, - arguments: [callback], - }; - } - - const codeLenses = derived<{ codeLenses: CodeLens[]; uri: URI } | undefined>('codeLenses', reader => { - const viewModel = resultCodeEditorView.viewModel.read(reader); - if (!viewModel) { - return undefined; - } - const model = viewModel.model; - const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); - - return { - codeLenses: viewModel.model.modifiedBaseRanges.read(reader).flatMap(r => { - const range = model.getLineRangeInResult(r.baseRange, reader).toRange(); - - const handled = model.isHandled(r).read(reader); - const state = model.getState(r).read(reader); - const result: CodeLens[] = []; - - if (!r.isConflicting && handled && !showNonConflictingChanges) { - return []; - } - - const stateLabel = ((state: ModifiedBaseRangeState): string => { - if (state.conflicting) { - return '= Manual Resolution'; - } else if (state.isEmpty) { - return '= Base'; - } else { - const labels = []; - if (state.input1) { - labels.push(model.input1.title); - } - if (state.input2) { - labels.push(model.input2.title); - } - return `= ${labels.join(' + ')}`; - } - })(state); - - result.push({ - range, - command: { - title: stateLabel, - id: 'notSupported', - } - }); - - - const stateToggles: CodeLens[] = []; - if (state.input1) { - result.push({ - range, - command: command(`$(error) Remove ${model.input1.title}`, async () => { - transaction((tx) => { - model.setState( - r, - state.withInputValue(1, false), - true, - tx - ); - }); - }), - }); - } - if (state.input2) { - result.push({ - range, - command: command(`$(error) Remove ${model.input2.title}`, async () => { - transaction((tx) => { - model.setState( - r, - state.withInputValue(2, false), - true, - tx - ); - }); - }), - }); - } - if (state.input2First) { - stateToggles.reverse(); - } - result.push(...stateToggles); - - - - if (state.conflicting) { - result.push( - { - range, - command: command(`$(error) Reset to base`, async () => { - transaction((tx) => { - model.setState( - r, - ModifiedBaseRangeState.default, - true, - tx - ); - }); - }) - } - ); - } - return result; - }), - uri: model.resultTextModel.uri, - }; - }); - - const codeLensProvider: CodeLensProvider = { - onDidChange: Event.map(Event.fromObservable(codeLenses), () => codeLensProvider), - async provideCodeLenses(model, token) { - const result = codeLenses.get(); - if (!result || result.uri.toString() !== model.uri.toString()) { - return { lenses: [], dispose: () => { } }; - } - return { lenses: result.codeLenses, dispose: () => { } }; - } - }; - - this._register(languageFeaturesService.codeLensProvider.register({ pattern: '**/*' }, codeLensProvider)); - } -} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css index c105dd827fb..684f8bad077 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css @@ -229,3 +229,46 @@ .merge-conflict-input-selection { background-color: red; } + +.merge-editor-conflict-actions { + margin: -4px 3px; +} + +.merge-editor-conflict-actions { + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--vscode-editorCodeLens-foreground) +} + +.merge-editor-conflict-actions>span, +.merge-editor-conflict-actions>a { + user-select: none; + -webkit-user-select: none; + white-space: nowrap; + vertical-align: sub; +} + +.merge-editor-conflict-actions>a { + text-decoration: none; +} + +.merge-editor-conflict-actions>a:hover { + cursor: pointer; + color: var(--vscode-editorLink-activeForeground) !important; +} + +.merge-editor-conflict-actions>a:hover .codicon { + color: var(--vscode-editorLink-activeForeground) !important; +} + +.merge-editor-conflict-actions .codicon { + vertical-align: middle; + color: currentColor !important; + color: var(--vscode-editorCodeLens-foreground); +} + +.merge-editor-conflict-actions>a:hover .codicon::before { + cursor: pointer; +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index b956e502130..7793c56b344 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -11,8 +11,8 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Color } from 'vs/base/common/color'; import { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { autorun, autorunWithStore, IObservable, IReader, observableValue, transaction } from 'vs/base/common/observable'; +import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { autorun, autorunWithStore, IObservable, IReader, observableFromEvent, observableValue, transaction } from 'vs/base/common/observable'; import { basename, isEqual } from 'vs/base/common/resources'; import { isDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -46,12 +46,13 @@ import { deepMerge, join, PersistentStore, thenIfNotDisposed } from 'vs/workbenc import { BaseCodeEditorView } from 'vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView'; import { ScrollSynchronizer } from 'vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; -import { ctxIsMergeEditor, ctxMergeBaseUri, ctxMergeEditorLayout, ctxMergeEditorShowBase, ctxMergeEditorShowNonConflictingChanges, ctxMergeResultUri, MergeEditorLayoutKind } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; +import { ctxIsMergeEditor, ctxMergeBaseUri, ctxMergeEditorLayout, ctxMergeEditorShowBase, ctxMergeEditorShowBaseAtTop, ctxMergeEditorShowNonConflictingChanges, ctxMergeResultUri, MergeEditorLayoutKind } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorResolverService, MergeEditorInputFactoryFunction, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import './colors'; +import { ConflictActionsFactory } from './conflictActions'; import { InputCodeEditorView } from './editors/inputCodeEditorView'; import { ResultCodeEditorView } from './editors/resultCodeEditorView'; import { getAlignments } from './lineAlignment'; @@ -77,12 +78,13 @@ export class MergeEditor extends AbstractTextEditor { private readonly inputResultView = this._register(this.instantiationService.createInstance(ResultCodeEditorView, this._viewModel)); private readonly _layoutMode = this.instantiationService.createInstance(MergeEditorLayoutStore); private readonly _layoutModeObs = observableValue('layoutMode', this._layoutMode.value); - private readonly _ctxIsMergeEditor: IContextKey; - private readonly _ctxUsesColumnLayout: IContextKey; - private readonly _ctxShowBase: IContextKey; - private readonly _ctxResultUri: IContextKey; - private readonly _ctxBaseUri: IContextKey; - private readonly _ctxShowNonConflictingChanges: IContextKey; + private readonly _ctxIsMergeEditor: IContextKey = ctxIsMergeEditor.bindTo(this.contextKeyService); + private readonly _ctxUsesColumnLayout: IContextKey = ctxMergeEditorLayout.bindTo(this.contextKeyService); + private readonly _ctxShowBase: IContextKey = ctxMergeEditorShowBase.bindTo(this.contextKeyService); + private readonly _ctxShowBaseAtTop = ctxMergeEditorShowBaseAtTop.bindTo(this.contextKeyService); + private readonly _ctxResultUri: IContextKey = ctxMergeResultUri.bindTo(this.contextKeyService); + private readonly _ctxBaseUri: IContextKey = ctxMergeBaseUri.bindTo(this.contextKeyService); + private readonly _ctxShowNonConflictingChanges: IContextKey = ctxMergeEditorShowNonConflictingChanges.bindTo(this.contextKeyService); private readonly _inputModel = observableValue('inputModel', undefined); public get inputModel(): IObservable { return this._inputModel; @@ -95,9 +97,20 @@ export class MergeEditor extends AbstractTextEditor { return !!this._configurationService.getValue('mergeEditor.writableInputs'); } + private readonly conflictActionsFactoryInput1 = new ConflictActionsFactory(this.input1View.editor); + private readonly conflictActionsFactoryInput2 = new ConflictActionsFactory(this.input2View.editor); + private readonly conflictActionsFactoryResult = new ConflictActionsFactory(this.inputResultView.editor); + + protected readonly codeLensesVisible = observableFromEvent( + this.configurationService.onDidChangeConfiguration, + () => /** @description codeLensesVisible */ this.configurationService.getValue('mergeEditor.showCodeLenses') ?? false + ); + + private readonly scrollSynchronizer = this._register(new ScrollSynchronizer(this._viewModel, this.input1View, this.input2View, this.baseView, this.inputResultView, this._layoutModeObs)); + constructor( @IInstantiationService instantiation: IInstantiationService, - @IContextKeyService contextKeyService: IContextKeyService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, @ITelemetryService telemetryService: ITelemetryService, @IStorageService storageService: IStorageService, @IThemeService themeService: IThemeService, @@ -107,17 +120,9 @@ export class MergeEditor extends AbstractTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @IFileService fileService: IFileService, @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(MergeEditor.ID, telemetryService, instantiation, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService, fileService); - - this._ctxIsMergeEditor = ctxIsMergeEditor.bindTo(contextKeyService); - this._ctxUsesColumnLayout = ctxMergeEditorLayout.bindTo(contextKeyService); - this._ctxBaseUri = ctxMergeBaseUri.bindTo(contextKeyService); - this._ctxResultUri = ctxMergeResultUri.bindTo(contextKeyService); - this._ctxShowBase = ctxMergeEditorShowBase.bindTo(contextKeyService); - this._ctxShowNonConflictingChanges = ctxMergeEditorShowNonConflictingChanges.bindTo(contextKeyService); - - this._register(new ScrollSynchronizer(this._viewModel, this.input1View, this.input2View, this.baseView, this.inputResultView)); } override dispose(): void { @@ -212,69 +217,55 @@ export class MergeEditor extends AbstractTextEditor { this._ctxResultUri.reset(); })); + // Set the view zones before restoring view state! // Otherwise scrolling will be off this._sessionDisposables.add(autorunWithStore((reader, store) => { - const input1ViewZoneIds: string[] = []; - const input2ViewZoneIds: string[] = []; - const baseViewZoneIds: string[] = []; - const resultViewZoneIds: string[] = []; const baseView = this.baseView.read(reader); this.inputResultView.editor.changeViewZones(resultViewZoneAccessor => { - const actualResultViewZoneAccessor = this._layoutModeObs.read(reader).kind === 'columns' ? resultViewZoneAccessor : undefined; + const layout = this._layoutModeObs.read(reader); + const shouldAlignResult = layout.kind === 'columns'; + const shouldAlignBase = layout.kind === 'mixed' && !layout.showBaseAtTop; this.input1View.editor.changeViewZones(input1ViewZoneAccessor => { this.input2View.editor.changeViewZones(input2ViewZoneAccessor => { if (baseView) { baseView.editor.changeViewZones(baseViewZoneAccessor => { - setViewZones(reader, - input1ViewZoneIds, input1ViewZoneAccessor, - input2ViewZoneIds, input2ViewZoneAccessor, - baseViewZoneIds, /*baseViewZoneAccessor,*/ undefined, - resultViewZoneIds, actualResultViewZoneAccessor, - ); + store.add(this.setViewZones(reader, + viewModel, + this.input1View.editor, + input1ViewZoneAccessor, + this.input2View.editor, + input2ViewZoneAccessor, + baseView.editor, + baseViewZoneAccessor, + shouldAlignBase, + this.inputResultView.editor, + resultViewZoneAccessor, + shouldAlignResult + )); }); } else { - setViewZones(reader, - input1ViewZoneIds, + store.add(this.setViewZones(reader, + viewModel, + this.input1View.editor, input1ViewZoneAccessor, - input2ViewZoneIds, + this.input2View.editor, input2ViewZoneAccessor, - baseViewZoneIds, undefined, - resultViewZoneIds, actualResultViewZoneAccessor, - ); + undefined, + false, + this.inputResultView.editor, + resultViewZoneAccessor, + shouldAlignResult + )); } }); }); }); - store.add({ - dispose: () => { - this.input1View.editor.changeViewZones(a => { - for (const zone of input1ViewZoneIds) { - a.removeZone(zone); - } - }); - this.input2View.editor.changeViewZones(a => { - for (const zone of input2ViewZoneIds) { - a.removeZone(zone); - } - }); - this.baseView.get()?.editor.changeViewZones(a => { - for (const zone of baseViewZoneIds) { - a.removeZone(zone); - } - }); - this.inputResultView.editor.changeViewZones(a => { - for (const zone of resultViewZoneIds) { - a.removeZone(zone); - } - }); - } - }); - + this.scrollSynchronizer.updateScrolling(); }, 'update alignment view zones')); const viewState = this.loadEditorViewState(input, context); @@ -340,146 +331,233 @@ export class MergeEditor extends AbstractTextEditor { ); } }); + } - function setViewZones( - reader: IReader, - input1ViewZoneIds: string[], - input1ViewZoneAccessor: IViewZoneChangeAccessor, - input2ViewZoneIds: string[], - input2ViewZoneAccessor: IViewZoneChangeAccessor, - baseViewZoneIds: string[], - baseViewZoneAccessor: IViewZoneChangeAccessor | undefined, - resultViewZoneIds: string[], - resultViewZoneAccessor: IViewZoneChangeAccessor | undefined, - ) { - let input1LinesAdded = 0; - let input2LinesAdded = 0; - let baseLinesAdded = 0; - let resultLinesAdded = 0; + private setViewZones( + reader: IReader, + viewModel: MergeEditorViewModel, + input1Editor: ICodeEditor, + input1ViewZoneAccessor: IViewZoneChangeAccessor, + input2Editor: ICodeEditor, + input2ViewZoneAccessor: IViewZoneChangeAccessor, + baseEditor: ICodeEditor | undefined, + baseViewZoneAccessor: IViewZoneChangeAccessor | undefined, + shouldAlignBase: boolean, + resultEditor: ICodeEditor, + resultViewZoneAccessor: IViewZoneChangeAccessor, + shouldAlignResult: boolean, + ): IDisposable { + let input1LinesAdded = 0; + let input2LinesAdded = 0; + let baseLinesAdded = 0; + let resultLinesAdded = 0; - const resultDiffs = model.baseResultDiffs.read(reader); - const baseRangeWithStoreAndTouchingDiffs = join( - model.modifiedBaseRanges.read(reader), - resultDiffs, - (baseRange, diff) => - baseRange.baseRange.touches(diff.inputRange) - ? CompareResult.neitherLessOrGreaterThan - : LineRange.compareByStart( - baseRange.baseRange, - diff.inputRange - ) - ); + const model = viewModel.model; - let lastModifiedBaseRange: ModifiedBaseRange | undefined = undefined; - let lastBaseResultDiff: DetailedLineRangeMapping | undefined = undefined; - for (const m of baseRangeWithStoreAndTouchingDiffs) { - interface LineAlignment { - baseLine: number; - input1Line?: number; - input2Line?: number; - resultLine?: number; - } + const input1ViewZoneIds: string[] = []; + const input2ViewZoneIds: string[] = []; + const baseViewZoneIds: string[] = []; + const resultViewZoneIds: string[] = []; - const lastResultDiff = lastOrDefault(m.rights)!; - if (lastResultDiff) { - lastBaseResultDiff = lastResultDiff; - } - let alignedLines: LineAlignment[]; - if (m.left) { - alignedLines = getAlignments(m.left).map(a => ({ - input1Line: a[0], - baseLine: a[1], - input2Line: a[2], - resultLine: undefined, + const resultDiffs = model.baseResultDiffs.read(reader); + const baseRangeWithStoreAndTouchingDiffs = join( + model.modifiedBaseRanges.read(reader), + resultDiffs, + (baseRange, diff) => + baseRange.baseRange.touches(diff.inputRange) + ? CompareResult.neitherLessOrGreaterThan + : LineRange.compareByStart( + baseRange.baseRange, + diff.inputRange + ) + ); + + const disposableStore = new DisposableStore(); + disposableStore.add({ + dispose: () => { + input1Editor.changeViewZones(a => { + for (const zone of input1ViewZoneIds) { + a.removeZone(zone); + } + }); + input2Editor.changeViewZones(a => { + for (const zone of input2ViewZoneIds) { + a.removeZone(zone); + } + }); + baseEditor?.changeViewZones(a => { + for (const zone of baseViewZoneIds) { + a.removeZone(zone); + } + }); + resultEditor.changeViewZones(a => { + for (const zone of resultViewZoneIds) { + a.removeZone(zone); + } + }); + } + }); + + const shouldShowCodeLenses = this.codeLensesVisible.read(reader); + const showNonConflictingChanges = this.showNonConflictingChanges.read(reader); + + let lastModifiedBaseRange: ModifiedBaseRange | undefined = undefined; + let lastBaseResultDiff: DetailedLineRangeMapping | undefined = undefined; + for (const m of baseRangeWithStoreAndTouchingDiffs) { + + if (shouldShowCodeLenses && m.left && (m.left.isConflicting || showNonConflictingChanges || !model.isHandled(m.left).read(reader))) { + + input1ViewZoneIds.push(input1ViewZoneAccessor.addZone({ + afterLineNumber: m.left.input1Range.startLineNumber - 1, + heightInPx: 16, + domNode: $('div.conflict-actions-placeholder'), + })); + const w1 = this.conflictActionsFactoryInput1.createContentWidget(m.left.input1Range.startLineNumber - 1, viewModel, m.left, this.input1View.inputNumber); + input1Editor.addContentWidget(w1); + disposableStore.add(toDisposable(() => { + input1Editor.removeContentWidget(w1); + })); + + + input2ViewZoneIds.push(input2ViewZoneAccessor.addZone({ + afterLineNumber: m.left.input2Range.startLineNumber - 1, + heightInPx: 16, + domNode: $('div.conflict-actions-placeholder'), + })); + const w2 = this.conflictActionsFactoryInput2.createContentWidget(m.left.input2Range.startLineNumber - 1, viewModel, m.left, this.input2View.inputNumber); + input2Editor.addContentWidget(w2); + disposableStore.add(toDisposable(() => { + input2Editor.removeContentWidget(w2); + })); + + const afterLineNumber = m.left.baseRange.startLineNumber + (lastBaseResultDiff?.resultingDeltaFromOriginalToModified ?? 0) - 1; + resultViewZoneIds.push(resultViewZoneAccessor.addZone({ + afterLineNumber, + heightInPx: 16, + domNode: $('div.conflict-actions-placeholder'), + })); + const w3 = this.conflictActionsFactoryResult.createResultWidget(afterLineNumber, viewModel, m.left); + resultEditor.addContentWidget(w3); + disposableStore.add(toDisposable(() => { + resultEditor.removeContentWidget(w3); + })); + + if (shouldAlignBase && baseViewZoneAccessor) { + baseViewZoneIds.push(baseViewZoneAccessor.addZone({ + afterLineNumber, + heightInPx: 16, + domNode: $('div.conflict-actions-placeholder'), })); + } + } - lastModifiedBaseRange = m.left; - // This is a total hack. - alignedLines[alignedLines.length - 1].resultLine = - m.left.baseRange.endLineNumberExclusive - + (lastBaseResultDiff ? lastBaseResultDiff.resultingDeltaFromOriginalToModified : 0); + interface LineAlignment { + baseLine: number; + input1Line?: number; + input2Line?: number; + resultLine?: number; + } - } else { - alignedLines = [{ - baseLine: lastResultDiff.inputRange.endLineNumberExclusive, - input1Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input1Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), - input2Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input2Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), - resultLine: lastResultDiff.outputRange.endLineNumberExclusive, - }]; + const lastResultDiff = lastOrDefault(m.rights)!; + if (lastResultDiff) { + lastBaseResultDiff = lastResultDiff; + } + let alignedLines: LineAlignment[]; + if (m.left) { + alignedLines = getAlignments(m.left).map(a => ({ + input1Line: a[0], + baseLine: a[1], + input2Line: a[2], + resultLine: undefined, + })); + + lastModifiedBaseRange = m.left; + // This is a total hack. + alignedLines[alignedLines.length - 1].resultLine = + m.left.baseRange.endLineNumberExclusive + + (lastBaseResultDiff ? lastBaseResultDiff.resultingDeltaFromOriginalToModified : 0); + + } else { + alignedLines = [{ + baseLine: lastResultDiff.inputRange.endLineNumberExclusive, + input1Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input1Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), + input2Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input2Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), + resultLine: lastResultDiff.outputRange.endLineNumberExclusive, + }]; + } + + for (const { input1Line, baseLine, input2Line, resultLine } of alignedLines) { + if (!shouldAlignBase && (input1Line === undefined || input2Line === undefined)) { + continue; } - for (const { input1Line, baseLine, input2Line, resultLine } of alignedLines) { - if (!baseViewZoneAccessor && (input1Line === undefined || input2Line === undefined)) { - continue; + const input1Line_ = + input1Line !== undefined ? input1Line + input1LinesAdded : -1; + const input2Line_ = + input2Line !== undefined ? input2Line + input2LinesAdded : -1; + const baseLine_ = baseLine + baseLinesAdded; + const resultLine_ = resultLine !== undefined ? resultLine + resultLinesAdded : -1; + + const max = Math.max(shouldAlignBase ? baseLine_ : 0, input1Line_, input2Line_, shouldAlignResult ? resultLine_ : 0); + + if (input1Line !== undefined) { + const diffInput1 = max - input1Line_; + if (diffInput1 > 0) { + input1ViewZoneIds.push( + input1ViewZoneAccessor.addZone({ + afterLineNumber: input1Line - 1, + heightInLines: diffInput1, + domNode: $('div.diagonal-fill'), + }) + ); + input1LinesAdded += diffInput1; } + } - const input1Line_ = - input1Line !== undefined ? input1Line + input1LinesAdded : -1; - const input2Line_ = - input2Line !== undefined ? input2Line + input2LinesAdded : -1; - const baseLine_ = baseLine + baseLinesAdded; - const resultLine_ = resultLine !== undefined ? resultLine + resultLinesAdded : -1; - - const max = Math.max(baseViewZoneAccessor ? baseLine_ : 0, input1Line_, input2Line_, resultLine_); - - if (input1Line !== undefined) { - const diffInput1 = max - input1Line_; - if (diffInput1 > 0) { - input1ViewZoneIds.push( - input1ViewZoneAccessor.addZone({ - afterLineNumber: input1Line - 1, - heightInLines: diffInput1, - domNode: $('div.diagonal-fill'), - }) - ); - input1LinesAdded += diffInput1; - } + if (input2Line !== undefined) { + const diffInput2 = max - input2Line_; + if (diffInput2 > 0) { + input2ViewZoneIds.push( + input2ViewZoneAccessor.addZone({ + afterLineNumber: input2Line - 1, + heightInLines: diffInput2, + domNode: $('div.diagonal-fill'), + }) + ); + input2LinesAdded += diffInput2; } + } - if (input2Line !== undefined) { - const diffInput2 = max - input2Line_; - if (diffInput2 > 0) { - input2ViewZoneIds.push( - input2ViewZoneAccessor.addZone({ - afterLineNumber: input2Line - 1, - heightInLines: diffInput2, - domNode: $('div.diagonal-fill'), - }) - ); - input2LinesAdded += diffInput2; - } + if (shouldAlignBase && baseViewZoneAccessor) { + const diffBase = max - baseLine_; + if (diffBase > 0) { + baseViewZoneIds.push( + baseViewZoneAccessor.addZone({ + afterLineNumber: baseLine - 1, + heightInLines: diffBase, + domNode: $('div.diagonal-fill'), + }) + ); + baseLinesAdded += diffBase; } + } - if (baseViewZoneAccessor) { - const diffBase = max - baseLine_; - if (diffBase > 0) { - baseViewZoneIds.push( - baseViewZoneAccessor.addZone({ - afterLineNumber: baseLine - 1, - heightInLines: diffBase, - domNode: $('div.diagonal-fill'), - }) - ); - baseLinesAdded += diffBase; - } - } - - if (resultViewZoneAccessor && resultLine !== undefined) { - const diffResult = max - resultLine_; - if (diffResult > 0) { - resultViewZoneIds.push( - resultViewZoneAccessor.addZone({ - afterLineNumber: resultLine - 1, - heightInLines: diffResult, - domNode: $('div.diagonal-fill'), - }) - ); - resultLinesAdded += diffResult; - } + if (shouldAlignResult && resultViewZoneAccessor && resultLine !== undefined) { + const diffResult = max - resultLine_; + if (diffResult > 0) { + resultViewZoneIds.push( + resultViewZoneAccessor.addZone({ + afterLineNumber: resultLine - 1, + heightInLines: diffResult, + domNode: $('div.diagonal-fill'), + }) + ); + resultLinesAdded += diffResult; } } } } + return disposableStore; } override setOptions(options: ITextEditorOptions | undefined): void { @@ -630,6 +708,7 @@ export class MergeEditor extends AbstractTextEditor { this._layoutMode.value = layout; this._ctxUsesColumnLayout.set(layout.kind); this._ctxShowBase.set(layout.showBase); + this._ctxShowBaseAtTop.set(layout.showBaseAtTop); this._onDidChangeSizeConstraints.fire(); this._layoutModeObs.set(layout, tx); }); @@ -704,7 +783,7 @@ export class MergeEditor extends AbstractTextEditor { } } -interface IMergeEditorLayout { +export interface IMergeEditorLayout { readonly kind: MergeEditorLayoutKind; readonly showBase: boolean; readonly showBaseAtTop: boolean; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer.ts index 854418a297b..1fd54b6b7e6 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer.ts @@ -10,6 +10,7 @@ import { ScrollType } from 'vs/editor/common/editorCommon'; import { DocumentLineRangeMap } from 'vs/workbench/contrib/mergeEditor/browser/model/mapping'; import { ReentrancyBarrier } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { BaseCodeEditorView } from 'vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView'; +import { IMergeEditorLayout } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; import { InputCodeEditorView } from './editors/inputCodeEditorView'; import { ResultCodeEditorView } from './editors/resultCodeEditorView'; @@ -19,21 +20,44 @@ export class ScrollSynchronizer extends Disposable { private readonly reentrancyBarrier = new ReentrancyBarrier(); + public readonly updateScrolling: () => void; + + private get shouldAlignResult() { return this.layout.get().kind === 'columns'; } + private get shouldAlignBase() { return this.layout.get().kind === 'mixed' && !this.layout.get().showBaseAtTop; } + constructor( private readonly viewModel: IObservable, private readonly input1View: InputCodeEditorView, private readonly input2View: InputCodeEditorView, private readonly baseView: IObservable, - private readonly inputResultView: ResultCodeEditorView + private readonly inputResultView: ResultCodeEditorView, + private readonly layout: IObservable, ) { super(); - const handleInput1OnScroll = () => { - const mapping = this.model?.input1ResultMapping.get(); - this.synchronizeScrolling(this.input1View.editor, this.inputResultView.editor, mapping); + const handleInput1OnScroll = this.updateScrolling = () => { + if (!this.model) { + return; + } + this.input2View.editor.setScrollTop(this.input1View.editor.getScrollTop(), ScrollType.Immediate); - this.baseView.get()?.editor.setScrollTop(this.input1View.editor.getScrollTop(), ScrollType.Immediate); + if (this.shouldAlignResult) { + this.inputResultView.editor.setScrollTop(this.input1View.editor.getScrollTop(), ScrollType.Immediate); + } else { + const mappingInput1Result = this.model!.input1ResultMapping.get(); + this.synchronizeScrolling(this.input1View.editor, this.inputResultView.editor, mappingInput1Result); + } + + const baseView = this.baseView.get(); + if (baseView) { + if (this.shouldAlignBase) { + this.baseView.get()?.editor.setScrollTop(this.input1View.editor.getScrollTop(), ScrollType.Immediate); + } else { + const mapping = new DocumentLineRangeMap(this.model!.baseInput1Diffs.get(), -1).reverse(); + this.synchronizeScrolling(this.input1View.editor, baseView.editor, mapping); + } + } }; this._store.add( @@ -54,12 +78,29 @@ export class ScrollSynchronizer extends Disposable { this._store.add( this.input2View.editor.onDidScrollChange( this.reentrancyBarrier.makeExclusive((c) => { + if (!this.model) { + return; + } + if (c.scrollTopChanged) { - const mapping = this.model?.input2ResultMapping.get(); - this.synchronizeScrolling(this.input2View.editor, this.inputResultView.editor, mapping); this.input1View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); - this.baseView.get()?.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + if (this.shouldAlignResult) { + this.inputResultView.editor.setScrollTop(this.input2View.editor.getScrollTop(), ScrollType.Immediate); + } else { + const mappingInput2Result = this.model!.input2ResultMapping.get(); + this.synchronizeScrolling(this.input2View.editor, this.inputResultView.editor, mappingInput2Result); + } + + const baseView = this.baseView.get(); + if (baseView && this.model) { + if (this.shouldAlignBase) { + this.baseView.get()?.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + } else { + const mapping = new DocumentLineRangeMap(this.model!.baseInput2Diffs.get(), -1).reverse(); + this.synchronizeScrolling(this.input2View.editor, baseView.editor, mapping); + } + } } if (c.scrollLeftChanged) { this.baseView.get()?.editor.setScrollLeft(c.scrollLeft, ScrollType.Immediate); @@ -73,14 +114,20 @@ export class ScrollSynchronizer extends Disposable { this.inputResultView.editor.onDidScrollChange( this.reentrancyBarrier.makeExclusive((c) => { if (c.scrollTopChanged) { - const mapping1 = this.model?.resultInput1Mapping.get(); - this.synchronizeScrolling(this.inputResultView.editor, this.input1View.editor, mapping1); - const mapping2 = this.model?.resultInput2Mapping.get(); - this.synchronizeScrolling(this.inputResultView.editor, this.input2View.editor, mapping2); + if (this.shouldAlignResult) { + this.input1View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + this.input2View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + } else { + const mapping1 = this.model?.resultInput1Mapping.get(); + this.synchronizeScrolling(this.inputResultView.editor, this.input1View.editor, mapping1); + + const mapping2 = this.model?.resultInput2Mapping.get(); + this.synchronizeScrolling(this.inputResultView.editor, this.input2View.editor, mapping2); + } const baseMapping = this.model?.resultBaseMapping.get(); const baseView = this.baseView.get(); - if (baseView) { + if (baseView && this.model) { this.synchronizeScrolling(this.inputResultView.editor, baseView.editor, baseMapping); } } @@ -100,8 +147,19 @@ export class ScrollSynchronizer extends Disposable { store.add(baseView.editor.onDidScrollChange( this.reentrancyBarrier.makeExclusive((c) => { if (c.scrollTopChanged) { - this.input1View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); - this.input2View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + if (!this.model) { + return; + } + if (this.shouldAlignBase) { + this.input1View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + this.input2View.editor.setScrollTop(c.scrollTop, ScrollType.Immediate); + } else { + const baseInput1Mapping = new DocumentLineRangeMap(this.model!.baseInput1Diffs.get(), -1); + this.synchronizeScrolling(baseView.editor, this.input1View.editor, baseInput1Mapping); + + const baseInput2Mapping = new DocumentLineRangeMap(this.model!.baseInput2Diffs.get(), -1); + this.synchronizeScrolling(baseView.editor, this.input2View.editor, baseInput2Mapping); + } const baseMapping = this.model?.baseResultMapping.get(); this.synchronizeScrolling(baseView.editor, this.inputResultView.editor, baseMapping); @@ -116,20 +174,6 @@ export class ScrollSynchronizer extends Disposable { } }, 'set baseViewEditor.onDidScrollChange') ); - - this._store.add( - autorunWithStore((reader, store) => { - const vm = this.viewModel.read(reader); - if (!vm) { - return; - } - this.baseView.read(reader); - - this.reentrancyBarrier.runExclusively(() => { - handleInput1OnScroll(); - }); - }, 'update scroll when base view changes') - ); } private synchronizeScrolling(scrollingEditor: CodeEditorWidget, targetEditor: CodeEditorWidget, mapping: DocumentLineRangeMap | undefined) { From 5183e9bcb9273339010469070acb5df3d1c59a44 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 26 Sep 2022 15:27:18 -0400 Subject: [PATCH 087/599] Make some more services lazy (#161827) * Lazy service instantiation * Make resolver eager --- .../welcomeGettingStarted/browser/gettingStartedService.ts | 2 +- .../workbench/services/assignment/common/assignmentService.ts | 2 +- .../services/editor/browser/editorResolverService.ts | 4 ++-- .../workbench/services/telemetry/browser/telemetryService.ts | 2 +- .../services/telemetry/electron-sandbox/telemetryService.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts index cf5d7f7671a..d0b2d601f17 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts @@ -716,4 +716,4 @@ registerAction2(class extends Action2 { } }); -registerSingleton(IWalkthroughsService, WalkthroughsService, false); +registerSingleton(IWalkthroughsService, WalkthroughsService, true); diff --git a/src/vs/workbench/services/assignment/common/assignmentService.ts b/src/vs/workbench/services/assignment/common/assignmentService.ts index 942388eb947..93008a87c07 100644 --- a/src/vs/workbench/services/assignment/common/assignmentService.ts +++ b/src/vs/workbench/services/assignment/common/assignmentService.ts @@ -131,4 +131,4 @@ export class WorkbenchAssignmentService extends BaseAssignmentService { } } -registerSingleton(IWorkbenchAssignmentService, WorkbenchAssignmentService, false); +registerSingleton(IWorkbenchAssignmentService, WorkbenchAssignmentService, true); diff --git a/src/vs/workbench/services/editor/browser/editorResolverService.ts b/src/vs/workbench/services/editor/browser/editorResolverService.ts index b35aabc0711..6731ee8717c 100644 --- a/src/vs/workbench/services/editor/browser/editorResolverService.ts +++ b/src/vs/workbench/services/editor/browser/editorResolverService.ts @@ -19,7 +19,7 @@ import { QuickPickItem, IKeyMods, IQuickInputService, IQuickPickItem, IQuickPick import { localize } from 'vs/nls'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; @@ -829,4 +829,4 @@ export class EditorResolverService extends Disposable implements IEditorResolver } } -registerSingleton(IEditorResolverService, EditorResolverService, false); +registerSingleton(IEditorResolverService, EditorResolverService, InstantiationType.Eager); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index dbf075cf7d2..eb5de68bbb9 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -108,4 +108,4 @@ export class TelemetryService extends Disposable implements ITelemetryService { } } -registerSingleton(ITelemetryService, TelemetryService, false); +registerSingleton(ITelemetryService, TelemetryService, true); diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts index 4e2103332d1..51bb15c57b9 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts @@ -84,4 +84,4 @@ export class TelemetryService extends Disposable implements ITelemetryService { } } -registerSingleton(ITelemetryService, TelemetryService, false); +registerSingleton(ITelemetryService, TelemetryService, true); From 9b4be06da50e1419cbca39dba713dc2e9bf4ef85 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 26 Sep 2022 12:32:59 -0700 Subject: [PATCH 088/599] dispose of decoration on run action, not after click (#161813) --- src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index 8b4cd8735f0..9a78883c533 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -122,7 +122,6 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, this._decorationMarkerIds.add(decoration.marker.id); dom.addDisposableListener(e, dom.EventType.CLICK, () => { this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions }); - this._contextMenuService.onDidHideContextMenu(() => decoration.dispose()); }); } } From 741fa37b10b4fcda13c1d73f266d64d9b69fe40e Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 26 Sep 2022 21:41:26 +0200 Subject: [PATCH 089/599] [json/css/html] update services / deps (#161831) --- extensions/css-language-features/package.json | 2 +- .../css-language-features/server/package.json | 2 +- .../css-language-features/server/yarn.lock | 13 ++-- extensions/css-language-features/yarn.lock | 8 +-- .../html-language-features/package.json | 2 +- .../server/package.json | 2 +- .../html-language-features/server/yarn.lock | 13 ++-- extensions/html-language-features/yarn.lock | 8 +-- .../server/package.json | 4 +- .../json-language-features/server/yarn.lock | 59 +++++++------------ 10 files changed, 44 insertions(+), 69 deletions(-) diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 3454dfc0f5f..497f6cd735c 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -996,7 +996,7 @@ "dependencies": { "vscode-languageclient": "^8.1.0-next.1", "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.5" + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index cb06dbc0cae..2528682c661 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -12,7 +12,7 @@ "dependencies": { "vscode-css-languageservice": "^6.1.1", "vscode-languageserver": "^8.1.0-next.1", - "vscode-uri": "^3.0.5" + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/mocha": "^9.1.1", diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index c1ef679ae8a..ec35ce87045 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -57,12 +57,7 @@ vscode-nls@^5.2.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== -vscode-uri@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.4.tgz#703c6dd7c0b727ee1c34a1287434138fb52d054f" - integrity sha512-aEmKD6H8Sg8gaQAUrnadG0BMeWXtiWhRsj1a94n2FYsMkDpgnK7BRVzZjOUYIvkv2B+bp5Bmt4ImZCpYbnJwkg== - -vscode-uri@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.5.tgz#3dd5a9e154e7c9a40de5eaa450a0ce59b435e584" - integrity sha512-bBp2pi1o6ynwlnGL8Tt6UBL1w3VsVZtHCU/Sl73bRfqjno3jMcVSCybdY+hj+31A8FQOELZJWwY+shLVLtcNew== +vscode-uri@^3.0.6, vscode-uri@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index caf235a479e..dc44620a06b 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -72,10 +72,10 @@ vscode-nls@^5.2.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== -vscode-uri@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.5.tgz#3dd5a9e154e7c9a40de5eaa450a0ce59b435e584" - integrity sha512-bBp2pi1o6ynwlnGL8Tt6UBL1w3VsVZtHCU/Sl73bRfqjno3jMcVSCybdY+hj+31A8FQOELZJWwY+shLVLtcNew== +vscode-uri@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== yallist@^4.0.0: version "4.0.0" diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 527932fd7d8..5a46ebe48bd 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -261,7 +261,7 @@ "@vscode/extension-telemetry": "0.6.2", "vscode-languageclient": "^8.1.0-next.1", "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.5" + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 00d2fe73472..7dc7e70a2f0 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -14,7 +14,7 @@ "vscode-languageserver": "^8.1.0-next.1", "vscode-languageserver-textdocument": "^1.0.7", "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.5" + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/mocha": "^9.1.1", diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index c467e1ac9b4..2532ccb506a 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -67,12 +67,7 @@ vscode-nls@^5.2.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== -vscode-uri@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.4.tgz#703c6dd7c0b727ee1c34a1287434138fb52d054f" - integrity sha512-aEmKD6H8Sg8gaQAUrnadG0BMeWXtiWhRsj1a94n2FYsMkDpgnK7BRVzZjOUYIvkv2B+bp5Bmt4ImZCpYbnJwkg== - -vscode-uri@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.5.tgz#3dd5a9e154e7c9a40de5eaa450a0ce59b435e584" - integrity sha512-bBp2pi1o6ynwlnGL8Tt6UBL1w3VsVZtHCU/Sl73bRfqjno3jMcVSCybdY+hj+31A8FQOELZJWwY+shLVLtcNew== +vscode-uri@^3.0.6, vscode-uri@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index cfe8b8f7ad1..478e8548591 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -116,10 +116,10 @@ vscode-nls@^5.2.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== -vscode-uri@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.5.tgz#3dd5a9e154e7c9a40de5eaa450a0ce59b435e584" - integrity sha512-bBp2pi1o6ynwlnGL8Tt6UBL1w3VsVZtHCU/Sl73bRfqjno3jMcVSCybdY+hj+31A8FQOELZJWwY+shLVLtcNew== +vscode-uri@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== yallist@^4.0.0: version "4.0.0" diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 8e4957e3948..04a3ec18dfd 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,9 +14,9 @@ "dependencies": { "jsonc-parser": "^3.2.0", "request-light": "^0.5.8", - "vscode-json-languageservice": "^5.1.0", + "vscode-json-languageservice": "^5.1.1", "vscode-languageserver": "^8.1.0-next.1", - "vscode-uri": "^3.0.5" + "vscode-uri": "^3.0.6" }, "devDependencies": { "@types/mocha": "^9.1.1", diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 6bfcd025444..feb920a12d7 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -12,11 +12,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -jsonc-parser@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.1.0.tgz#73b8f0e5c940b83d03476bc2e51a20ef0932615d" - integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg== - jsonc-parser@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -27,16 +22,16 @@ request-light@^0.5.8: resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.8.tgz#8bf73a07242b9e7b601fac2fa5dc22a094abcc27" integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg== -vscode-json-languageservice@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.1.0.tgz#b1f197a60338cb378189fcb41489a84846724dd9" - integrity sha512-D5612D7h/Gh4A0JmdttPveWzT9dur21WXvBHWKPdOt0sLO6ILz8vN6+IzWnvwDOVAEFTpzIAMVMZwbKZkwGGiA== +vscode-json-languageservice@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.1.1.tgz#d7e36351cf54abc1a5456fe29ae04a6a5f801e88" + integrity sha512-EtAcTD6MOfyf8+MokDsAHNM7ttuZvCo077w9aMtJiyps41gkOcoBThAbXDk6Y0Oi6ki5aDs8lgY4KxYiVW/lxA== dependencies: - jsonc-parser "^3.1.0" - vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.17.1" - vscode-nls "^5.0.1" - vscode-uri "^3.0.3" + jsonc-parser "^3.2.0" + vscode-languageserver-textdocument "^1.0.7" + vscode-languageserver-types "^3.17.2" + vscode-nls "^5.2.0" + vscode-uri "^3.0.6" vscode-jsonrpc@8.1.0-next.1: version "8.1.0-next.1" @@ -51,21 +46,16 @@ vscode-languageserver-protocol@3.17.3-next.1: vscode-jsonrpc "8.1.0-next.1" vscode-languageserver-types "3.17.2" -vscode-languageserver-textdocument@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" - integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== +vscode-languageserver-textdocument@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz#16df468d5c2606103c90554ae05f9f3d335b771b" + integrity sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg== -vscode-languageserver-types@3.17.2: +vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.2: version "3.17.2" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-languageserver-types@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" - integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== - vscode-languageserver@^8.1.0-next.1: version "8.1.0-next.1" resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.1.0-next.1.tgz#1c173de554889bd18ca6e20eaf4bdc84164c86b4" @@ -73,17 +63,12 @@ vscode-languageserver@^8.1.0-next.1: dependencies: vscode-languageserver-protocol "3.17.3-next.1" -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" + integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== -vscode-uri@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" - integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== - -vscode-uri@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.5.tgz#3dd5a9e154e7c9a40de5eaa450a0ce59b435e584" - integrity sha512-bBp2pi1o6ynwlnGL8Tt6UBL1w3VsVZtHCU/Sl73bRfqjno3jMcVSCybdY+hj+31A8FQOELZJWwY+shLVLtcNew== +vscode-uri@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.6.tgz#5e6e2e1a4170543af30151b561a41f71db1d6f91" + integrity sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ== From 8013a36ecaab31ebdb2719fe934a29ca9c3cd43a Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 26 Sep 2022 12:46:13 -0700 Subject: [PATCH 090/599] Fix nb diff overview ruler scaling. (#161832) --- .../notebook/browser/diff/notebookDiffOverviewRuler.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts index c446f07e32b..a18ea3021c3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts @@ -124,6 +124,7 @@ export class NotebookDiffOverviewRuler extends Themable { private _layoutNow() { const layoutInfo = this.notebookEditor.getLayoutInfo(); const height = layoutInfo.height; + const scrollHeight = layoutInfo.scrollHeight; const ratio = browser.PixelRatio.value; this._domNode.setWidth(this.width); this._domNode.setHeight(height); @@ -131,7 +132,7 @@ export class NotebookDiffOverviewRuler extends Themable { this._domNode.domNode.height = height * ratio; const ctx = this._domNode.domNode.getContext('2d')!; ctx.clearRect(0, 0, this.width * ratio, height * ratio); - this._renderCanvas(ctx, this.width * ratio, ratio); + this._renderCanvas(ctx, this.width * ratio, height * ratio, scrollHeight * ratio, ratio); this._renderOverviewViewport(); } @@ -168,7 +169,7 @@ export class NotebookDiffOverviewRuler extends Themable { }; } - private _renderCanvas(ctx: CanvasRenderingContext2D, width: number, ratio: number) { + private _renderCanvas(ctx: CanvasRenderingContext2D, width: number, height: number, scrollHeight: number, ratio: number) { if (!this._insertColorHex || !this._removeColorHex) { // no op when colors are not yet known return; @@ -179,7 +180,8 @@ export class NotebookDiffOverviewRuler extends Themable { for (let i = 0; i < this._diffElementViewModels.length; i++) { const element = this._diffElementViewModels[i]; - const cellHeight = element.layoutInfo.totalHeight * ratio; + const cellHeight = (element.layoutInfo.totalHeight / scrollHeight) * ratio * height; + switch (element.type) { case 'insert': ctx.fillStyle = this._insertColorHex; From 6e0841243ff0cb50ec41512f42194ed0ac98713d Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 26 Sep 2022 22:08:23 +0200 Subject: [PATCH 091/599] Merge editor improvements (#161837) * Only reset result when result contains conflict markers * Show merge editor code-lens by default (instead of checkboxes) * Improve merge editor code-lens tooltips * Fixes label --- .../browser/mergeEditorInputModel.ts | 7 +- .../browser/view/conflictActions.ts | 74 ++++++++++--------- .../browser/view/editors/codeEditorView.ts | 2 +- .../mergeEditor/browser/view/mergeEditor.ts | 2 +- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index 1d0580d8e6b..5882c9818aa 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -21,6 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IRevertOptions } from 'vs/workbench/common/editor'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; +import { conflictMarkers } from 'vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController'; import { MergeDiffComputer } from 'vs/workbench/contrib/mergeEditor/browser/model/diffComputer'; import { InputData, MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -303,6 +304,10 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa // So that "Don't save" does revert the file await resultTextFileModel.save(); + const lines = resultTextFileModel.textEditorModel!.getLinesContent(); + const hasConflictMarkers = lines.some(l => l.startsWith(conflictMarkers.start)); + const resetResult = hasConflictMarkers; + const diffProvider = this._instantiationService.createInstance(WorkerBasedDocumentDiffProvider); const model = this._instantiationService.createInstance( MergeEditorModel, @@ -313,7 +318,7 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa this._instantiationService.createInstance(MergeDiffComputer, diffProvider), this._instantiationService.createInstance(MergeDiffComputer, diffProvider), { - resetResult: true + resetResult } ); store.add(model); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index f42b282024d..57aed4fda5e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -77,10 +77,11 @@ export class ConflictActionsFactory extends Disposable { createContentWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IContentWidget { - function command(title: string, action: () => Promise): IContentWidgetAction { + function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { return { text: title, - action + action, + tooltip, }; } @@ -113,7 +114,7 @@ export class ConflictActionsFactory extends Disposable { ); }); }) - : command(localize('remove', "$(error) Remove ${0}", inputData.title), async () => { + : command(localize('remove', "$(error) Remove {0}", inputData.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -149,7 +150,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }), + }, localize('acceptBothTooltip', "Both changes can be combined automatically")), ); } } @@ -173,35 +174,37 @@ export class ConflictActionsFactory extends Disposable { const result: IContentWidgetAction[] = []; - const stateLabel = ((state: ModifiedBaseRangeState): string => { - if (state.conflicting) { - return localize('manualResolution', "Manual Resolution"); - } else if (state.isEmpty) { - return localize('noChangesAccepted', 'No Changes Accepted'); - } else { - const labels = []; - if (state.input1) { - labels.push(model.input1.title); - } - if (state.input2) { - labels.push(model.input2.title); - } - if (state.input2First) { - labels.reverse(); - } - return `${labels.join(' + ')}`; + + if (state.conflicting) { + result.push({ + text: localize('manualResolution', "Manual Resolution"), + tooltip: localize('manualResolutionTooltip', "This conflict has been resolved manually"), + }); + } else if (state.isEmpty) { + result.push({ + text: localize('noChangesAccepted', 'No Changes Accepted'), + tooltip: localize('noChangesAcceptedTooltip', "The current resolution of this conflict equals the common ancestor of both the right and left changes."), + }); + + } else { + const labels = []; + if (state.input1) { + labels.push(model.input1.title); } - })(state); - - result.push({ - text: stateLabel, - action: async () => { }, - }); - + if (state.input2) { + labels.push(model.input2.title); + } + if (state.input2First) { + labels.reverse(); + } + result.push({ + text: `${labels.join(' + ')}` + }); + } const stateToggles: IContentWidgetAction[] = []; if (state.input1) { - result.push(command(localize('remove', "$(error) Remove ${0}", model.input1.title), async () => { + result.push(command(localize('remove', "$(error) Remove {0}", model.input1.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -214,7 +217,7 @@ export class ConflictActionsFactory extends Disposable { ); } if (state.input2) { - result.push(command(localize('remove', "$(error) Remove ${0}", model.input2.title), async () => { + result.push(command(localize('remove', "$(error) Remove {0}", model.input2.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -256,8 +259,8 @@ export class ConflictActionsFactory extends Disposable { interface IContentWidgetAction { text: string; - hover?: string; - action: () => Promise; + tooltip?: string; + action?: () => Promise; } class ActionsContentWidget extends Disposable implements IContentWidget { @@ -289,7 +292,12 @@ class ActionsContentWidget extends Disposable implements IContentWidget { children.push($('span', undefined, '\u00a0|\u00a0')); } const title = renderLabelWithIcons(item.text); - children.push($('a', { title: item.hover, role: 'button', onclick: () => item.action() }, ...title)); + + if (item.action) { + children.push($('a', { title: item.tooltip, role: 'button', onclick: () => item.action!() }, ...title)); + } else { + children.push($('span', { title: item.tooltip }, ...title)); + } } reset(this._domNode, ...children); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index 0a57fa548a9..7d53075c364 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -61,7 +61,7 @@ export abstract class CodeEditorView extends Disposable { protected readonly checkboxesVisible = observableFromEvent( this.configurationService.onDidChangeConfiguration, - () => /** @description checkboxesVisible */ this.configurationService.getValue('mergeEditor.showCheckboxes') ?? true + () => /** @description checkboxesVisible */ this.configurationService.getValue('mergeEditor.showCheckboxes') ?? false ); public readonly editor = this.instantiationService.createInstance( diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 7793c56b344..eff805c058f 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -103,7 +103,7 @@ export class MergeEditor extends AbstractTextEditor { protected readonly codeLensesVisible = observableFromEvent( this.configurationService.onDidChangeConfiguration, - () => /** @description codeLensesVisible */ this.configurationService.getValue('mergeEditor.showCodeLenses') ?? false + () => /** @description codeLensesVisible */ this.configurationService.getValue('mergeEditor.showCodeLenses') ?? true ); private readonly scrollSynchronizer = this._register(new ScrollSynchronizer(this._viewModel, this.input1View, this.input2View, this.baseView, this.inputResultView, this._layoutModeObs)); From a07a479de2d3dfcace749588eafa2657239feb25 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 26 Sep 2022 13:08:26 -0700 Subject: [PATCH 092/599] Ensure quotes are stripped from cwd Fixes #160109 --- .../workbench/contrib/terminal/common/terminalEnvironment.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 80041aeb869..5a17c3c3f69 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -229,6 +229,10 @@ async function _resolveCwd(cwd: string, variableResolver: VariableResolver | und } function _sanitizeCwd(cwd: string): string { + // Sanity check that the cwd is not wrapped in quotes (see #160109) + if (cwd.match(/$['"].*['"]^/)) { + cwd = cwd.substring(1, cwd.length - 1); + } // Make the drive letter uppercase on Windows (see #9448) if (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') { return cwd[0].toUpperCase() + cwd.substr(1); From 0df97dd38528bc00b7987823c4cdb8f2f9a0ed56 Mon Sep 17 00:00:00 2001 From: Litrop Date: Tue, 27 Sep 2022 04:16:09 +0800 Subject: [PATCH 093/599] Not add '[' to ipv6 host when '[' exists. (#157009) --- src/vs/base/common/network.ts | 2 +- src/vs/platform/remote/browser/browserSocketFactory.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 243bb3b82d3..648a6391131 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -150,7 +150,7 @@ class RemoteAuthoritiesImpl { } const authority = uri.authority; let host = this._hosts[authority]; - if (host && host.indexOf(':') !== -1) { + if (host && host.indexOf(':') !== -1 && host.indexOf('[') === -1) { host = `[${host}]`; } const port = this._ports[authority]; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts index cac305317db..46a6dd3a7a7 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -274,7 +274,7 @@ export class BrowserSocketFactory implements ISocketFactory { connect(host: string, port: number, path: string, query: string, debugLabel: string, callback: IConnectCallback): void { const webSocketSchema = (/^https:/.test(window.location.href) ? 'wss' : 'ws'); - const socket = this._webSocketFactory.create(`${webSocketSchema}://${/:/.test(host) ? `[${host}]` : host}:${port}${path}?${query}&skipWebSocketFrames=false`, debugLabel); + const socket = this._webSocketFactory.create(`${webSocketSchema}://${(/:/.test(host) && !/\[/.test(host)) ? `[${host}]` : host}:${port}${path}?${query}&skipWebSocketFrames=false`, debugLabel); const errorListener = socket.onError((err) => callback(err, undefined)); socket.onOpen(() => { errorListener.dispose(); From a0739779645957db4acbc11c8978bdcb6ae19d61 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Mon, 26 Sep 2022 22:22:35 +0200 Subject: [PATCH 094/599] Don't keep hover visible if it isn't sticky (#161839) Fixes #161708: Don't keep hover visible if it isn't sticky --- src/vs/editor/contrib/hover/browser/contentHover.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 25b5d12467d..30de80e0952 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -129,8 +129,8 @@ export class ContentHoverController extends Disposable { } // The hover is currently visible - - const isGettingCloser = (mouseEvent && this._widget.isMouseGettingCloser(mouseEvent.event.posx, mouseEvent.event.posy)); + const hoverIsSticky = this._editor.getOption(EditorOption.hover).sticky; + const isGettingCloser = (hoverIsSticky && mouseEvent && this._widget.isMouseGettingCloser(mouseEvent.event.posx, mouseEvent.event.posy)); if (isGettingCloser) { // The mouse is getting closer to the hover, so we will keep the hover untouched // But we will kick off a hover update at the new anchor, insisting on keeping the hover visible. From ad23961d5bd65c3c8a9e44bf18e9627a0f248ce8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 22:44:13 +0200 Subject: [PATCH 095/599] rearrange import and export actions (#161843) --- .../browser/userDataProfile.ts | 66 ++++++++- .../browser/userDataProfileActions.ts | 125 ++++++++---------- 2 files changed, 117 insertions(+), 74 deletions(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 90b0029d1f7..602b490276f 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -19,11 +19,14 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { RenameProfileAction } from 'vs/workbench/contrib/userDataProfile/browser/userDataProfileActions'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { CURRENT_PROFILE_CONTEXT, HAS_PROFILES_CONTEXT, IS_CURRENT_PROFILE_TRANSIENT_CONTEXT, IUserDataProfileManagementService, IUserDataProfileService, ManageProfilesSubMenu, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TTILE } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { CURRENT_PROFILE_CONTEXT, HAS_PROFILES_CONTEXT, IS_CURRENT_PROFILE_TRANSIENT_CONTEXT, IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService, ManageProfilesSubMenu, PROFILES_CATEGORY, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TTILE, PROFILE_EXTENSION, PROFILE_FILTER } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { charCount } from 'vs/base/common/strings'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { joinPath } from 'vs/base/common/resources'; export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution { @@ -153,6 +156,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements this.currentprofileActionsDisposable.value = new DisposableStore(); this.currentprofileActionsDisposable.value.add(this.registerUpdateCurrentProfileShortNameAction()); this.currentprofileActionsDisposable.value.add(this.registerRenameCurrentProfileAction()); + this.currentprofileActionsDisposable.value.add(this.registerExportCurrentProfileAction()); } private registerUpdateCurrentProfileShortNameAction(): IDisposable { @@ -227,4 +231,64 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements }); } + private registerExportCurrentProfileAction(): IDisposable { + const that = this; + const disposables = new DisposableStore(); + const id = 'workbench.profiles.actions.exportProfile'; + disposables.add(registerAction2(class ExportProfileAction extends Action2 { + constructor() { + super({ + id, + title: { + value: localize('export profile', "Export ({0})...", that.userDataProfileService.currentProfile.name), + original: `Export (${that.userDataProfileService.currentProfile.name})...` + }, + category: PROFILES_CATEGORY, + menu: [ + { + id: ManageProfilesSubMenu, + group: '4_import_export_profiles', + when: PROFILES_ENABLEMENT_CONTEXT, + order: 1 + }, { + id: MenuId.CommandPalette + } + ] + }); + } + + async run(accessor: ServicesAccessor) { + const textFileService = accessor.get(ITextFileService); + const fileDialogService = accessor.get(IFileDialogService); + const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService); + const notificationService = accessor.get(INotificationService); + + const profileLocation = await fileDialogService.showSaveDialog({ + title: localize('export profile dialog', "Save Profile"), + filters: PROFILE_FILTER, + defaultUri: joinPath(await fileDialogService.defaultFilePath(), `profile.${PROFILE_EXTENSION}`), + }); + + if (!profileLocation) { + return; + } + + const profile = await userDataProfileImportExportService.exportProfile({ skipComments: true }); + await textFileService.create([{ resource: profileLocation, value: JSON.stringify(profile), options: { overwrite: true } }]); + + notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY)); + } + })); + disposables.add(MenuRegistry.appendMenuItem(MenuId.MenubarShare, { + command: { + id, + title: { + value: localize('export settings profile', "Export Settings Profile ({0})...", that.userDataProfileService.currentProfile.name), + original: `Export Settings Profile (${that.userDataProfileService.currentProfile.name})...` + } + }, + })); + return disposables; + } + } diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts index 49ece437ba0..6c1d719b0bf 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts @@ -5,17 +5,15 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { joinPath } from 'vs/base/common/resources'; import { localize } from 'vs/nls'; -import { Action2, IMenuService, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, IMenuService, registerAction2 } from 'vs/platform/actions/common/actions'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileService } from 'vs/platform/files/common/files'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { QuickPickItem, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { asJson, asText, IRequestService } from 'vs/platform/request/common/request'; -import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileManagementService, IUserDataProfileImportExportService, PROFILES_CATEGORY, PROFILE_EXTENSION, PROFILE_FILTER, ManageProfilesSubMenu, IUserDataProfileService, PROFILES_ENABLEMENT_CONTEXT, HAS_PROFILES_CONTEXT, MANAGE_PROFILES_ACTION_ID } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileManagementService, IUserDataProfileImportExportService, PROFILES_CATEGORY, ManageProfilesSubMenu, IUserDataProfileService, PROFILES_ENABLEMENT_CONTEXT, HAS_PROFILES_CONTEXT, MANAGE_PROFILES_ACTION_ID, PROFILE_FILTER } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -136,16 +134,23 @@ registerAction2(class CreateProfileAction extends Action2 { const commandService = accessor.get(ICommandService); const pick = await quickInputService.pick( [{ + id: CreateEmptyProfileAction.ID, + label: CreateEmptyProfileAction.TITLE.value, + }, { + type: 'separator', + }, { id: CreateFromCurrentProfileAction.ID, label: CreateFromCurrentProfileAction.TITLE.value, }, { - id: CreateEmptyProfileAction.ID, - label: CreateEmptyProfileAction.TITLE.value, + id: CreateFromTemplateAction.ID, + label: CreateFromTemplateAction.TITLE.value, + }, { + type: 'separator', }, { id: CreateTransientProfileAction.ID, label: CreateTransientProfileAction.TITLE.value, }], { hideInput: true, canPickMany: false, title: localize('create settings profile', "{0}: Create...", PROFILES_CATEGORY) }); - if (pick) { + if (pick?.id) { return commandService.executeCommand(pick.id); } } @@ -379,70 +384,19 @@ registerAction2(class SwitchProfileAction extends Action2 { } }); -registerAction2(class ExportProfileAction extends Action2 { +class ImportProfileAction extends Action2 { + static readonly ID = 'workbench.profiles.actions.importProfile'; + static readonly TITLE = { + value: localize('import profile', "Import from ..."), + original: 'Import...' + }; constructor() { super({ - id: 'workbench.profiles.actions.exportProfile', - title: { - value: localize('export profile', "Export..."), - original: 'Export...' - }, + id: ImportProfileAction.ID, + title: ImportProfileAction.TITLE, category: PROFILES_CATEGORY, - menu: [ - { - id: ManageProfilesSubMenu, - group: '4_import_export_profiles', - when: PROFILES_ENABLEMENT_CONTEXT, - order: 1 - }, { - id: MenuId.CommandPalette - } - ] - }); - } - - async run(accessor: ServicesAccessor) { - const textFileService = accessor.get(ITextFileService); - const fileDialogService = accessor.get(IFileDialogService); - const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService); - const notificationService = accessor.get(INotificationService); - - const profileLocation = await fileDialogService.showSaveDialog({ - title: localize('export profile dialog', "Save Profile"), - filters: PROFILE_FILTER, - defaultUri: joinPath(await fileDialogService.defaultFilePath(), `profile.${PROFILE_EXTENSION}`), - }); - - if (!profileLocation) { - return; - } - - const profile = await userDataProfileImportExportService.exportProfile({ skipComments: true }); - await textFileService.create([{ resource: profileLocation, value: JSON.stringify(profile), options: { overwrite: true } }]); - - notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY)); - } -}); - -registerAction2(class ImportProfileAction extends Action2 { - constructor() { - super({ - id: 'workbench.profiles.actions.importProfile', - title: { - value: localize('import profile', "Import..."), - original: 'Import...' - }, - category: PROFILES_CATEGORY, - menu: [ - { - id: ManageProfilesSubMenu, - group: '4_import_export_profiles', - when: PROFILES_ENABLEMENT_CONTEXT, - order: 2 - }, { - id: MenuId.CommandPalette - } - ] + f1: true, + precondition: PROFILES_ENABLEMENT_CONTEXT?.negate(), }); } @@ -470,11 +424,11 @@ registerAction2(class ImportProfileAction extends Action2 { const disposables = new DisposableStore(); const quickPick = disposables.add(quickInputService.createQuickPick()); const updateQuickPickItems = (value?: string) => { - const selectFromFileItem: IQuickPickItem = { label: localize('select from file', "Import from profile file") }; - quickPick.items = value ? [{ label: localize('select from url', "Import from URL"), description: quickPick.value }, selectFromFileItem] : [selectFromFileItem]; + const selectFromFileItem: IQuickPickItem = { label: isSettingProfilesEnabled ? localize('select from file', "Select Settings Profile template file") : localize('import from file', "Import from profile file") }; + quickPick.items = value ? [{ label: isSettingProfilesEnabled ? localize('select from url', "Create from template URL") : localize('import from url', "Import from URL"), description: quickPick.value }, selectFromFileItem] : [selectFromFileItem]; }; - quickPick.title = localize('import profile quick pick title', "Import Settings from a Profile"); - quickPick.placeholder = localize('import profile placeholder', "Provide profile URL or select profile file to import"); + quickPick.title = isSettingProfilesEnabled ? localize('create from profile template quick pick title', "Create from Settings Profile Template") : localize('import profile quick pick title', "Import Settings from a Profile"); + quickPick.placeholder = isSettingProfilesEnabled ? localize('create from profile template placeholder', "Provide a template URL or Select a template file") : localize('import profile placeholder', "Provide profile URL or select profile file to import"); quickPick.ignoreFocusOut = true; disposables.add(quickPick.onDidChangeValue(updateQuickPickItems)); updateQuickPickItems(); @@ -527,7 +481,32 @@ registerAction2(class ImportProfileAction extends Action2 { } } -}); +} +registerAction2(ImportProfileAction); + +class CreateFromTemplateAction extends Action2 { + static readonly ID = 'workbench.profiles.actions.createFromTemplate'; + static readonly TITLE = { + value: localize('create from template profile', "Create from a Settings Profile Template..."), + original: 'Create from a Settings Profile Template...' + }; + constructor() { + super({ + id: CreateFromTemplateAction.ID, + title: CreateFromTemplateAction.TITLE, + category: PROFILES_CATEGORY, + f1: true, + precondition: PROFILES_ENABLEMENT_CONTEXT, + }); + } + + async run(accessor: ServicesAccessor) { + return accessor.get(ICommandService).executeCommand(ImportProfileAction.ID); + } + +} + +registerAction2(CreateFromTemplateAction); // Developer Actions From 395b017424bd17daf1e6ec90a8eac07fada51f61 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 26 Sep 2022 22:49:15 +0200 Subject: [PATCH 096/599] fix styling (#161844) --- .../browser/parts/activitybar/media/activityaction.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 292c36545bc..e4ece0d2fdb 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -179,13 +179,13 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label.profile-activity-item { height: 20px; width: 28px; - margin: 9px; + margin: 14px 10px; padding: 0px; justify-content: center; align-items: center; font-size: 12px; line-height: 16px; - border: 1.5px solid; + border: 2px solid; } /* Right aligned */ From 06bd7ae776e2706a4aba2690d95788327dd16c43 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 26 Sep 2022 23:16:07 +0200 Subject: [PATCH 097/599] [css] use findDocumentSymbols (#161847) [css] use findDocumentSymbols. For #157356 --- extensions/css-language-features/server/src/cssServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/css-language-features/server/src/cssServer.ts b/extensions/css-language-features/server/src/cssServer.ts index ccc0958c502..c5db57340fd 100644 --- a/extensions/css-language-features/server/src/cssServer.ts +++ b/extensions/css-language-features/server/src/cssServer.ts @@ -223,7 +223,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) if (document) { await dataProvidersReady; const stylesheet = stylesheets.get(document); - return getLanguageService(document).findDocumentSymbols(document, stylesheet); + return getLanguageService(document).findDocumentSymbols2(document, stylesheet); } return []; }, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token); From 9883eb4a62e920d3fab3a1d2e56c3f25e44a887c Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 26 Sep 2022 15:02:29 -0700 Subject: [PATCH 098/599] Need to spread the array for format (#161852) --- src/vs/workbench/api/common/extHostLocalizationService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index 38f3b41f632..5e91c2bef1f 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -35,7 +35,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { getMessage(extensionId: string, details: IStringDetails): string { const { message, args, comment } = details; if (this.isDefaultLanguage) { - return format(message, args); + return format(message, ...(args ?? [])); } let key = message; @@ -46,7 +46,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { if (!str) { this.logService.warn(`Using default string since no string found in i18n bundle that has the key: ${key}`); } - return format(str ?? key, args); + return format(str ?? key, ...(args ?? [])); } getBundle(extensionId: string): { [key: string]: string } { From 4f26134e3bdf7830921f6a9d75a653bfecb72b45 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Mon, 26 Sep 2022 15:22:09 -0700 Subject: [PATCH 099/599] Search Tree Compression (#161546) compression tree for search results --- .../search/browser/search.contribution.ts | 16 ++--- .../contrib/search/browser/searchActions.ts | 22 +++--- .../search/browser/searchResultsView.ts | 72 +++++++++++++------ .../contrib/search/browser/searchView.ts | 31 ++++---- 4 files changed, 87 insertions(+), 54 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 3f8f2efa982..6231409e20b 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -23,7 +23,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IListService, WorkbenchListFocusContextKey, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; +import { IListService, WorkbenchListFocusContextKey, WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { Extensions as QuickAccessExtensions, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -104,7 +104,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); const viewer = searchView.getControl(); const focus = tree.getFocus()[0]; @@ -128,7 +128,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); searchView.open(tree.getFocus()[0], false, true, true); } } @@ -145,7 +145,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); accessor.get(IInstantiationService).createInstance(RemoveAction, tree, tree.getFocus()[0]!).run(); } } @@ -159,7 +159,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); accessor.get(IInstantiationService).createInstance(ReplaceAction, tree, tree.getFocus()[0] as Match, searchView).run(); } } @@ -174,7 +174,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); accessor.get(IInstantiationService).createInstance(ReplaceAllAction, searchView, tree.getFocus()[0] as FileMatch).run(); } } @@ -189,7 +189,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); accessor.get(IInstantiationService).createInstance(ReplaceAllInFolderAction, tree, tree.getFocus()[0] as FolderMatch).run(); } } @@ -852,7 +852,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: (accessor, args: any) => { const searchView = getSearchView(accessor.get(IViewsService)); if (searchView) { - const tree: WorkbenchObjectTree = searchView.getControl(); + const tree: WorkbenchCompressibleObjectTree = searchView.getControl(); searchView.openEditorWithMultiCursor(tree.getFocus()[0]); } } diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index cd458000ec8..45015b41829 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -15,7 +15,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILabelService } from 'vs/platform/label/common/label'; -import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; +import { getSelectionKeyboardEvent, WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IViewsService } from 'vs/workbench/common/views'; import { searchRemoveIcon, searchReplaceAllIcon, searchReplaceIcon } from 'vs/workbench/contrib/search/browser/searchIcons'; @@ -396,12 +396,12 @@ export abstract class AbstractSearchAndReplaceAction extends Action { /** * Returns element to focus after removing the given element */ - getElementToFocusAfterRemoved(viewer: WorkbenchObjectTree, elementToRemove: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { + getElementToFocusAfterRemoved(viewer: WorkbenchCompressibleObjectTree, elementToRemove: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { const elementToFocus = this.getNextElementAfterRemoved(viewer, elementToRemove); return elementToFocus || this.getPreviousElementAfterRemoved(viewer, elementToRemove, isTreeViewVisible); } - getNextElementAfterRemoved(viewer: WorkbenchObjectTree, element: RenderableMatch): RenderableMatch { + getNextElementAfterRemoved(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch): RenderableMatch { const navigator: ITreeNavigator = viewer.navigate(element); if (element instanceof FolderMatch) { while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { } @@ -415,7 +415,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { return navigator.current(); } - getPreviousElementAfterRemoved(viewer: WorkbenchObjectTree, element: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { + getPreviousElementAfterRemoved(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { const navigator: ITreeNavigator = viewer.navigate(element); let previousElement = navigator.previous(); // Hence take the previous element. @@ -448,10 +448,10 @@ export abstract class AbstractSearchAndReplaceAction extends Action { class ReplaceActionRunner { constructor( - private viewer: WorkbenchObjectTree, + private viewer: WorkbenchCompressibleObjectTree, private viewlet: SearchView | undefined, - private getElementToFocusAfterRemoved: (viewer: WorkbenchObjectTree, lastElementToBeRemoved: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, - private getPreviousElementAfterRemoved: (viewer: WorkbenchObjectTree, element: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, + private getElementToFocusAfterRemoved: (viewer: WorkbenchCompressibleObjectTree, lastElementToBeRemoved: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, + private getPreviousElementAfterRemoved: (viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, // Services @IReplaceService private readonly replaceService: IReplaceService, @IEditorService private readonly editorService: IEditorService, @@ -573,7 +573,7 @@ export class RemoveAction extends AbstractSearchAndReplaceAction { static readonly LABEL = nls.localize('RemoveAction.label', "Dismiss"); constructor( - private viewer: WorkbenchObjectTree, + private viewer: WorkbenchCompressibleObjectTree, private element: RenderableMatch, @IKeybindingService keyBindingService: IKeybindingService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -640,7 +640,7 @@ export class ReplaceAllInFolderAction extends AbstractSearchAndReplaceAction { static readonly LABEL = nls.localize('file.replaceAll.label', "Replace All"); private replaceRunner: ReplaceActionRunner; - constructor(viewer: WorkbenchObjectTree, private folderMatch: FolderMatch, + constructor(viewer: WorkbenchCompressibleObjectTree, private folderMatch: FolderMatch, @IInstantiationService private readonly instantiationService: IInstantiationService, @IKeybindingService keyBindingService: IKeybindingService ) { @@ -660,7 +660,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { static runQ = Promise.resolve(); private replaceRunner: ReplaceActionRunner; - constructor(viewer: WorkbenchObjectTree, private element: Match, viewlet: SearchView, + constructor(viewer: WorkbenchCompressibleObjectTree, private element: Match, viewlet: SearchView, @IInstantiationService private readonly instantiationService: IInstantiationService, @IKeybindingService keyBindingService: IKeybindingService, ) { @@ -825,7 +825,7 @@ export const focusSearchListCommand: ICommandHandler = accessor => { }); }; -function getElementsToOperateOnInfo(viewer: WorkbenchObjectTree, currElement: RenderableMatch, sortConfig: ISearchConfigurationProperties): { elements: RenderableMatch[]; mustReselect: boolean } { +function getElementsToOperateOnInfo(viewer: WorkbenchCompressibleObjectTree, currElement: RenderableMatch, sortConfig: ISearchConfigurationProperties): { elements: RenderableMatch[]; mustReselect: boolean } { let elements: RenderableMatch[] = viewer.getSelection().filter((x): x is RenderableMatch => x !== null).sort((a, b) => searchComparer(a, b, sortConfig.sortOrder)); const mustReselect = elements.includes(currElement); // this indicates whether we need to re-focus/re-select on a remove. diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index d2bbfc89c65..61e04bbf36a 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -8,7 +8,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; +import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { IAction } from 'vs/base/common/actions'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as paths from 'vs/base/common/path'; @@ -24,8 +24,10 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction } from 'vs/workbench/contrib/search/browser/searchActions'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; -import { FileMatch, Match, RenderableMatch, SearchModel, FolderMatch, FolderMatchNoRoot } from 'vs/workbench/contrib/search/common/searchModel'; +import { FileMatch, Match, RenderableMatch, SearchModel, FolderMatch, FolderMatchNoRoot, FolderMatchWorkspaceRoot } from 'vs/workbench/contrib/search/common/searchModel'; import { isEqual } from 'vs/base/common/resources'; +import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree'; +import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; interface IFolderMatchTemplate { label: IResourceLabel; @@ -73,8 +75,7 @@ export class SearchDelegate implements IListVirtualDelegate { throw new Error('Invalid search tree element'); } } - -export class FolderMatchRenderer extends Disposable implements ITreeRenderer { +export class FolderMatchRenderer extends Disposable implements ICompressibleTreeRenderer { static readonly TEMPLATE_ID = 'folderMatch'; readonly templateId = FolderMatchRenderer.TEMPLATE_ID; @@ -85,16 +86,37 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer, any>, index: number, templateData: IFolderMatchTemplate, height: number | undefined): void { + const compressed = node.element; + const folder = compressed.elements[compressed.elements.length - 1]; + const label = compressed.elements.map(e => e.name()); + + if (folder.resource) { + const fileKind = (folder instanceof FolderMatchWorkspaceRoot) ? FileKind.ROOT_FOLDER : FileKind.FOLDER; + templateData.label.setResource({ resource: folder.resource, name: label }, { + fileKind, + separator: this.labelService.getSeparator(folder.resource.scheme), + }); + } else { + templateData.label.setLabel(nls.localize('searchFolderMatch.other.label', "Other files")); + } + + templateData.actions.clear(); + templateData.actions.context = folder; + this.renderFolderDetails(folder, templateData); + } + renderTemplate(container: HTMLElement): IFolderMatchTemplate { const disposables: IDisposable[] = []; const folderMatchElement = DOM.append(container, DOM.$('.foldermatch')); - const label = this.labels.create(folderMatchElement); + const label = this.labels.create(folderMatchElement, { supportDescriptionHighlights: true, supportHighlights: true }); disposables.push(label); const badge = new CountBadge(DOM.append(folderMatchElement, DOM.$('.badge'))); disposables.push(attachBadgeStyler(badge, this.themeService)); @@ -122,19 +144,8 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer 1 ? nls.localize('searchFileMatches', "{0} files found", count) : nls.localize('searchFileMatch', "{0} file found", count)); - templateData.actions.clear(); - - const actions: IAction[] = []; - if (this.searchModel.isReplaceActive() && count > 0) { - actions.push(this.instantiationService.createInstance(ReplaceAllInFolderAction, this.searchView.getControl(), folderMatch)); - } - - actions.push(this.instantiationService.createInstance(RemoveAction, this.searchView.getControl(), folderMatch)); - templateData.actions.push(actions, { icon: true, label: false }); + this.renderFolderDetails(folderMatch, templateData); } disposeElement(element: ITreeNode, index: number, templateData: IFolderMatchTemplate): void { @@ -143,9 +154,23 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer 1 ? nls.localize('searchFileMatches', "{0} files found", count) : nls.localize('searchFileMatch', "{0} file found", count)); + + const actions: IAction[] = []; + if (this.searchModel.isReplaceActive() && count > 0) { + actions.push(this.instantiationService.createInstance(ReplaceAllInFolderAction, this.searchView.getControl(), folder)); + } + + actions.push(this.instantiationService.createInstance(RemoveAction, this.searchView.getControl(), folder)); + templateData.actions.push(actions, { icon: true, label: false }); + } } -export class FileMatchRenderer extends Disposable implements ITreeRenderer { +export class FileMatchRenderer extends Disposable implements ICompressibleTreeRenderer { static readonly TEMPLATE_ID = 'fileMatch'; readonly templateId = FileMatchRenderer.TEMPLATE_ID; @@ -162,6 +187,10 @@ export class FileMatchRenderer extends Disposable implements ITreeRenderer, any>, index: number, templateData: IFileMatchTemplate, height: number | undefined): void { + throw new Error('Should never happen since node is incompressible.'); + } + renderTemplate(container: HTMLElement): IFileMatchTemplate { const disposables: IDisposable[] = []; const fileMatchElement = DOM.append(container, DOM.$('.filematch')); @@ -210,7 +239,7 @@ export class FileMatchRenderer extends Disposable implements ITreeRenderer { +export class MatchRenderer extends Disposable implements ICompressibleTreeRenderer { static readonly TEMPLATE_ID = 'match'; readonly templateId = MatchRenderer.TEMPLATE_ID; @@ -224,6 +253,9 @@ export class MatchRenderer extends Disposable implements ITreeRenderer, void>, index: number, templateData: IMatchTemplate, height: number | undefined): void { + throw new Error('Should never happen since node is incompressible.'); + } renderTemplate(container: HTMLElement): IMatchTemplate { container.classList.add('linematch'); diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index e209f70f451..4595b58eb50 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -8,7 +8,8 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree'; +import { ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { IAction } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Color, RGBA } from 'vs/base/common/color'; @@ -43,7 +44,7 @@ import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/file import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; +import { getSelectionKeyboardEvent, WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IOpenerService, withSelection } from 'vs/platform/opener/common/opener'; import { IProgress, IProgressService, IProgressStep } from 'vs/platform/progress/common/progress'; @@ -123,7 +124,7 @@ export class SearchView extends ViewPane { private contextMenu: IMenu | null = null; - private tree!: WorkbenchObjectTree; + private tree!: WorkbenchCompressibleObjectTree; private treeLabels!: ResourceLabels; private viewletState: MementoObject; private messagesElement!: HTMLElement; @@ -561,22 +562,22 @@ export class SearchView extends ViewPane { } } - private createResultIterator(collapseResults: ISearchConfigurationProperties['collapseResults']): Iterable> { + private createResultIterator(collapseResults: ISearchConfigurationProperties['collapseResults']): Iterable> { const folderMatches = this.searchResult.folderMatches() .filter(fm => !fm.isEmpty()) .sort(searchMatchComparer); if (folderMatches.length === 1) { - return this.createFolderIterator(folderMatches[0], collapseResults); + return this.createFolderIterator(folderMatches[0], collapseResults, true); } return Iterable.map(folderMatches, folderMatch => { - const children = this.createFolderIterator(folderMatch, collapseResults); - return >{ element: folderMatch, children }; + const children = this.createFolderIterator(folderMatch, collapseResults, true); + return >{ element: folderMatch, children, incompressible: true }; // roots should always be incompressible }); } - private createFolderIterator(folderMatch: FolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterable> { + private createFolderIterator(folderMatch: FolderMatch, collapseResults: ISearchConfigurationProperties['collapseResults'], childFolderIncompressible: boolean): Iterable> { const sortOrder = this.searchConfig.sortOrder; const matchArray = this.isTreeLayoutViewVisible ? folderMatch.matches() : folderMatch.downstreamFileMatches(); @@ -587,7 +588,7 @@ export class SearchView extends ViewPane { if (match instanceof FileMatch) { children = this.createFileIterator(match); } else { - children = this.createFolderIterator(match, collapseResults); + children = this.createFolderIterator(match, collapseResults, false); } let nodeExists = true; try { this.tree.getNode(match); } catch (e) { nodeExists = false; } @@ -595,18 +596,18 @@ export class SearchView extends ViewPane { const collapsed = nodeExists ? undefined : (collapseResults === 'alwaysCollapse' || (match.count() > 10 && collapseResults !== 'alwaysExpand')); - return >{ element: match, children, collapsed }; + return >{ element: match, children, collapsed, incompressible: (match instanceof FileMatch) ? true : childFolderIncompressible }; }); } - private createFileIterator(fileMatch: FileMatch): Iterable> { + private createFileIterator(fileMatch: FileMatch): Iterable> { const matches = fileMatch.matches().sort(searchMatchComparer); - return Iterable.map(matches, r => (>{ element: r })); + return Iterable.map(matches, r => (>{ element: r, incompressible: true })); } - private createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterable> { + private createIterator(match: FolderMatch | FileMatch | SearchResult, collapseResults: ISearchConfigurationProperties['collapseResults']): Iterable> { return match instanceof SearchResult ? this.createResultIterator(collapseResults) : - match instanceof FolderMatch ? this.createFolderIterator(match, collapseResults) : + match instanceof FolderMatch ? this.createFolderIterator(match, collapseResults, false) : this.createFileIterator(match); } @@ -744,7 +745,7 @@ export class SearchView extends ViewPane { }; this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility })); - this.tree = this._register(>this.instantiationService.createInstance(WorkbenchObjectTree, + this.tree = this._register(>this.instantiationService.createInstance(WorkbenchCompressibleObjectTree, 'SearchView', this.resultsElement, delegate, From 121f13044a4d0a51d21eefd137f695b643d2b462 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 26 Sep 2022 18:27:11 -0400 Subject: [PATCH 100/599] Bind `isMobile` context key (#161854) Re: https://github.com/microsoft/vscode/issues/160675 --- src/vs/workbench/browser/contextkeys.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 2ac8feeba1f..08c286d1e84 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext } from 'vs/platform/contextkey/common/contextkeys'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext, IsMobileContext } from 'vs/platform/contextkey/common/contextkeys'; import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext } from 'vs/workbench/common/contextkeys'; import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; @@ -96,6 +96,7 @@ export class WorkbenchContextKeysHandler extends Disposable { IsWebContext.bindTo(this.contextKeyService); IsMacNativeContext.bindTo(this.contextKeyService); IsIOSContext.bindTo(this.contextKeyService); + IsMobileContext.bindTo(this.contextKeyService); RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.remoteAuthority) || ''); From be778b7a51254f1f5dcdb09536e5ee3e3a3a984b Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 26 Sep 2022 16:02:31 -0700 Subject: [PATCH 101/599] Update inlay hints contrast (#161859) * Update inlay hints colors * Update dark+ --- src/vs/platform/theme/common/colorRegistry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 01f9f4743ad..c3d8d33a0b7 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -387,8 +387,8 @@ export const editorActiveLinkForeground = registerColor('editorLink.activeForegr /** * Inline hints */ -export const editorInlayHintForeground = registerColor('editorInlayHint.foreground', { dark: transparent(badgeForeground, .8), light: transparent(badgeForeground, .8), hcDark: badgeForeground, hcLight: badgeForeground }, nls.localize('editorInlayHintForeground', 'Foreground color of inline hints')); -export const editorInlayHintBackground = registerColor('editorInlayHint.background', { dark: transparent(badgeBackground, .6), light: transparent(badgeBackground, .3), hcDark: badgeBackground, hcLight: badgeBackground }, nls.localize('editorInlayHintBackground', 'Background color of inline hints')); +export const editorInlayHintForeground = registerColor('editorInlayHint.foreground', { dark: badgeForeground, light: badgeForeground, hcDark: Color.black, hcLight: badgeForeground }, nls.localize('editorInlayHintForeground', 'Foreground color of inline hints')); +export const editorInlayHintBackground = registerColor('editorInlayHint.background', { dark: transparent(badgeBackground, .8), light: transparent(badgeBackground, .6), hcDark: '#f38518', hcLight: badgeBackground }, nls.localize('editorInlayHintBackground', 'Background color of inline hints')); export const editorInlayHintTypeForeground = registerColor('editorInlayHint.typeForeground', { dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground }, nls.localize('editorInlayHintForegroundTypes', 'Foreground color of inline hints for types')); export const editorInlayHintTypeBackground = registerColor('editorInlayHint.typeBackground', { dark: editorInlayHintBackground, light: editorInlayHintBackground, hcDark: editorInlayHintBackground, hcLight: editorInlayHintBackground }, nls.localize('editorInlayHintBackgroundTypes', 'Background color of inline hints for types')); export const editorInlayHintParameterForeground = registerColor('editorInlayHint.parameterForeground', { dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground }, nls.localize('editorInlayHintForegroundParameter', 'Foreground color of inline hints for parameters')); From 7ac6686975164157c9f1daac9d25a3cb15e19d74 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 26 Sep 2022 19:46:50 -0400 Subject: [PATCH 102/599] `Show Edit Session` should always be available in palette (#161866) --- .../editSessions/browser/editSessions.contribution.ts | 5 ++--- .../contrib/editSessions/browser/editSessionsViews.ts | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 146864b176f..1119e189073 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -10,7 +10,7 @@ import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecyc import { Action2, IAction2Options, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IEditSessionsStorageService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { IEditSessionsStorageService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions'; import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -255,8 +255,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo id: 'workbench.editSessions.actions.showEditSessions', title: { value: localize('show edit session', "Show Edit Sessions"), original: 'Show Edit Sessions' }, category: EDIT_SESSION_SYNC_CATEGORY, - f1: true, - precondition: EDIT_SESSIONS_SIGNED_IN + f1: true }); } diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index 7a70b872e41..ddde6f4d765 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts @@ -10,7 +10,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { Registry } from 'vs/platform/registry/common/platform'; import { TreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView'; import { Extensions, ITreeItem, ITreeViewDataProvider, ITreeViewDescriptor, IViewsRegistry, TreeItemCollapsibleState, TreeViewItemHandleArg, ViewContainer } from 'vs/workbench/common/views'; -import { EDIT_SESSIONS_DATA_VIEW_ID, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_SIGNED_IN_KEY, EDIT_SESSIONS_TITLE, IEditSessionsStorageService } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { EDIT_SESSIONS_DATA_VIEW_ID, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_TITLE, IEditSessionsStorageService } from 'vs/workbench/contrib/editSessions/common/editSessions'; import { URI } from 'vs/base/common/uri'; import { fromNow } from 'vs/base/common/date'; import { Codicon } from 'vs/base/common/codicons'; @@ -54,7 +54,7 @@ export class EditSessionsDataViews extends Disposable { canMoveView: false, treeView, collapsed: false, - when: ContextKeyExpr.and(EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_SHOW_VIEW), + when: ContextKeyExpr.and(EDIT_SESSIONS_SHOW_VIEW), order: 100, hideByDefault: true, }], container); @@ -69,7 +69,7 @@ export class EditSessionsDataViews extends Disposable { localize('storeEditSessionTitle', 'Store Edit Session') ) ), - when: ContextKeyExpr.and(ContextKeyExpr.equals(EDIT_SESSIONS_SIGNED_IN_KEY, true), ContextKeyExpr.equals(EDIT_SESSIONS_COUNT_KEY, 0)), + when: ContextKeyExpr.equals(EDIT_SESSIONS_COUNT_KEY, 0), order: 1 }); From 191bd0908ca43e4ea1fcc4ea2f610c5942018ea3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 26 Sep 2022 18:49:59 -0700 Subject: [PATCH 103/599] Delay custom editor service (#161871) For #159178 --- .../contrib/customEditor/browser/customEditor.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts index f7ce07c9213..a79139a3b19 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; @@ -16,7 +16,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { CustomEditorInput } from './customEditorInput'; import { CustomEditorService } from './customEditors'; -registerSingleton(ICustomEditorService, CustomEditorService, false); +registerSingleton(ICustomEditorService, CustomEditorService, InstantiationType.Delayed); Registry.as(EditorExtensions.EditorPane) .registerEditorPane( From 36b1398cfbabbe91d695717d76b818a788f7b7d9 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Mon, 26 Sep 2022 21:01:24 -0700 Subject: [PATCH 104/599] Search tree in multiroot doesn't collapse to one below root (#161863) Fixes #161858 --- src/vs/workbench/contrib/search/browser/searchActions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 45015b41829..cddc3dd9e41 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -300,7 +300,7 @@ export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { } if (searchView.isTreeLayoutViewVisible && !canCollapseFirstLevel) { const immediateParent = node.parent(); - if (immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot) { + if (!(immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot || immediateParent instanceof SearchResult)) { canCollapseFirstLevel = true; } } @@ -320,8 +320,8 @@ export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { do { const immediateParent = node.parent(); if (immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot) { - if (viewer.hasElement(immediateParent) && viewer.isCollapsed(immediateParent)) { - viewer.collapse(immediateParent, true); + if (viewer.hasElement(node)) { + viewer.collapse(node, true); } else { viewer.collapseAll(); } From 26ef29d3ce07b104acc8aebd6eceb8bdcea46c42 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 27 Sep 2022 00:25:39 -0700 Subject: [PATCH 105/599] Unit test failure: TextFileEditorModel save() and isDirty() (fix #161886) (#161891) --- .../test/browser/textFileEditorModel.test.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts index 0fc86c74e4f..a6fb673f437 100644 --- a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts @@ -21,6 +21,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { SaveReason, SaveSourceRegistry } from 'vs/workbench/common/editor'; import { isEqual } from 'vs/base/common/resources'; import { UTF16be } from 'vs/workbench/services/textfile/common/encoding'; +import { isWeb } from 'vs/base/common/platform'; suite('Files - TextFileEditorModel', () => { @@ -655,8 +656,18 @@ suite('Files - TextFileEditorModel', () => { await accessor.textFileService.save(toResource.call(this, '/path/index_async2.txt')); assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async.txt'))); assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async2.txt'))); - assert.ok(assertIsDefined(getLastResolvedFileStat(model1)).mtime > m1Mtime); - assert.ok(assertIsDefined(getLastResolvedFileStat(model2)).mtime > m2Mtime); + + if (isWeb) { + // web tests does not ensure timeouts are respected at all, so we cannot + // really assert the mtime to be different, only that it is equal or greater. + // https://github.com/microsoft/vscode/issues/161886 + assert.ok(assertIsDefined(getLastResolvedFileStat(model1)).mtime >= m1Mtime); + assert.ok(assertIsDefined(getLastResolvedFileStat(model2)).mtime >= m2Mtime); + } else { + // on desktop we want to assert this condition more strictly though + assert.ok(assertIsDefined(getLastResolvedFileStat(model1)).mtime > m1Mtime); + assert.ok(assertIsDefined(getLastResolvedFileStat(model2)).mtime > m2Mtime); + } model1.dispose(); model2.dispose(); From b4d97007ecb02c27b8770cbf3b935bf26b49508f Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 27 Sep 2022 09:55:36 +0200 Subject: [PATCH 106/599] debug: bump js-debug (#161898) --- product.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.json b/product.json index d97f6cc80b5..6e124afcf90 100644 --- a/product.json +++ b/product.json @@ -46,7 +46,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.71.1", + "version": "1.72.0", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", From 29b8a1e27fb5fc96ce6895e2b53cbe5c32b22a38 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 27 Sep 2022 14:21:59 +0200 Subject: [PATCH 107/599] Run OSS tool (#161956) --- ThirdPartyNotices.txt | 4 +- cglicenses.json | 99 ++++++++++++++++++++++++++++++++ extensions/razor/cgmanifest.json | 28 ++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 5c36a652b4b..02721af49cc 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -9,7 +9,7 @@ This project incorporates components from the projects listed below. The origina 2. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) 3. atom/language-css version 0.45.1 (https://github.com/atom/language-css) 4. atom/language-java version 0.32.1 (https://github.com/atom/language-java) -5. atom/language-sass version 0.62.1 (https://github.com/atom/language-sass) +5. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) 6. atom/language-shellscript version 0.28.2 (https://github.com/atom/language-shellscript) 7. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) 8. better-go-syntax version 1.0.0 (https://github.com/jeff-hykin/better-go-syntax/ ) @@ -42,7 +42,7 @@ This project incorporates components from the projects listed below. The origina 35. language-less version 0.34.2 (https://github.com/atom/language-less) 36. language-php version 0.48.1 (https://github.com/atom/language-php) 37. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -38. marked version 4.0.16 (https://github.com/markedjs/marked) +38. marked version 4.1.0 (https://github.com/markedjs/marked) 39. mdn-data version 1.1.12 (https://github.com/mdn/data) 40. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) 41. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) diff --git a/cglicenses.json b/cglicenses.json index f80a3fac7fc..0ce05392959 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -220,5 +220,104 @@ "", "THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." ] + }, + { + // Reason: The substack org has been deleted on GH + "name": "concat-map", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS", + "FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR", + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER", + "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN", + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] + }, + { + // Reason: The substack org has been deleted on GH + "name": "github-from-package", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS", + "FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR", + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER", + "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN", + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] + }, + { + // Reason: The substack org has been deleted on GH + "name": "minimist", + "fullLicenseText": [ + "This software is released under the MIT license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of", + "this software and associated documentation files (the \"Software\"), to deal in", + "the Software without restriction, including without limitation the rights to", + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software is furnished to do so,", + "subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS", + "FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR", + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER", + "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN", + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] + }, + { + // Reason: The substack org has been deleted on GH + "name": "mkdirp", + "fullLicenseText": [ + "Copyright 2010 James Halliday (mail@substack.net)", + "", + "This project is free software released under the MIT/X11 license:", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in", + "all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN", + "THE SOFTWARE." + ] } ] diff --git a/extensions/razor/cgmanifest.json b/extensions/razor/cgmanifest.json index 2ad1d82c1ea..c0de1392dd5 100644 --- a/extensions/razor/cgmanifest.json +++ b/extensions/razor/cgmanifest.json @@ -10,8 +10,32 @@ } }, "license": "MIT", - "version": "0.3.0" + "version": "0.3.0", + "licenseDetail": [ + "The MIT License (MIT)", + "", + "Copyright (c) 2014 James Summerton", + "", + "Permission is hereby granted, free of charge, to any person obtaining", + "a copy of this software and associated documentation files (the", + "\"Software\"), to deal in the Software without restriction, including", + "without limitation the rights to use, copy, modify, merge, publish,", + "distribute, sublicense, and/or sell copies of the Software, and to", + "permit persons to whom the Software is furnished to do so, subject to", + "the following conditions:", + "", + "The above copyright notice and this permission notice shall be", + "included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,", + "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF", + "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND", + "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE", + "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", + "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION", + "WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] } ], "version": 1 -} \ No newline at end of file +} From 809cceca75dabbdc52529ac157866ca9c713918c Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 27 Sep 2022 14:29:48 +0200 Subject: [PATCH 108/599] update distro (#161957) --- .vscode/settings.json | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 184042b4f2e..3ff60a9bc67 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "git.ignoreLimitWarning": true, "git.branchProtection": [ "main", + "distro", "release/*" ], "git.branchProtectionPrompt": "alwaysCommitToNewBranch", diff --git a/package.json b/package.json index 6aef60a69eb..f96cb537eb8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.72.0", - "distro": "d9fc5ec0abd44d6d2eab4ad5c0cf4ca9c4e839e1", + "distro": "a241d92bfe3ed59289ea4922a282d747f8e59a9e", "author": { "name": "Microsoft Corporation" }, From dbfdbb223310e5bba9e8cf421e12e04f8c18a50d Mon Sep 17 00:00:00 2001 From: Benjamin Simmonds <44439583+benibenj@users.noreply.github.com> Date: Tue, 27 Sep 2022 14:56:54 +0200 Subject: [PATCH 109/599] Fix #161904 (#161927) * Fix #161904 * fix tests --- .../contrib/extensions/browser/extensionsViews.ts | 2 +- .../test/electron-browser/extensionsViews.test.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index d812d8b2a0f..7dc97080775 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -681,7 +681,7 @@ export class ExtensionsListView extends ViewPane { private filterRecentlyUpdatedExtensions(local: IExtension[], query: Query, options: IQueryOptions): IExtension[] { let { value, categories } = this.parseCategories(query.value); const currentTime = Date.now(); - local = local.filter(e => !e.isBuiltin && !e.outdated && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView.RECENT_UPDATE_DURATION); + local = local.filter(e => !e.isBuiltin && !e.outdated && e.local?.updated && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView.RECENT_UPDATE_DURATION); value = value.replace(/@recentlyUpdated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase(); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index cab7fda0f66..e85ca87d7cd 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -59,9 +59,9 @@ suite('ExtensionsViews Tests', () => { didUninstallEvent: Emitter; const localEnabledTheme = aLocalExtension('first-enabled-extension', { categories: ['Themes', 'random'] }, { installedTimestamp: 123456 }); - const localEnabledLanguage = aLocalExtension('second-enabled-extension', { categories: ['Programming languages'], version: '1.0.0' }, { installedTimestamp: Date.now() }); + const localEnabledLanguage = aLocalExtension('second-enabled-extension', { categories: ['Programming languages'], version: '1.0.0' }, { installedTimestamp: Date.now(), updated: false }); const localDisabledTheme = aLocalExtension('first-disabled-extension', { categories: ['themes'] }, { installedTimestamp: 234567 }); - const localDisabledLanguage = aLocalExtension('second-disabled-extension', { categories: ['programming languages'] }, { installedTimestamp: Date.now() - 50000 }); + const localDisabledLanguage = aLocalExtension('second-disabled-extension', { categories: ['programming languages'] }, { installedTimestamp: Date.now() - 50000, updated: true }); const localRandom = aLocalExtension('random-enabled-extension', { categories: ['random'] }, { installedTimestamp: 345678 }); const builtInTheme = aLocalExtension('my-theme', { contributes: { themes: ['my-theme'] } }, { type: ExtensionType.System, installedTimestamp: 222 }); const builtInBasic = aLocalExtension('my-lang', { contributes: { grammars: [{ language: 'my-language' }] } }, { type: ExtensionType.System, installedTimestamp: 666666 }); @@ -381,12 +381,8 @@ suite('ExtensionsViews Tests', () => { test('Test local query with sorting order', async () => { await testableView.show('@recentlyUpdated').then(result => { - assert.strictEqual(result.length, 2, 'Unexpected number of results for @recentlyUpdated'); - const actual = [result.get(0).name, result.get(1).name]; - const expected = [localEnabledLanguage.manifest.name, localDisabledLanguage.manifest.name]; - for (let i = 0; i < actual.length; i++) { - assert.strictEqual(actual[i], expected[i], 'Unexpected default sort order of extensions for @recentlyUpdate query'); - } + assert.strictEqual(result.length, 1, 'Unexpected number of results for @recentlyUpdated'); + assert.strictEqual(result.get(0).name, localDisabledLanguage.manifest.name, 'Unexpected default sort order of extensions for @recentlyUpdate query'); }); await testableView.show('@installed @sort:updateDate').then(result => { From 8b8767eadefaf4898fffa7942e9918ca446275fc Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 27 Sep 2022 15:10:15 +0200 Subject: [PATCH 110/599] Badge value is not type validated (#161966) Fixes #161919 --- src/vs/workbench/api/common/extHostTreeViews.ts | 6 ++++-- src/vs/workbench/api/common/extHostTypes.ts | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 537c3e15849..7722444d759 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -14,7 +14,7 @@ import { CheckboxUpdate, DataTransferDTO, ExtHostTreeViewsShape, MainThreadTreeV import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions, TreeCommand, TreeViewPaneHandleArg, ITreeItemCheckboxState } from 'vs/workbench/common/views'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { asPromise } from 'vs/base/common/async'; -import { TreeItemCollapsibleState, TreeItemCheckboxState, ThemeIcon, MarkdownString as MarkdownStringType, TreeItem } from 'vs/workbench/api/common/extHostTypes'; +import { TreeItemCollapsibleState, TreeItemCheckboxState, ThemeIcon, MarkdownString as MarkdownStringType, TreeItem, ViewBadge as ExtHostViewBadge } from 'vs/workbench/api/common/extHostTypes'; import { isUndefinedOrNull, isString } from 'vs/base/common/types'; import { equals, coalesce } from 'vs/base/common/arrays'; import { ILogService } from 'vs/platform/log/common/log'; @@ -122,7 +122,9 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { return treeView.badge; }, set badge(badge: vscode.ViewBadge | undefined) { - treeView.badge = badge; + if (ExtHostViewBadge.isViewBadge(badge)) { + treeView.badge = badge; + } }, reveal: (element: T, options?: IRevealOptions): Promise => { return treeView.reveal(element, options); diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 57c2608bdfc..22e9e1f0441 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2460,6 +2460,22 @@ export enum ProgressLocation { Notification = 15 } +export namespace ViewBadge { + export function isViewBadge(thing: any): thing is vscode.ViewBadge { + const viewBadgeThing = thing as vscode.ViewBadge; + + if (!isNumber(viewBadgeThing.value)) { + console.log('INVALID view badge, invalid value', viewBadgeThing.value); + return false; + } + if (viewBadgeThing.tooltip && !isString(viewBadgeThing.tooltip)) { + console.log('INVALID view badge, invalid tooltip', viewBadgeThing.tooltip); + return false; + } + return true; + } +} + @es5ClassCompat export class TreeItem { From 43894c6ea09cb984c643e4ef2990202ecec4e4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 27 Sep 2022 07:29:29 -0700 Subject: [PATCH 111/599] add Cargo.toml for inno-updater (#161976) --- build/win32/Cargo.toml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 build/win32/Cargo.toml diff --git a/build/win32/Cargo.toml b/build/win32/Cargo.toml new file mode 100644 index 00000000000..decae65f9e6 --- /dev/null +++ b/build/win32/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "inno_updater" +version = "0.9.0" +authors = ["Microsoft "] +build = "build.rs" + +[dependencies] +byteorder = "1" +crc = "^1.0.0" +slog = "2.1.1" +slog-async = "2.2.0" +slog-term = "2.3.0" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "^0.3.9", features = ["winuser", "libloaderapi", "commctrl", "processthreadsapi", "tlhelp32", "handleapi", "psapi", "errhandlingapi", "winbase", "shellapi"] } + +[profile.release] +lto = true +panic = 'abort' From 70a7ce4d1a5b23c3081a8d1c6a5e0e91f188cf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 27 Sep 2022 07:55:34 -0700 Subject: [PATCH 112/599] Auto releasing a build needs peer approval (#161981) * make sure VSCODE_RELEASE has peer approval * boom --- build/azure-pipelines/product-build.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 25b0c188196..666d9489da3 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -593,10 +593,28 @@ stages: steps: - template: product-publish.yml + - ${{ if and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')) }}: + - stage: ApproveRelease + dependsOn: [] # run in parallel to compile stage + pool: vscode-1es-linux + jobs: + - deployment: ApproveRelease + displayName: "Approve Release" + environment: "vscode" + variables: + skipComponentGovernanceDetection: true + strategy: + runOnce: + deploy: + steps: + - checkout: none + - ${{ if or(and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')), and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(variables['VSCODE_SCHEDULEDBUILD'], true))) }}: - stage: Release dependsOn: - Publish + - ${{ if and(parameters.VSCODE_RELEASE, eq(parameters.VSCODE_DISTRO_REF, ' ')) }}: + - ApproveRelease pool: vscode-1es-linux jobs: - job: ReleaseBuild From fa91f636926ddb0b581f1584108264973dbeb481 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 08:06:21 -0700 Subject: [PATCH 113/599] Prevent exception in attachToElement Part of #160914 --- .../contrib/terminal/browser/terminalGroupService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts index 1e7b0333e87..9835ac1fbca 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroupService.ts @@ -179,7 +179,9 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe if (pane && !pane.isVisible()) { await this._viewsService.openView(TERMINAL_VIEW_ID, focus); } - await instance.focusWhenReady(true); + // Do not await the focus as setVisible must be called immediately to ensure + // something else didn't steal focus + instance.focusWhenReady(true); // HACK: as a workaround for https://github.com/microsoft/vscode/issues/134692, // this will trigger a forced refresh of the viewport to sync the viewport and scroll bar. // This can likely be removed after https://github.com/xtermjs/xterm.js/issues/291 is From ea5b244abdd8604bc7a3761a7a625b0e87ac5167 Mon Sep 17 00:00:00 2001 From: Harald Kirschner Date: Tue, 27 Sep 2022 17:15:57 +0200 Subject: [PATCH 114/599] File snippets for HTML and PHP (#161881) * Adding file snippets for HTML and PHP to start small. * Adding TS --- extensions/html/package.json | 6 ++++++ extensions/html/snippets/html.code-snippets | 18 ++++++++++++++++++ extensions/php/snippets/php.code-snippets | 2 ++ .../snippets/typescript.code-snippets | 1 + 4 files changed, 27 insertions(+) create mode 100644 extensions/html/snippets/html.code-snippets diff --git a/extensions/html/package.json b/extensions/html/package.json index aad035c05cc..238f1348955 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -76,6 +76,12 @@ "meta.tag string.quoted": "other" } } + ], + "snippets": [ + { + "language": "html", + "path": "./snippets/html.code-snippets" + } ] }, "repository": { diff --git a/extensions/html/snippets/html.code-snippets b/extensions/html/snippets/html.code-snippets new file mode 100644 index 00000000000..62d61b43b7b --- /dev/null +++ b/extensions/html/snippets/html.code-snippets @@ -0,0 +1,18 @@ +{ + "html doc": { + "isFileTemplate": true, + "body": [ + "", + "", + "", + "\t", + "\t${1:title}", + "", + "", + "\t$0", + "", + "" + ], + "description": "HTML Document" + } +} diff --git a/extensions/php/snippets/php.code-snippets b/extensions/php/snippets/php.code-snippets index 9c061291647..3c213765b4b 100644 --- a/extensions/php/snippets/php.code-snippets +++ b/extensions/php/snippets/php.code-snippets @@ -12,6 +12,7 @@ }, "PHPDoc class …": { "prefix": "doc_class", + "isFileTemplate": true, "body": [ "/**", " * ${6:undocumented class}", @@ -42,6 +43,7 @@ }, "PHPDoc function …": { "prefix": "doc_f", + "isFileTemplate": true, "body": [ "/**", " * ${1:undocumented function summary}", diff --git a/extensions/typescript-basics/snippets/typescript.code-snippets b/extensions/typescript-basics/snippets/typescript.code-snippets index 0162ef50975..35b2aa1711c 100644 --- a/extensions/typescript-basics/snippets/typescript.code-snippets +++ b/extensions/typescript-basics/snippets/typescript.code-snippets @@ -14,6 +14,7 @@ }, "Class Definition": { "prefix": "class", + "isFileTemplate": true, "body": [ "class ${1:name} {", "\tconstructor(${2:parameters}) {", From 6274321c7a42ede84ebb28522cab34009cbb003c Mon Sep 17 00:00:00 2001 From: Benjamin Simmonds <44439583+benibenj@users.noreply.github.com> Date: Tue, 27 Sep 2022 17:53:03 +0200 Subject: [PATCH 115/599] show builtin extensions if the require an action (#161986) * show builtin extensions if the require an action * Show outdated builtin extensions but with no ignor --- .../contrib/extensions/browser/extensionsActions.ts | 11 ++++++++--- .../contrib/extensions/browser/extensionsViews.ts | 9 +++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index ffcefca9cbd..102fec7ea15 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -877,10 +877,15 @@ export class SkipUpdateAction extends AbstractUpdateAction { } override update() { - super.update(); - if (this.extension) { - this._checked = this.extensionsWorkbenchService.isExtensionIgnoresUpdates(this.extension); + if (!this.extension) { + return; } + if (this.extension.isBuiltin) { + this.enabled = false; + return; + } + super.update(); + this._checked = this.extensionsWorkbenchService.isExtensionIgnoresUpdates(this.extension); } override async run(): Promise { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 7dc97080775..575a220bc18 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -512,14 +512,15 @@ export class ExtensionsListView extends ViewPane { value = value.replace(/@installed/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase(); - let result = local - .filter(e => !e.isBuiltin - && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) - && (!categories.length || categories.some(category => (e.local && e.local.manifest.categories || []).some(c => c.toLowerCase() === category)))); + const matchingText = (e: IExtension) => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) + && (!categories.length || categories.some(category => (e.local && e.local.manifest.categories || []).some(c => c.toLowerCase() === category))); + let result; if (options.sortBy !== undefined) { + result = local.filter(e => !e.isBuiltin && matchingText(e)); result = this.sortExtensions(result, options); } else { + result = local.filter(e => (!e.isBuiltin || e.outdated || e.reloadRequiredStatus !== undefined) && matchingText(e)); const runningExtensionsById = runningExtensions.reduce((result, e) => { result.set(ExtensionIdentifier.toKey(e.identifier.value), e); return result; }, new Map()); const defaultSort = (e1: IExtension, e2: IExtension) => { From 97fd38a375b0b5b785d7e215818ab1c194658605 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 27 Sep 2022 09:26:20 -0700 Subject: [PATCH 116/599] Update inserted/removed diff character background (#161275) * Update diff inserted/removed text background * Update inserted text color --- src/vs/platform/theme/common/colorRegistry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index c3d8d33a0b7..d4ba695131b 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -406,8 +406,8 @@ export const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAu export const defaultInsertColor = new Color(new RGBA(155, 185, 85, .2)); export const defaultRemoveColor = new Color(new RGBA(255, 0, 0, .2)); -export const diffInserted = registerColor('diffEditor.insertedTextBackground', { dark: '#9ccc2c33', light: '#9ccc2c66', hcDark: null, hcLight: null }, nls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true); -export const diffRemoved = registerColor('diffEditor.removedTextBackground', { dark: '#ff000066', light: '#ff00004d', hcDark: null, hcLight: null }, nls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true); +export const diffInserted = registerColor('diffEditor.insertedTextBackground', { dark: '#9ccc2c33', light: '#9ccc2c40', hcDark: null, hcLight: null }, nls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true); +export const diffRemoved = registerColor('diffEditor.removedTextBackground', { dark: '#ff000033', light: '#ff000033', hcDark: null, hcLight: null }, nls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true); export const diffInsertedLine = registerColor('diffEditor.insertedLineBackground', { dark: defaultInsertColor, light: defaultInsertColor, hcDark: null, hcLight: null }, nls.localize('diffEditorInsertedLines', 'Background color for lines that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true); export const diffRemovedLine = registerColor('diffEditor.removedLineBackground', { dark: defaultRemoveColor, light: defaultRemoveColor, hcDark: null, hcLight: null }, nls.localize('diffEditorRemovedLines', 'Background color for lines that got removed. The color must not be opaque so as not to hide underlying decorations.'), true); From c812153801324eafd631a77769cebe2cb3ff0550 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 27 Sep 2022 18:36:04 +0200 Subject: [PATCH 117/599] badge should not allow decimal values (#162001) Fixes #161990 --- src/vs/workbench/api/common/extHostTreeViews.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 7722444d759..3ade5261221 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -123,7 +123,10 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { }, set badge(badge: vscode.ViewBadge | undefined) { if (ExtHostViewBadge.isViewBadge(badge)) { - treeView.badge = badge; + treeView.badge = { + value: Math.floor(badge.value), + tooltip: badge.tooltip + }; } }, reveal: (element: T, options?: IRevealOptions): Promise => { From a29fd5ed153f849cdc0e998e2ca3acf3cc41e64c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 27 Sep 2022 09:36:28 -0700 Subject: [PATCH 118/599] show correct path for install dir warning (#161996) --- src/vs/workbench/electron-sandbox/window.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 579ad0ea8bc..388e0886346 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -683,7 +683,7 @@ export class NativeWindow extends Disposable { if (this.uriIdentityService.extUri.isEqualOrParent(folder.uri, installLocationUri)) { this.bannerService.show({ id: 'appRootWarning.banner', - message: localize('appRootWarning.banner', "Files you store within the installation folder ('{0}') may be OVERWRITTEN or DELETED IRREVERSIBLY without warning at update time.", this.environmentService.appRoot), + message: localize('appRootWarning.banner', "Files you store within the installation folder ('{0}') may be OVERWRITTEN or DELETED IRREVERSIBLY without warning at update time.", this.labelService.getUriLabel(installLocationUri)), icon: Codicon.warning }); From 0279e216c538caaf2624856c8a944c0974f60467 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 27 Sep 2022 10:17:33 -0700 Subject: [PATCH 119/599] Change "load all" to "load more" (#162015) Change "load all" to "load more", fix #161884 --- .../contrib/debug/browser/callStackView.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 7643f1a8057..74631ace0ca 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -229,7 +229,7 @@ export class CallStackView extends ViewPane { this.instantiationService.createInstance(ThreadsRenderer), this.instantiationService.createInstance(StackFramesRenderer), new ErrorsRenderer(), - new LoadAllRenderer(this.themeService), + new LoadMoreRenderer(this.themeService), new ShowMoreRenderer(this.themeService) ], this.dataSource, { accessibilityProvider: new CallStackAccessibilityProvider(), @@ -259,7 +259,7 @@ export class CallStackView extends ViewPane { return e; } if (e instanceof ThreadAndSessionIds) { - return LoadAllRenderer.LABEL; + return LoadMoreRenderer.LABEL; } return localize('showMoreStackFrames2', "Show More Stack Frames"); @@ -804,14 +804,14 @@ class ErrorsRenderer implements ICompressibleTreeRenderer { - static readonly ID = 'loadAll'; - static readonly LABEL = localize('loadAllStackFrames', "Load All Stack Frames"); +class LoadMoreRenderer implements ICompressibleTreeRenderer { + static readonly ID = 'loadMore'; + static readonly LABEL = localize('loadAllStackFrames', "Load More Stack Frames"); constructor(private readonly themeService: IThemeService) { } get templateId(): string { - return LoadAllRenderer.ID; + return LoadMoreRenderer.ID; } renderTemplate(container: HTMLElement): ILabelTemplateData { @@ -826,7 +826,7 @@ class LoadAllRenderer implements ICompressibleTreeRenderer, index: number, data: ILabelTemplateData): void { - data.label.textContent = LoadAllRenderer.LABEL; + data.label.textContent = LoadMoreRenderer.LABEL; } renderCompressedElements(node: ITreeNode, FuzzyScore>, index: number, templateData: ILabelTemplateData, height: number | undefined): void { @@ -904,7 +904,7 @@ class CallStackDelegate implements IListVirtualDelegate { return ErrorsRenderer.ID; } if (element instanceof ThreadAndSessionIds) { - return LoadAllRenderer.ID; + return LoadMoreRenderer.ID; } // element instanceof Array @@ -1067,7 +1067,7 @@ class CallStackAccessibilityProvider implements IListAccessibilityProvider Date: Tue, 27 Sep 2022 20:13:22 +0200 Subject: [PATCH 120/599] fix #161933 (#162029) --- src/vs/workbench/api/common/extHostOutput.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index abe63cff8da..09741ef4a3c 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -35,6 +35,7 @@ class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOu readonly extension: IExtensionDescription, ) { super(); + this._register(logger.onDidChangeLogLevel(level => this.setLevel(level))); } appendLine(value: string): void { @@ -235,7 +236,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { ...this.createExtHostOutputChannel(name, channelPromise), trace(value: string, ...args: any[]): void { validate(); - channelPromise.then(channel => channel.info(value, ...args)); + channelPromise.then(channel => channel.trace(value, ...args)); }, debug(value: string, ...args: any[]): void { validate(); From 83bbb3941f76c88678c280b0dd8225f03a5f78b3 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 27 Sep 2022 12:34:40 -0700 Subject: [PATCH 121/599] Fix settings sync typo (#162050) --- .../userDataSync/browser/userDataSyncWorkbenchService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 8cf00b48ffd..36368bb699e 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -381,7 +381,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat if (status === SyncStatus.HasConflicts) { progress.report({ message: localize('resolving conflicts', "Resolving conflicts...") }); } else { - progress.report({ message: localize('syncing...', "Turnin on...") }); + progress.report({ message: localize('syncing...', "Turning on...") }); } })); await manualSyncTask.merge(); From 4e074b46318270d728a0171d601beb8938ee0916 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 12:59:08 -0700 Subject: [PATCH 122/599] Update xterm - Fix priority task queue and idle callback fallback xtermjs/xterm.js#4155 - Remove queuemicrotask polyfill xtermjs/xterm.js#4154 - Fix repetitive microtask problem xtermjs/xterm.js#4153 --- package.json | 4 ++-- remote/package.json | 4 ++-- remote/web/package.json | 2 +- remote/web/yarn.lock | 8 ++++---- remote/yarn.lock | 16 ++++++++-------- yarn.lock | 16 ++++++++-------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index f96cb537eb8..50ebfd5ab89 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.10", + "xterm": "5.1.0-beta.13", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.10", + "xterm-headless": "5.1.0-beta.13", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index 399771595e0..f2e0e2c39e6 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.10", + "xterm": "5.1.0-beta.13", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.10", + "xterm-headless": "5.1.0-beta.13", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index ced3eb18679..e4145725bfe 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,7 +11,7 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.10", + "xterm": "5.1.0-beta.13", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-unicode11": "0.5.0-beta.1", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 72a9a2160ac..2227e164923 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -88,7 +88,7 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm@5.1.0-beta.10: - version "5.1.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" - integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== +xterm@5.1.0-beta.13: + version "5.1.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" + integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== diff --git a/remote/yarn.lock b/remote/yarn.lock index f1b96db5bb3..2faad009179 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -813,15 +813,15 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.10: - version "5.1.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.10.tgz#2a747a1fa96a877c26aea3311b0a62ddae7e2578" - integrity sha512-tRoXL1e87XOIuZ5yIjK43q3x9/MqZ+K24Na7UTl+AqmkXjb5svXfShMV3x8HiNAyxcrnL/MXNilfLoniQGacIA== +xterm-headless@5.1.0-beta.13: + version "5.1.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.13.tgz#ff1ae4bf9a9962410fb46dbe19c73f9b93ae4539" + integrity sha512-jbCCuJgpnv1Ncda45J08wlEAVEReYQonFx9Nu9YvjQyvnN5h0PkIAztFHHO3bjRPFHCC44fPfcmvJOvA4pZAZA== -xterm@5.1.0-beta.10: - version "5.1.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" - integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== +xterm@5.1.0-beta.13: + version "5.1.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" + integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index d85a254fc80..879f9671836 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11653,15 +11653,15 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.10: - version "5.1.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.10.tgz#2a747a1fa96a877c26aea3311b0a62ddae7e2578" - integrity sha512-tRoXL1e87XOIuZ5yIjK43q3x9/MqZ+K24Na7UTl+AqmkXjb5svXfShMV3x8HiNAyxcrnL/MXNilfLoniQGacIA== +xterm-headless@5.1.0-beta.13: + version "5.1.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.13.tgz#ff1ae4bf9a9962410fb46dbe19c73f9b93ae4539" + integrity sha512-jbCCuJgpnv1Ncda45J08wlEAVEReYQonFx9Nu9YvjQyvnN5h0PkIAztFHHO3bjRPFHCC44fPfcmvJOvA4pZAZA== -xterm@5.1.0-beta.10: - version "5.1.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.10.tgz#2f55e4e6d63b45152c768857accc06c47920f898" - integrity sha512-McztCKJJ2QvY28oXwK9ACMbbNTKiKQSbli+tZJIROkICmA7QFizwsQBQDoOtAw0po0dP1CInLJXwurqZmfCymQ== +xterm@5.1.0-beta.13: + version "5.1.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" + integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== y18n@^3.2.1: version "3.2.2" From b712a791e8fdc8375164b6bf37d881469345c9c8 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 27 Sep 2022 13:25:20 -0700 Subject: [PATCH 123/599] tweak regex for create PR (#162055) fix #161911 --- .../contrib/terminal/browser/terminalQuickFixBuiltinActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index b25b1e6c4b9..861b33b4f10 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -16,7 +16,7 @@ export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /most similar command is\s+([^\s]{3,})/; export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; -export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s+remote:\s+(https:.+pull.+)/; +export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*remote:\s*(https:.+pull.+)/; export function gitSimilarCommand(): ITerminalQuickFixOptions { return { From 8b4a451a231b1893609519453ce31ed058515c79 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 27 Sep 2022 13:25:31 -0700 Subject: [PATCH 124/599] tweak regex for git similar command (#162057) fix #161997 --- .../contrib/terminal/browser/terminalQuickFixBuiltinActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 861b33b4f10..c077701ab8a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -13,7 +13,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.+/; -export const GitSimilarOutputRegex = /most similar command is\s+([^\s]{3,})/; +export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*remote:\s*(https:.+pull.+)/; From b4600dab2901669075f529744fabc5a9ec809b26 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 27 Sep 2022 13:39:05 -0700 Subject: [PATCH 125/599] Fix audio mime type listing (#162063) --- extensions/image-preview/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index a3bc0dc4f82..20d5b083e3a 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -50,7 +50,7 @@ "priority": "builtin", "selector": [ { - "filenamePattern": "*.{mp3,wav,opus,aac}" + "filenamePattern": "*.{mp3,wav,ogg,aac}" } ] }, From ca635a3cdfc74f11c08607648e38bdd8fdea2b07 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 27 Sep 2022 14:28:22 -0700 Subject: [PATCH 126/599] Add playsInline to video (#162065) We want the video to play in the editor, not go fullscreen --- extensions/image-preview/media/videoPreview.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/image-preview/media/videoPreview.js b/extensions/image-preview/media/videoPreview.js index a8f1f6955fd..54aa60ad86f 100644 --- a/extensions/image-preview/media/videoPreview.js +++ b/extensions/image-preview/media/videoPreview.js @@ -30,6 +30,7 @@ if (settings.src !== null) { video.src = settings.src; } + video.playsInline = true; video.controls = true; function onLoaded() { From 4f0edb3fe78fa3f443acf012889c628aaf3a27cd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 27 Sep 2022 14:28:39 -0700 Subject: [PATCH 127/599] Pick up latest TS 4.8.4 recovery (#162059) --- extensions/package.json | 2 +- extensions/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/package.json b/extensions/package.json index 8f1df05f4e5..e12225cc76f 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "4.8.3" + "typescript": "4.8.4" }, "scripts": { "postinstall": "node ./postinstall.mjs" diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 919cf0aa6a8..619417cb66c 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -42,10 +42,10 @@ node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== -typescript@4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88" - integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig== +typescript@4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== vscode-grammar-updater@^1.1.0: version "1.1.0" From 08578603ee434e8d6574a26f1f83cda98335b2dc Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 27 Sep 2022 14:36:44 -0700 Subject: [PATCH 128/599] focus on first item in quick fix menu (#162064) --- .../workbench/contrib/terminal/browser/xterm/quickFixAddon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index 9a78883c533..2fe8a69d30a 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -121,7 +121,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, if (actions) { this._decorationMarkerIds.add(decoration.marker.id); dom.addDisposableListener(e, dom.EventType.CLICK, () => { - this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions }); + this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions, autoSelectFirstItem: true }); }); } } From 8f439177663ad47f1ae607b412289d2fcab79ec8 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Tue, 27 Sep 2022 14:53:22 -0700 Subject: [PATCH 129/599] Fix #161917. Bind pointer event listener on overview container (#162061) --- .../contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts index a18ea3021c3..7ccc71587d3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffOverviewRuler.ts @@ -66,7 +66,7 @@ export class NotebookDiffOverviewRuler extends Themable { this._renderOverviewViewport(); })); - this._register(DOM.addStandardDisposableListener(this._overviewViewportDomElement.domNode, DOM.EventType.POINTER_DOWN, (e) => { + this._register(DOM.addStandardDisposableListener(container, DOM.EventType.POINTER_DOWN, (e) => { this.notebookEditor.delegateVerticalScrollbarPointerDown(e); })); } From 2d6d6cd72a4b1099b2e0b85c6d0ba675395f064d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 14:58:24 -0700 Subject: [PATCH 130/599] Fix free port quick fix on Windows Valid port numbers are 1-65535, but 1-1023 are reserved. Fixes #161775 --- .../terminal/browser/terminalQuickFixBuiltinActions.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index c077701ab8a..db6b8e23e78 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IAction } from 'vs/base/common/actions'; -import { isWindows } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { QuickFixMatchResult, ITerminalQuickFixAction, ITerminalQuickFixOptions, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; @@ -14,7 +13,7 @@ export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; -export const FreePortOutputRegex = /address already in use \d\.\d\.\d\.\d:(\d\d\d\d)|Unable to bind [^ ]*:(\d+)|can't listen on port (\d+)|listen EADDRINUSE [^ ]*:(\d+)/; +export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*remote:\s*(https:.+pull.+)/; @@ -50,8 +49,7 @@ export function freePort(terminalInstance?: Partial): ITermin return { quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '', commandLineMatcher: AnyCommandLineRegex, - // TODO: Support free port on Windows https://github.com/microsoft/vscode/issues/161775 - outputMatcher: isWindows ? undefined : { + outputMatcher: { lineMatcher: FreePortOutputRegex, anchor: 'bottom', offset: 0, From 58f254ace22759cf0ecde4d30c605879598d41fc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 15:04:11 -0700 Subject: [PATCH 131/599] Improve free port messages --- .../contrib/terminal/browser/terminalProcessManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 08da73cc57b..4eb15699743 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -178,10 +178,10 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce try { if (this._process?.freePortKillProcess) { const result = await this._process?.freePortKillProcess(port); - this._notificationService.notify({ message: `Killed process w ID: ${result.processId} to free port ${result.port}`, severity: Severity.Info }); + this._notificationService.notify({ message: localize('killportsuccess', 'Killed process with PID {0} listening on port {1}', result.processId, result.port), severity: Severity.Info }); } } catch (e) { - this._notificationService.notify({ message: `Could not kill process for port ${port} wth error ${e}`, severity: Severity.Warning }); + this._notificationService.notify({ message: localize('killportfailure', 'Could not kill process listening on port {0}, command exited with error {1}', port, e), severity: Severity.Warning }); } } From 0994daba5c976d63b7986a7354a9baf021cc9313 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 27 Sep 2022 15:08:49 -0700 Subject: [PATCH 132/599] Fix selection of notebook renderers for outputs (#162068) Fix selection of notebook renderers This fixes selection of notebook renderers when multiple renderers exist for a given mime type --- .../browser/view/renderers/webviewPreloads.ts | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index c0f2e223fea..75881cc86d8 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1489,11 +1489,28 @@ async function webviewPreloads(ctx: PreloadContext) { this._renderers.get(rendererId)?.disposeOutputItem(outputId); } - public async render(info: rendererApi.OutputItem, element: HTMLElement, signal: AbortSignal): Promise { - const renderers = Array.from(this._renderers.values()) - .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends); + public async render(info: rendererApi.OutputItem, preferredRendererId: string | undefined, element: HTMLElement, signal: AbortSignal): Promise { + let renderer: Renderer | undefined; - if (!renderers.length) { + if (typeof preferredRendererId === 'string') { + renderer = Array.from(this._renderers.values()) + .find((renderer) => renderer.data.id === preferredRendererId); + } else { + const renderers = Array.from(this._renderers.values()) + .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends); + + if (renderers.length) { + // De-prioritize built-in renderers + renderers.sort((a, b) => +a.data.isBuiltin - +b.data.isBuiltin); + + // Use first renderer we find in sorted list + renderer = renderers[0]; + } + } + + if (renderer) { + await renderer.renderOutputItem(info, element, signal); + } else { const errorContainer = document.createElement('div'); const error = document.createElement('div'); @@ -1509,15 +1526,7 @@ async function webviewPreloads(ctx: PreloadContext) { element.innerText = ''; element.appendChild(errorContainer); - - return; } - - // De-prioritize built-in renderers - renderers.sort((a, b) => +a.data.isBuiltin - +b.data.isBuiltin); - - // Use first renderer we find in sorted list - await renderers[0].renderOutputItem(info, element, signal); } }(); @@ -1874,7 +1883,7 @@ async function webviewPreloads(ctx: PreloadContext) { const controller = new AbortController(); this.renderTaskAbort = controller; try { - await renderers.render(this.outputItem, this.element, this.renderTaskAbort.signal); + await renderers.render(this.outputItem, undefined, this.element, this.renderTaskAbort.signal); } finally { if (this.renderTaskAbort === controller) { this.renderTaskAbort = undefined; @@ -2001,7 +2010,7 @@ async function webviewPreloads(ctx: PreloadContext) { public async renderOutputElement(data: webviewMessages.ICreationRequestMessage, preloadErrors: ReadonlyArray, signal: AbortSignal) { const outputElement = this.createOutputElement(data); - await outputElement.render(data.content, preloadErrors, signal); + await outputElement.render(data.content, data.rendererId, preloadErrors, signal); // don't hide until after this step so that the height is right outputElement.element.style.visibility = data.initiallyHidden ? 'hidden' : ''; @@ -2132,6 +2141,7 @@ async function webviewPreloads(ctx: PreloadContext) { public readonly element: HTMLElement; private _content?: { readonly content: webviewMessages.ICreationContent; + readonly preferredRendererId: string | undefined; readonly preloadErrors: ReadonlyArray; }; private hasResizeObserver = false; @@ -2164,11 +2174,11 @@ async function webviewPreloads(ctx: PreloadContext) { this.renderTaskAbort = undefined; } - public async render(content: webviewMessages.ICreationContent, preloadErrors: ReadonlyArray, signal?: AbortSignal) { + public async render(content: webviewMessages.ICreationContent, preferredRendererId: string | undefined, preloadErrors: ReadonlyArray, signal?: AbortSignal) { this.renderTaskAbort?.abort(); this.renderTaskAbort = undefined; - this._content = { content, preloadErrors }; + this._content = { content, preferredRendererId, preloadErrors }; if (content.type === 0 /* RenderOutputType.Html */) { const trustedHtml = ttPolicy?.createHTML(content.htmlContent) ?? content.htmlContent; this.element.innerHTML = trustedHtml as string; @@ -2186,7 +2196,7 @@ async function webviewPreloads(ctx: PreloadContext) { signal?.addEventListener('abort', () => controller.abort()); try { - await renderers.render(item, this.element, controller.signal); + await renderers.render(item, preferredRendererId, this.element, controller.signal); } finally { if (this.renderTaskAbort === controller) { this.renderTaskAbort = undefined; @@ -2229,13 +2239,13 @@ async function webviewPreloads(ctx: PreloadContext) { public rerender() { if (this._content) { - this.render(this._content.content, this._content.preloadErrors); + this.render(this._content.content, this._content.preferredRendererId, this._content.preloadErrors); } } public updateAndRerender(content: webviewMessages.ICreationContent) { if (this._content) { - this._content = { content, preloadErrors: this._content.preloadErrors }; + this._content = { content, preferredRendererId: this._content.preferredRendererId, preloadErrors: this._content.preloadErrors }; this.rerender(); } } From c66e0fa5759c98bc0903a8ac88ebd6876357fd24 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 15:15:52 -0700 Subject: [PATCH 133/599] Add terminal quick fix to commands to skip shell Fixes #162078 --- src/vs/workbench/contrib/terminal/common/terminal.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e886f17e418..c165c6cc43e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -615,6 +615,7 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TerminalCommandId.New, TerminalCommandId.Paste, TerminalCommandId.PasteSelection, + TerminalCommandId.QuickFix, TerminalCommandId.ResizePaneDown, TerminalCommandId.ResizePaneLeft, TerminalCommandId.ResizePaneRight, From e77c6d808a41718b7d1a0680bc19f1ac4aad7f6c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 15:51:19 -0700 Subject: [PATCH 134/599] Fix extracting correct PID on Windows --- src/vs/platform/terminal/node/ptyService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 4b23e3c42b7..85ea2b0cc33 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -124,7 +124,7 @@ export class PtyService extends Disposable implements IPtyService { await new Promise((resolve, reject) => { exec(`kill ${processId}`, {}, (err, stdout) => { if (err) { - return reject(`Problem occurred when killing the process w ID: ${processId}`); + return reject(`Problem occurred when killing the process with PID: ${processId}`); } resolve(stdout); }); @@ -143,13 +143,13 @@ export class PtyService extends Disposable implements IPtyService { }); const processesForPort = stdout.split('\n'); if (processesForPort.length >= 1) { - const capturePid = /LISTENING\s+(\d{3})/; + const capturePid = /LISTENING\s+(\d+)/; const processId = processesForPort[0].match(capturePid)?.[1]; if (processId) { await new Promise((resolve, reject) => { exec(`Taskkill /F /PID ${processId}`, {}, (err, stdout) => { if (err) { - return reject(`Problem occurred when killing the process w ID: ${processId}`); + return reject(`Problem occurred when killing the process with PID: ${processId}`); } resolve(stdout); }); From 7d9967760de4327380c2cd6e8792b212b90cf2c6 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 27 Sep 2022 17:39:57 -0700 Subject: [PATCH 135/599] fix quick fix css (#162084) --- .../terminal/browser/media/terminal.css | 4 ++++ .../browser/xterm/decorationStyles.ts | 3 ++- .../terminal/browser/xterm/quickFixAddon.ts | 20 +++++++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index da532922828..237a81753bf 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -248,6 +248,10 @@ border-style: solid; } +.xterm-screen .xterm-decoration-container .xterm-decoration.quick-fix { + z-index: 7; +} + .monaco-workbench .part.sidebar > .title > .title-actions .switch-terminal { display: flex; align-items: center; diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts index 5f3a59ec230..33d85f3ccc1 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts @@ -20,7 +20,8 @@ export const enum DecorationSelector { Codicon = 'codicon', XtermDecoration = 'xterm-decoration', OverviewRuler = '.xterm-decoration-overview-ruler', - QuickFix = 'codicon-light-bulb' + QuickFix = 'quick-fix', + LightBulb = 'codicon-light-bulb' } export function updateLayout(configurationService: IConfigurationService, element?: HTMLElement): void { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index 2fe8a69d30a..d988516c0ac 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -15,6 +15,10 @@ import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Terminal, IDecoration } from 'xterm'; import { IAction } from 'vs/base/common/actions'; +import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; +import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { Color } from 'vs/base/common/color'; export interface ITerminalQuickFix { showMenu(): void; @@ -115,8 +119,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, decoration?.onRender((e: HTMLElement) => { if (!this._decorationMarkerIds.has(decoration.marker.id)) { this._currentQuickFixElement = e; - e.classList.add(DecorationSelector.QuickFix, DecorationSelector.Codicon, DecorationSelector.CommandDecoration, DecorationSelector.XtermDecoration); - e.style.color = '#ffcc00'; + e.classList.add(DecorationSelector.QuickFix, DecorationSelector.LightBulb, DecorationSelector.Codicon, DecorationSelector.CommandDecoration, DecorationSelector.XtermDecoration); updateLayout(this._configurationService, e); if (actions) { this._decorationMarkerIds.add(decoration.marker.id); @@ -168,3 +171,16 @@ export function getQuickFixes(command: ITerminalCommand, actionOptions: Map { + foregroundColor = theme.getColor('editorLightBulb.foreground'); + backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(PANEL_BACKGROUND); + if (foregroundColor) { + collector.addRule(`.${DecorationSelector.CommandDecoration}.${DecorationSelector.QuickFix} { color: ${foregroundColor.toString()} !important; } `); + } + if (backgroundColor) { + collector.addRule(`.${DecorationSelector.CommandDecoration}.${DecorationSelector.QuickFix} { background-color: ${backgroundColor.toString()}; } `); + } +}); From fd06e2ffd9a1a81ac83e4c5f82c5d7682c086d28 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 27 Sep 2022 17:54:22 -0700 Subject: [PATCH 136/599] Various terminal quick fix fixes (#162083) --- .../commandDetectionCapability.ts | 7 ++--- .../contrib/terminal/browser/terminal.ts | 2 -- .../browser/terminalQuickFixBuiltinActions.ts | 26 +++++++++---------- .../test/browser/quickFixAddon.test.ts | 16 ++++++------ 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 757881846c1..0beddabbf59 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -660,13 +660,11 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en if (outputMatcher?.length && (endLine - startLine) < outputMatcher.length) { return undefined; } - let output = ''; let line: string | undefined; if (outputMatcher?.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { line = getXtermLineContent(buffer, i, i, cols); - output = line + output; - const match = output.match(outputMatcher.lineMatcher); + const match = line.match(outputMatcher.lineMatcher); if (match) { return match; } @@ -674,9 +672,8 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en } else { for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) { line = getXtermLineContent(buffer, i, i, cols); - output += line; if (outputMatcher) { - const match = output.match(outputMatcher.lineMatcher); + const match = line.match(outputMatcher.lineMatcher); if (match) { return match; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 1b47d3e9cd8..9bb8e35938c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -920,14 +920,12 @@ export interface ITerminalInstance { } export interface ITerminalQuickFixOptions { - quickFixLabel: string | DynamicQuickFixLabel; commandLineMatcher: string | RegExp; outputMatcher?: ITerminalOutputMatcher; getQuickFixes: QuickFixCallback; exitStatus?: boolean; } export type QuickFixMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null }; -export type DynamicQuickFixLabel = (matchResult: QuickFixMatchResult) => string; export type QuickFixCallback = (matchResult: QuickFixMatchResult, command: ITerminalCommand) => ITerminalQuickFixAction[] | undefined; export interface ITerminalQuickFixAction extends IAction { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index db6b8e23e78..61d15833cfb 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -15,12 +15,13 @@ export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; -export const GitCreatePrOutputRegex = /Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*remote:\s*(https:.+pull.+)/; +// The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*", +// it's safe to assume it's a github pull request if the URL includes `/pull/` +export const GitCreatePrOutputRegex = /remote:\s*(https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/; export function gitSimilarCommand(): ITerminalQuickFixOptions { return { commandLineMatcher: GitCommandLineRegex, - quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Run git ${matchResult.outputMatch[1]}` : ``, outputMatcher: { lineMatcher: GitSimilarOutputRegex, anchor: 'bottom', @@ -34,10 +35,11 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { if (!fixedCommand) { return; } - const label = localize("terminal.gitSimilarCommand", "Run git {0}", fixedCommand); + const commandToRunInTerminal = `git ${fixedCommand}`; + const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); actions.push({ class: undefined, tooltip: label, id: 'terminal.gitSimilarCommand', label, enabled: true, - commandToRunInTerminal: `git ${fixedCommand}`, + commandToRunInTerminal, addNewLine: true, run: () => { } }); @@ -47,7 +49,6 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { } export function freePort(terminalInstance?: Partial): ITerminalQuickFixOptions { return { - quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Free port ${matchResult.outputMatch[1]}` : '', commandLineMatcher: AnyCommandLineRegex, outputMatcher: { lineMatcher: FreePortOutputRegex, @@ -77,7 +78,6 @@ export function freePort(terminalInstance?: Partial): ITermin } export function gitPushSetUpstream(): ITerminalQuickFixOptions { return { - quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Git push ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, outputMatcher: { lineMatcher: GitPushOutputRegex, @@ -92,11 +92,11 @@ export function gitPushSetUpstream(): ITerminalQuickFixOptions { return; } const actions: ITerminalQuickFixAction[] = []; - const label = localize("terminal.gitPush", "Git push {0}", branch); - command.command = `git push --set-upstream origin ${branch}`; + const commandToRunInTerminal = `git push --set-upstream origin ${branch}`; + const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); actions.push({ class: undefined, tooltip: label, id: 'terminal.gitPush', label, enabled: true, - commandToRunInTerminal: command.command, + commandToRunInTerminal, addNewLine: true, run: () => { } }); @@ -107,7 +107,6 @@ export function gitPushSetUpstream(): ITerminalQuickFixOptions { export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOptions { return { - quickFixLabel: (matchResult: QuickFixMatchResult) => matchResult.outputMatch ? `Create PR for ${matchResult.outputMatch[1]}` : '', commandLineMatcher: GitPushCommandLineRegex, outputMatcher: { lineMatcher: GitCreatePrOutputRegex, @@ -120,13 +119,12 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOpt if (!command) { return; } - const branch = matchResult?.outputMatch?.[1]; - const link = matchResult?.outputMatch?.[2]; - if (!branch || !link) { + const link = matchResult?.outputMatch?.[1]; + if (!link) { return; } const actions: IAction[] = []; - const label = localize("terminal.gitCreatePr", "Create PR"); + const label = localize("terminal.openLink", "Open link: {0}", link); actions.push({ class: undefined, tooltip: label, id: 'terminal.gitCreatePr', label, enabled: true, run: () => openerService.open(link) diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 6ea4fb09962..6de36f45a01 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -56,9 +56,9 @@ suite('QuickFixAddon', () => { const actions = [ { id: 'terminal.gitSimilarCommand', - label: 'Run git status', + label: 'Run: git status', run: true, - tooltip: 'Run git status', + tooltip: 'Run: git status', enabled: true } ]; @@ -136,9 +136,9 @@ suite('QuickFixAddon', () => { const actions = [ { id: 'terminal.gitPush', - label: 'Git push test22', + label: 'Run: git push --set-upstream origin test22', run: true, - tooltip: 'Git push test22', + tooltip: 'Run: git push --set-upstream origin test22', enabled: true } ]; @@ -179,9 +179,9 @@ suite('QuickFixAddon', () => { const actions = [ { id: 'terminal.gitCreatePr', - label: 'Create PR', + label: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22', run: true, - tooltip: 'Create PR', + tooltip: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22', enabled: true } ]; @@ -219,9 +219,9 @@ suite('QuickFixAddon', () => { const actions = [ { id: 'terminal.gitPush', - label: 'Git push test22', + label: 'Run: git push --set-upstream origin test22', run: true, - tooltip: 'Git push test22', + tooltip: 'Run: git push --set-upstream origin test22', enabled: true } ]; From 3b395e29a1c968fcfa027b7446328dc3155b3efc Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 27 Sep 2022 19:41:23 -0700 Subject: [PATCH 137/599] Fix https://github.com/microsoft/vscode/issues/161935 --- .../contrib/editSessions/browser/editSessionsViews.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index 7a70b872e41..c794bad44e1 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts @@ -208,7 +208,8 @@ class EditSessionDataViewDataProvider implements ITreeViewDataProvider { const sessionData = await this.editSessionsStorageService.read(session.ref); const label = sessionData?.editSession.folders.map((folder) => folder.name).join(', ') ?? session.ref; const machineId = sessionData?.editSession.machine; - const description = machineId === undefined ? fromNow(session.created, true) : `${fromNow(session.created, true)}\u00a0\u00a0\u2022\u00a0\u00a0${await this.editSessionsStorageService.getMachineById(machineId)}`; + const machineName = machineId ? await this.editSessionsStorageService.getMachineById(machineId) : undefined; + const description = machineName === undefined ? fromNow(session.created, true) : `${fromNow(session.created, true)}\u00a0\u00a0\u2022\u00a0\u00a0${machineName}`; editSessions.push({ handle: resource.toString(), From e1730b2f26afbf1e1e59f10c580480f97066b915 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 27 Sep 2022 20:01:20 -0700 Subject: [PATCH 138/599] Fix https://github.com/microsoft/vscode/issues/162034 --- .../contrib/editSessions/browser/editSessions.contribution.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 146864b176f..8f48022e6fb 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -398,6 +398,9 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo try { const { changes, conflictingChanges } = await this.generateChanges(editSession, ref); + if (changes.length === 0) { + return; + } // TODO@joyceerhl Provide the option to diff files which would be overwritten by edit session contents if (conflictingChanges.length > 0) { From 689cfc73d3aea10d668bb77c9bdd8403d40609d1 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 27 Sep 2022 20:33:09 -0700 Subject: [PATCH 139/599] Don't prompt for auth if the auth session that the user previously used for edit sessions is no longer available --- .../browser/editSessions.contribution.ts | 5 ++++ .../browser/editSessionsStorageService.ts | 23 +++++++++++++++---- .../editSessions/common/editSessions.ts | 3 ++- .../test/browser/editSessions.test.ts | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 8f48022e6fb..212fd940a22 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -131,6 +131,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this._register(this.fileService.registerProvider(EditSessionsFileSystemProvider.SCHEMA, new EditSessionsFileSystemProvider(this.editSessionsStorageService))); this.lifecycleService.onWillShutdown((e) => e.join(this.autoStoreEditSession(), { id: 'autoStoreEditSession', label: localize('autoStoreEditSession', 'Storing current edit session...') })); this._register(this.editSessionsStorageService.onDidSignIn(() => this.updateAccountsMenuBadge())); + this._register(this.editSessionsStorageService.onDidSignOut(() => this.updateAccountsMenuBadge())); } private autoResumeEditSession() { @@ -378,6 +379,10 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.logService.info(ref !== undefined ? `Resuming edit session with ref ${ref}...` : 'Resuming edit session...'); + if (silent && !(await this.editSessionsStorageService.initialize(false, true))) { + return; + } + const data = await this.editSessionsStorageService.read(ref); if (!data) { if (ref === undefined && !silent) { diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts index 7637ef73355..fcdcc89dcce 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts @@ -56,6 +56,11 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes return this._didSignIn.event; } + private _didSignOut = new Emitter(); + get onDidSignOut() { + return this._didSignOut.event; + } + constructor( @IFileService private readonly fileService: IFileService, @IStorageService private readonly storageService: IStorageService, @@ -162,11 +167,11 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes return []; } - public async initialize(fromContinueOn: boolean) { + public async initialize(fromContinueOn: boolean, silent: boolean = false) { if (this.initialized) { return true; } - this.initialized = await this.doInitialize(fromContinueOn); + this.initialized = await this.doInitialize(fromContinueOn, silent); this.signedInContext.set(this.initialized); if (this.initialized) { this._didSignIn.fire(); @@ -181,7 +186,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes * meaning that authentication is configured and it * can be used to communicate with the remote storage service */ - private async doInitialize(fromContinueOn: boolean): Promise { + private async doInitialize(fromContinueOn: boolean, silent: boolean): Promise { // Wait for authentication extensions to be registered await this.extensionService.whenInstalledExtensionsRegistered(); @@ -206,7 +211,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes return true; } - const authenticationSession = await this.getAuthenticationSession(fromContinueOn); + const authenticationSession = await this.getAuthenticationSession(fromContinueOn, silent); if (authenticationSession !== undefined) { this.#authenticationInfo = authenticationSession; this.storeClient.setAuthToken(authenticationSession.token, authenticationSession.providerId); @@ -239,7 +244,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes return currentMachineId; } - private async getAuthenticationSession(fromContinueOn: boolean) { + private async getAuthenticationSession(fromContinueOn: boolean, silent: boolean) { // If the user signed in previously and the session is still available, reuse that without prompting the user again if (this.existingSessionId) { this.logService.info(`Searching for existing authentication session with ID ${this.existingSessionId}`); @@ -247,6 +252,8 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes if (existingSession) { this.logService.info(`Found existing authentication session with ID ${existingSession.session.id}`); return { sessionId: existingSession.session.id, token: existingSession.session.idToken ?? existingSession.session.accessToken, providerId: existingSession.session.providerId }; + } else { + this._didSignOut.fire(); } } @@ -261,6 +268,12 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes } } + // If we aren't supposed to prompt the user because + // we're in a silent flow, just return here + if (silent) { + return; + } + // Ask the user to pick a preferred account const authenticationSession = await this.getAccountPreference(fromContinueOn); if (authenticationSession !== undefined) { diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index f9b84cf5bc0..99e5c8a16cc 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -25,8 +25,9 @@ export interface IEditSessionsStorageService { readonly isSignedIn: boolean; readonly onDidSignIn: Event; + readonly onDidSignOut: Event; - initialize(fromContinueOn: boolean): Promise; + initialize(fromContinueOn: boolean, silent?: boolean): Promise; read(ref: string | undefined): Promise<{ ref: string; editSession: EditSession } | undefined>; write(editSession: EditSession): Promise; delete(ref: string | null): Promise; diff --git a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts index a766a535095..3bcd8b1d946 100644 --- a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -68,6 +68,7 @@ suite('Edit session sync', () => { instantiationService.stub(INotificationService, new TestNotificationService()); instantiationService.stub(IEditSessionsStorageService, new class extends mock() { override onDidSignIn = Event.None; + override onDidSignOut = Event.None; }); instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(ISCMService, SCMService); From c2a2ad4f63d05b6ef6af19601d235708be6f379e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 27 Sep 2022 21:01:14 -0700 Subject: [PATCH 140/599] Rename image-preview extension to media-preview (#162093) Fixes #162092 Also removes `aac` from the list of supported audio formats --- build/gulpfile.extensions.js | 2 +- build/npm/dirs.js | 2 +- extensions/image-preview/README.md | 16 ---------- .../.vscodeignore | 0 extensions/media-preview/README.md | 29 ++++++++++++++++++ .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../{image-preview => media-preview}/icon.png | Bin .../media/audioPreview.css | 0 .../media/audioPreview.js | 0 .../media/imagePreview.css | 0 .../media/imagePreview.js | 0 .../media/loading-dark.svg | 0 .../media/loading-hc.svg | 0 .../media/loading.svg | 0 .../media/videoPreview.css | 0 .../media/videoPreview.js | 0 .../package.json | 10 +++--- .../package.nls.json | 4 +-- .../src/audioPreview.ts | 0 .../src/binarySizeStatusBarEntry.ts | 0 .../src/extension.ts | 0 .../src/imagePreview/index.ts | 0 .../src/imagePreview/sizeStatusBarEntry.ts | 0 .../src/imagePreview/zoomStatusBarEntry.ts | 0 .../src/mediaPreview.ts | 0 .../src/ownedStatusBarEntry.ts | 0 .../src/util/dispose.ts | 0 .../src/util/dom.ts | 0 .../src/videoPreview.ts | 0 .../tsconfig.json | 0 .../yarn.lock | 0 .../src/singlefolder-tests/env.test.ts | 2 +- 33 files changed, 39 insertions(+), 26 deletions(-) delete mode 100644 extensions/image-preview/README.md rename extensions/{image-preview => media-preview}/.vscodeignore (100%) create mode 100644 extensions/media-preview/README.md rename extensions/{image-preview => media-preview}/extension-browser.webpack.config.js (100%) rename extensions/{image-preview => media-preview}/extension.webpack.config.js (100%) rename extensions/{image-preview => media-preview}/icon.png (100%) rename extensions/{image-preview => media-preview}/media/audioPreview.css (100%) rename extensions/{image-preview => media-preview}/media/audioPreview.js (100%) rename extensions/{image-preview => media-preview}/media/imagePreview.css (100%) rename extensions/{image-preview => media-preview}/media/imagePreview.js (100%) rename extensions/{image-preview => media-preview}/media/loading-dark.svg (100%) rename extensions/{image-preview => media-preview}/media/loading-hc.svg (100%) rename extensions/{image-preview => media-preview}/media/loading.svg (100%) rename extensions/{image-preview => media-preview}/media/videoPreview.css (100%) rename extensions/{image-preview => media-preview}/media/videoPreview.js (100%) rename extensions/{image-preview => media-preview}/package.json (91%) rename extensions/{image-preview => media-preview}/package.nls.json (67%) rename extensions/{image-preview => media-preview}/src/audioPreview.ts (100%) rename extensions/{image-preview => media-preview}/src/binarySizeStatusBarEntry.ts (100%) rename extensions/{image-preview => media-preview}/src/extension.ts (100%) rename extensions/{image-preview => media-preview}/src/imagePreview/index.ts (100%) rename extensions/{image-preview => media-preview}/src/imagePreview/sizeStatusBarEntry.ts (100%) rename extensions/{image-preview => media-preview}/src/imagePreview/zoomStatusBarEntry.ts (100%) rename extensions/{image-preview => media-preview}/src/mediaPreview.ts (100%) rename extensions/{image-preview => media-preview}/src/ownedStatusBarEntry.ts (100%) rename extensions/{image-preview => media-preview}/src/util/dispose.ts (100%) rename extensions/{image-preview => media-preview}/src/util/dom.ts (100%) rename extensions/{image-preview => media-preview}/src/videoPreview.ts (100%) rename extensions/{image-preview => media-preview}/tsconfig.json (100%) rename extensions/{image-preview => media-preview}/yarn.lock (100%) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 4023b3860e9..07033b9c960 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -46,7 +46,6 @@ const compilations = [ 'gulp/tsconfig.json', 'html-language-features/client/tsconfig.json', 'html-language-features/server/tsconfig.json', - 'image-preview/tsconfig.json', 'ipynb/tsconfig.json', 'jake/tsconfig.json', 'json-language-features/client/tsconfig.json', @@ -55,6 +54,7 @@ const compilations = [ 'markdown-language-features/server/tsconfig.json', 'markdown-language-features/tsconfig.json', 'markdown-math/tsconfig.json', + 'media-preview/tsconfig.json', 'merge-conflict/tsconfig.json', 'microsoft-authentication/tsconfig.json', 'npm/tsconfig.json', diff --git a/build/npm/dirs.js b/build/npm/dirs.js index 6e5ba3ca9a4..f820f39e222 100644 --- a/build/npm/dirs.js +++ b/build/npm/dirs.js @@ -23,7 +23,6 @@ exports.dirs = [ 'extensions/gulp', 'extensions/html-language-features', 'extensions/html-language-features/server', - 'extensions/image-preview', 'extensions/ipynb', 'extensions/jake', 'extensions/json-language-features', @@ -31,6 +30,7 @@ exports.dirs = [ 'extensions/markdown-language-features/server', 'extensions/markdown-language-features', 'extensions/markdown-math', + 'extensions/media-preview', 'extensions/merge-conflict', 'extensions/microsoft-authentication', 'extensions/notebook-renderers', diff --git a/extensions/image-preview/README.md b/extensions/image-preview/README.md deleted file mode 100644 index d3f0bd6cb6c..00000000000 --- a/extensions/image-preview/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Image Preview - -**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. - -## Features - -This extension provides VS Code's built-in image preview functionality. - -Supported image formats: - -- `*.jpg`, `*.jpe`, `*.jpeg` -- `*.png` -- `*.bmp` -- `*.gif` -- `*.ico` -- `*.webp` diff --git a/extensions/image-preview/.vscodeignore b/extensions/media-preview/.vscodeignore similarity index 100% rename from extensions/image-preview/.vscodeignore rename to extensions/media-preview/.vscodeignore diff --git a/extensions/media-preview/README.md b/extensions/media-preview/README.md new file mode 100644 index 00000000000..30bb44b87a1 --- /dev/null +++ b/extensions/media-preview/README.md @@ -0,0 +1,29 @@ +# Media Preview + +**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. + +## Features + +This extension provides basic preview for images, audio and video files. + +### Supported image file extensions + +- `.jpg`, `.jpe`, `.jpeg` +- `.png` +- `.bmp` +- `.gif` +- `.ico` +- `.webp` +- `.avif` + + +### Supported audio formats + +- `.mp3` +- `.wav` +- `.ogg` + +### Supported video formats + +- `.mp4` (does not support `aac` audio track) +- `.webm` (vp8 only) diff --git a/extensions/image-preview/extension-browser.webpack.config.js b/extensions/media-preview/extension-browser.webpack.config.js similarity index 100% rename from extensions/image-preview/extension-browser.webpack.config.js rename to extensions/media-preview/extension-browser.webpack.config.js diff --git a/extensions/image-preview/extension.webpack.config.js b/extensions/media-preview/extension.webpack.config.js similarity index 100% rename from extensions/image-preview/extension.webpack.config.js rename to extensions/media-preview/extension.webpack.config.js diff --git a/extensions/image-preview/icon.png b/extensions/media-preview/icon.png similarity index 100% rename from extensions/image-preview/icon.png rename to extensions/media-preview/icon.png diff --git a/extensions/image-preview/media/audioPreview.css b/extensions/media-preview/media/audioPreview.css similarity index 100% rename from extensions/image-preview/media/audioPreview.css rename to extensions/media-preview/media/audioPreview.css diff --git a/extensions/image-preview/media/audioPreview.js b/extensions/media-preview/media/audioPreview.js similarity index 100% rename from extensions/image-preview/media/audioPreview.js rename to extensions/media-preview/media/audioPreview.js diff --git a/extensions/image-preview/media/imagePreview.css b/extensions/media-preview/media/imagePreview.css similarity index 100% rename from extensions/image-preview/media/imagePreview.css rename to extensions/media-preview/media/imagePreview.css diff --git a/extensions/image-preview/media/imagePreview.js b/extensions/media-preview/media/imagePreview.js similarity index 100% rename from extensions/image-preview/media/imagePreview.js rename to extensions/media-preview/media/imagePreview.js diff --git a/extensions/image-preview/media/loading-dark.svg b/extensions/media-preview/media/loading-dark.svg similarity index 100% rename from extensions/image-preview/media/loading-dark.svg rename to extensions/media-preview/media/loading-dark.svg diff --git a/extensions/image-preview/media/loading-hc.svg b/extensions/media-preview/media/loading-hc.svg similarity index 100% rename from extensions/image-preview/media/loading-hc.svg rename to extensions/media-preview/media/loading-hc.svg diff --git a/extensions/image-preview/media/loading.svg b/extensions/media-preview/media/loading.svg similarity index 100% rename from extensions/image-preview/media/loading.svg rename to extensions/media-preview/media/loading.svg diff --git a/extensions/image-preview/media/videoPreview.css b/extensions/media-preview/media/videoPreview.css similarity index 100% rename from extensions/image-preview/media/videoPreview.css rename to extensions/media-preview/media/videoPreview.css diff --git a/extensions/image-preview/media/videoPreview.js b/extensions/media-preview/media/videoPreview.js similarity index 100% rename from extensions/image-preview/media/videoPreview.js rename to extensions/media-preview/media/videoPreview.js diff --git a/extensions/image-preview/package.json b/extensions/media-preview/package.json similarity index 91% rename from extensions/image-preview/package.json rename to extensions/media-preview/package.json index 20d5b083e3a..b82a4eef836 100644 --- a/extensions/image-preview/package.json +++ b/extensions/media-preview/package.json @@ -1,5 +1,5 @@ { - "name": "image-preview", + "name": "media-preview", "displayName": "%displayName%", "description": "%description%", "extensionKind": [ @@ -50,7 +50,7 @@ "priority": "builtin", "selector": [ { - "filenamePattern": "*.{mp3,wav,ogg,aac}" + "filenamePattern": "*.{mp3,wav,ogg}" } ] }, @@ -93,10 +93,10 @@ } }, "scripts": { - "compile": "gulp compile-extension:image-preview", - "watch": "npm run build-preview && gulp watch-extension:image-preview", + "compile": "gulp compile-extension:media-preview", + "watch": "npm run build-preview && gulp watch-extension:media-preview", "vscode:prepublish": "npm run build-ext", - "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:image-preview ./tsconfig.json", + "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:media-preview ./tsconfig.json", "compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none", "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, diff --git a/extensions/image-preview/package.nls.json b/extensions/media-preview/package.nls.json similarity index 67% rename from extensions/image-preview/package.nls.json rename to extensions/media-preview/package.nls.json index 423aaf0c82b..3e45e4d0d2e 100644 --- a/extensions/image-preview/package.nls.json +++ b/extensions/media-preview/package.nls.json @@ -1,6 +1,6 @@ { - "displayName": "Image Preview", - "description": "Provides VS Code's built-in image preview", + "displayName": "Media Preview", + "description": "Provides VS Code's built-in previews for images, audio, and video", "customEditor.audioPreview.displayName": "Audio Preview", "customEditor.imagePreview.displayName": "Image Preview", "customEditor.videoPreview.displayName": "Video Preview", diff --git a/extensions/image-preview/src/audioPreview.ts b/extensions/media-preview/src/audioPreview.ts similarity index 100% rename from extensions/image-preview/src/audioPreview.ts rename to extensions/media-preview/src/audioPreview.ts diff --git a/extensions/image-preview/src/binarySizeStatusBarEntry.ts b/extensions/media-preview/src/binarySizeStatusBarEntry.ts similarity index 100% rename from extensions/image-preview/src/binarySizeStatusBarEntry.ts rename to extensions/media-preview/src/binarySizeStatusBarEntry.ts diff --git a/extensions/image-preview/src/extension.ts b/extensions/media-preview/src/extension.ts similarity index 100% rename from extensions/image-preview/src/extension.ts rename to extensions/media-preview/src/extension.ts diff --git a/extensions/image-preview/src/imagePreview/index.ts b/extensions/media-preview/src/imagePreview/index.ts similarity index 100% rename from extensions/image-preview/src/imagePreview/index.ts rename to extensions/media-preview/src/imagePreview/index.ts diff --git a/extensions/image-preview/src/imagePreview/sizeStatusBarEntry.ts b/extensions/media-preview/src/imagePreview/sizeStatusBarEntry.ts similarity index 100% rename from extensions/image-preview/src/imagePreview/sizeStatusBarEntry.ts rename to extensions/media-preview/src/imagePreview/sizeStatusBarEntry.ts diff --git a/extensions/image-preview/src/imagePreview/zoomStatusBarEntry.ts b/extensions/media-preview/src/imagePreview/zoomStatusBarEntry.ts similarity index 100% rename from extensions/image-preview/src/imagePreview/zoomStatusBarEntry.ts rename to extensions/media-preview/src/imagePreview/zoomStatusBarEntry.ts diff --git a/extensions/image-preview/src/mediaPreview.ts b/extensions/media-preview/src/mediaPreview.ts similarity index 100% rename from extensions/image-preview/src/mediaPreview.ts rename to extensions/media-preview/src/mediaPreview.ts diff --git a/extensions/image-preview/src/ownedStatusBarEntry.ts b/extensions/media-preview/src/ownedStatusBarEntry.ts similarity index 100% rename from extensions/image-preview/src/ownedStatusBarEntry.ts rename to extensions/media-preview/src/ownedStatusBarEntry.ts diff --git a/extensions/image-preview/src/util/dispose.ts b/extensions/media-preview/src/util/dispose.ts similarity index 100% rename from extensions/image-preview/src/util/dispose.ts rename to extensions/media-preview/src/util/dispose.ts diff --git a/extensions/image-preview/src/util/dom.ts b/extensions/media-preview/src/util/dom.ts similarity index 100% rename from extensions/image-preview/src/util/dom.ts rename to extensions/media-preview/src/util/dom.ts diff --git a/extensions/image-preview/src/videoPreview.ts b/extensions/media-preview/src/videoPreview.ts similarity index 100% rename from extensions/image-preview/src/videoPreview.ts rename to extensions/media-preview/src/videoPreview.ts diff --git a/extensions/image-preview/tsconfig.json b/extensions/media-preview/tsconfig.json similarity index 100% rename from extensions/image-preview/tsconfig.json rename to extensions/media-preview/tsconfig.json diff --git a/extensions/image-preview/yarn.lock b/extensions/media-preview/yarn.lock similarity index 100% rename from extensions/image-preview/yarn.lock rename to extensions/media-preview/yarn.lock diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts index a445753483d..d02e5a44442 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts @@ -32,7 +32,7 @@ suite('vscode API - env', () => { test('env.remoteName', function () { const remoteName = env.remoteName; const knownWorkspaceExtension = extensions.getExtension('vscode.git'); - const knownUiAndWorkspaceExtension = extensions.getExtension('vscode.image-preview'); + const knownUiAndWorkspaceExtension = extensions.getExtension('vscode.media-preview'); if (typeof remoteName === 'undefined') { // not running in remote, so we expect both extensions assert.ok(knownWorkspaceExtension); From 7b7f5a046646993c2b6ee00b76d4eef75a012341 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 27 Sep 2022 21:09:30 -0700 Subject: [PATCH 141/599] Fix output sizing for multiline evaluation result (#162101) Fix output sizing for multiline evaluation resul Fix #151768 --- .../workbench/contrib/debug/browser/replViewer.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/replViewer.ts b/src/vs/workbench/contrib/debug/browser/replViewer.ts index 94b7ecd5b13..9c4adf953f3 100644 --- a/src/vs/workbench/contrib/debug/browser/replViewer.ts +++ b/src/vs/workbench/contrib/debug/browser/replViewer.ts @@ -312,18 +312,21 @@ export class ReplDelegate extends CachedListVirtualDelegate { return super.getHeight(element); } + /** + * With wordWrap enabled, this is an estimate. With wordWrap disabled, this is the real height that the list will use. + */ protected estimateHeight(element: IReplElement, ignoreValueLength = false): number { const lineHeight = this.replOptions.replConfiguration.lineHeight; - const countNumberOfLines = (str: string) => Math.max(1, (str && str.match(/\r\n|\n/g) || []).length); + const countNumberOfLines = (str: string) => str.match(/\n/g)?.length ?? 0; const hasValue = (e: any): e is { value: string } => typeof e.value === 'string'; - // Calculate a rough overestimation for the height - // For every 70 characters increase the number of lines needed beyond the first if (hasValue(element) && !isNestedVariable(element)) { const value = element.value; - const valueRows = countNumberOfLines(value) + (ignoreValueLength ? 0 : Math.floor(value.length / 70)); + const valueRows = countNumberOfLines(value) + + (ignoreValueLength ? 0 : Math.floor(value.length / 70)) // Make an estimate for wrapping + + (element instanceof SimpleReplElement ? 0 : 1); // A SimpleReplElement ends in \n if it's a complete line - return valueRows * lineHeight; + return Math.max(valueRows, 1) * lineHeight; } return lineHeight; From 7ff04babc6b4fc45944b741b680443d53946bb20 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 28 Sep 2022 09:49:59 +0200 Subject: [PATCH 142/599] Revert "Engineering - use specific image version (#160878)" (#162052) This reverts commit 924d7622faad0bc0172704c3ebbdcfc1db37a63c. --- build/azure-pipelines/product-build-pr.yml | 25 +++++----------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index 954585cdf35..8362da25ee5 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -26,10 +26,7 @@ jobs: - ${{ if ne(variables['VSCODE_CIBUILD'], true) }}: - job: Compile displayName: Compile & Hygiene - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 variables: VSCODE_ARCH: x64 @@ -40,10 +37,7 @@ jobs: - job: Linuxx64UnitTest displayName: Linux (Unit Tests) - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 variables: VSCODE_ARCH: x64 @@ -60,10 +54,7 @@ jobs: - job: Linuxx64IntegrationTest displayName: Linux (Integration Tests) - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 variables: VSCODE_ARCH: x64 @@ -80,10 +71,7 @@ jobs: - job: Linuxx64SmokeTest displayName: Linux (Smoke Tests) - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 variables: VSCODE_ARCH: x64 @@ -101,10 +89,7 @@ jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - job: Linuxx64MaintainNodeModulesCache displayName: Linux (Maintain node_modules cache) - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 variables: VSCODE_ARCH: x64 From 044571548e0268d0e4f09300a05887e4495b84a8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 10:34:16 +0200 Subject: [PATCH 143/599] fix #161961 (#162136) * fix #161961 * remove comment --- .../relauncher/browser/relauncher.contribution.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index cdde19ded70..a2c8e69b223 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -27,7 +27,7 @@ interface IConfiguration extends IWindowsConfiguration { editor?: { accessibilitySupport?: 'on' | 'off' | 'auto' }; security?: { workspace?: { trust?: { enabled?: boolean } } }; window: IWindowSettings & { experimental?: { windowControlsOverlay?: { enabled?: boolean }; useSandbox?: boolean } }; - workbench?: { experimental?: { settingsProfiles?: { enabled?: boolean } } }; + workbench?: { experimental?: { settingsProfiles?: { enabled?: boolean } }; enableExperiments?: boolean }; } export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { @@ -42,6 +42,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private accessibilitySupport: 'on' | 'off' | 'auto' | undefined; private workspaceTrustEnabled: boolean | undefined; private settingsProfilesEnabled: boolean | undefined; + private experimentsEnabled: boolean | undefined; constructor( @IHostService private readonly hostService: IHostService, @@ -123,6 +124,12 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo changed = true; } + // Experiments + if (typeof config.workbench?.enableExperiments === 'boolean' && config.workbench.enableExperiments !== this.experimentsEnabled) { + this.experimentsEnabled = config.workbench.enableExperiments; + changed = true; + } + // Notify only when changed and we are the focused window (avoids notification spam across windows) if (notify && changed) { this.doConfirm( From 352782487fcbfb0f390b0362f9b0496e1da72244 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 11:28:21 +0200 Subject: [PATCH 144/599] Fix #162134 (#162140) --- src/vs/platform/userDataSync/common/userDataSyncService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 85acc352626..49b22b246ad 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -420,7 +420,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return isUndefined(result) ? null : result; } - if (this.environmentService.isBuilt && !this.productService.enableSyncingProfiles) { + if (this.environmentService.isBuilt && (!this.productService.enableSyncingProfiles || isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.stableUrl))) { return null; } @@ -592,7 +592,7 @@ class ProfileSynchronizer extends Disposable { if (!this._profile.isDefault) { return; } - if (this.environmentService.isBuilt && !this.productService.enableSyncingProfiles) { + if (this.environmentService.isBuilt && (!this.productService.enableSyncingProfiles || isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.stableUrl))) { this.logService.debug('Skipping profiles sync'); return; } From 8044546365d137fdf7bb038f5b8033f7f0f8edc3 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Wed, 28 Sep 2022 02:32:51 -0700 Subject: [PATCH 145/599] Add `$schema` to `cgmanifest.json` (#159779) Co-authored-by: Martin Aeschlimann --- .vscode/cgmanifest.schema.json | 142 --------------------------------- .vscode/settings.json | 2 +- 2 files changed, 1 insertion(+), 143 deletions(-) delete mode 100644 .vscode/cgmanifest.schema.json diff --git a/.vscode/cgmanifest.schema.json b/.vscode/cgmanifest.schema.json deleted file mode 100644 index 2e719b02396..00000000000 --- a/.vscode/cgmanifest.schema.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "type": "object", - "properties": { - "registrations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "component": { - "oneOf": [ - { - "type": "object", - "required": [ - "type", - "git" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "git" - ] - }, - "git": { - "type": "object", - "required": [ - "name", - "repositoryUrl", - "commitHash" - ], - "properties": { - "name": { - "type": "string" - }, - "repositoryUrl": { - "type": "string" - }, - "commitHash": { - "type": "string" - } - } - } - } - }, - { - "type": "object", - "required": [ - "type", - "npm" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "npm" - ] - }, - "npm": { - "type": "object", - "required": [ - "name", - "version" - ], - "properties": { - "name": { - "type": "string" - }, - "version": { - "type": "string" - } - } - } - } - }, - { - "type": "object", - "required": [ - "type", - "other" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "other" - ] - }, - "other": { - "type": "object", - "required": [ - "name", - "downloadUrl", - "version" - ], - "properties": { - "name": { - "type": "string" - }, - "downloadUrl": { - "type": "string" - }, - "version": { - "type": "string" - } - } - } - } - } - ] - }, - "repositoryUrl": { - "type": "string", - "description": "The git url of the component" - }, - "version": { - "type": "string", - "description": "The version of the component" - }, - "license": { - "type": "string", - "description": "The name of the license" - }, - "developmentDependency": { - "type": "boolean", - "description": "This component is inlined in the vscode repo and **is not shipped**." - }, - "isOnlyProductionDependency": { - "type": "boolean", - "description": "This component is shipped and **is not inlined in the vscode repo**." - }, - "licenseDetail": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The license text" - } - } - } - } - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json index 3ff60a9bc67..3907bc758b4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,7 +53,7 @@ "fileMatch": [ "cgmanifest.json" ], - "url": "./.vscode/cgmanifest.schema.json" + "url": "https://json.schemastore.org/component-detection-manifest.json", }, { "fileMatch": [ From 7559012a34e79c263ffd627b53806e74e281f1c7 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:58:10 +0200 Subject: [PATCH 146/599] Git protocol handler improvements (#162144) --- extensions/git/src/protocolHandler.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/git/src/protocolHandler.ts b/extensions/git/src/protocolHandler.ts index 3dccfa48665..9ed1f3639ec 100644 --- a/extensions/git/src/protocolHandler.ts +++ b/extensions/git/src/protocolHandler.ts @@ -12,6 +12,7 @@ import * as querystring from 'querystring'; import { OutputChannelLogger } from './log'; const schemes = new Set(['file', 'git', 'http', 'https', 'ssh']); +const refRegEx = /^$|[~\^:\\\*\s\[\]]|^-|^\.|\/\.|\.\.|\.lock\/|\.lock$|\/$|\.$/; export class GitProtocolHandler implements UriHandler { @@ -44,7 +45,7 @@ export class GitProtocolHandler implements UriHandler { } if (ref !== undefined && typeof ref !== 'string') { - this.outputChannelLogger.logWarning('Failed to open URI:' + uri.toString()); + this.outputChannelLogger.logWarning('Failed to open URI due to multiple references:' + uri.toString()); return; } @@ -62,6 +63,11 @@ export class GitProtocolHandler implements UriHandler { if (!schemes.has(cloneUri.scheme.toLowerCase())) { throw new Error('Unsupported scheme.'); } + + // Validate the reference + if (typeof ref === 'string' && refRegEx.test(ref)) { + throw new Error('Invalid reference.'); + } } catch (ex) { this.outputChannelLogger.logWarning('Invalid URI:' + uri.toString()); From f8a296871a1f117d55aa76de1c7ab37489e8610b Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 28 Sep 2022 12:02:01 +0200 Subject: [PATCH 147/599] Changing the z-index of the find options widget so it appears above the sticky scroll widget --- src/vs/editor/contrib/find/browser/findOptionsWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/find/browser/findOptionsWidget.ts b/src/vs/editor/contrib/find/browser/findOptionsWidget.ts index ca04b53497d..7169c362279 100644 --- a/src/vs/editor/contrib/find/browser/findOptionsWidget.ts +++ b/src/vs/editor/contrib/find/browser/findOptionsWidget.ts @@ -43,6 +43,7 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this._domNode.className = 'findOptionsWidget'; this._domNode.style.display = 'none'; this._domNode.style.top = '10px'; + this._domNode.style.zIndex = '12'; this._domNode.setAttribute('role', 'presentation'); this._domNode.setAttribute('aria-hidden', 'true'); From 0e2340359e37b21efb8f8586e2c43d8ca8c03326 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 28 Sep 2022 12:16:15 +0200 Subject: [PATCH 148/599] Fixes #162111 --- .../workbench/contrib/mergeEditor/browser/commands/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 98fc203bfe6..33cb8fd014f 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -294,7 +294,7 @@ export class ShowHideAtTopBase extends Action2 { order: 10, }, ], - precondition: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorShowBase), + precondition: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorShowBase, ctxMergeEditorLayout.isEqualTo('mixed')), }); } From b3434bf251f78f1fb0b7f50a8ba50e4f9e6bf55a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 12:28:32 +0200 Subject: [PATCH 149/599] Fix #161868 (#162148) --- .../theme-abyss/themes/abyss-color-theme.json | 1 + .../theme-defaults/themes/light_vs.json | 1 + .../themes/kimbie-dark-color-theme.json | 1 + .../tomorrow-night-blue-color-theme.json | 1 + .../parts/activitybar/activitybarActions.ts | 19 +++++++++++++++---- .../activitybar/media/activityaction.css | 8 ++++---- src/vs/workbench/common/theme.ts | 7 +++++++ 7 files changed, 30 insertions(+), 8 deletions(-) diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 3157d39b234..7ce14d2de22 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -409,6 +409,7 @@ // "activityBar.foreground": "", // "activityBarBadge.background": "", // "activityBarBadge.foreground": "", + "activityBarItem.settingsProfilesBackground": "#082877", // Workbench: Panel // "panel.background": "", diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index 7a80ebf00e0..0a6eaf61703 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -2,6 +2,7 @@ "$schema": "vscode://schemas/color-theme", "name": "Light (Visual Studio)", "colors": { + "activityBarItem.settingsProfilesBackground": "#4d4d4d", "editor.background": "#FFFFFF", "editor.foreground": "#000000", "editor.inactiveSelectionBackground": "#E5EBF1", diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index 76cdb8a9753..8208d90f102 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -32,6 +32,7 @@ "ports.iconRunningProcessForeground": "#369432", "activityBar.background": "#221a0f", "activityBar.foreground": "#d3af86", + "activityBarItem.settingsProfilesBackground": "#47351d", "sideBar.background": "#362712", "menu.background": "#362712", "menu.foreground": "#CCCCCC", diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json index eef990db889..45f1a1d55b0 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json @@ -36,6 +36,7 @@ "statusBar.noFolderBackground": "#001126", "statusBar.debuggingBackground": "#001126", "activityBar.background": "#001733", + "activityBarItem.settingsProfilesBackground": "#003271", "progressBar.background": "#bbdaffcc", "badge.background": "#bbdaffcc", "badge.foreground": "#001733", diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 6eb949476b5..25e76eb12dc 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -19,7 +19,7 @@ import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platf import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { IActivity } from 'vs/workbench/common/activity'; -import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_SETTINGS_PROFILE_BACKGROUND, ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; @@ -504,13 +504,24 @@ registerThemingParticipant((theme, collector) => { `); } - const activityBarSettingsProfileHoveFgColor = theme.getColor(ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND); - if (activityBarSettingsProfileHoveFgColor) { + const activityBarSettingsProfileBgColor = theme.getColor(ACTIVITY_BAR_SETTINGS_PROFILE_BACKGROUND); + if (activityBarSettingsProfileBgColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item { + background-color: ${activityBarSettingsProfileBgColor} !important; + } + `); + } + + const activityBarSettingsProfileHoverFgColor = theme.getColor(ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND); + if (activityBarSettingsProfileHoverFgColor) { collector.addRule(` .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.profile-activity-item, .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.profile-activity-item, .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.profile-activity-item { - color: ${activityBarSettingsProfileHoveFgColor} !important; + color: ${activityBarSettingsProfileHoverFgColor} !important; } `); } diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index e4ece0d2fdb..84d5729892d 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -178,14 +178,14 @@ .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label.profile-activity-item { height: 20px; - width: 28px; - margin: 14px 10px; + width: 32px; + margin: 14px 8px; padding: 0px; justify-content: center; align-items: center; - font-size: 12px; + font-size: 14px; line-height: 16px; - border: 2px solid; + border-radius: 8px; } /* Right aligned */ diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index b89e7d795d6..8c49d1bf96b 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -639,6 +639,13 @@ export const ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND = registerColor('act hcLight: ACTIVITY_BAR_FOREGROUND }, localize('activityBarItem.settingsProfilesHoverForeground', "Foreground color for the settings profile entry on the activity bar when hovering.")); +export const ACTIVITY_BAR_SETTINGS_PROFILE_BACKGROUND = registerColor('activityBarItem.settingsProfilesBackground', { + dark: lighten(ACTIVITY_BAR_BACKGROUND, 0.5), + light: darken(ACTIVITY_BAR_BACKGROUND, 0.12), + hcDark: null, + hcLight: null +}, localize('statusBarItemSettingsProfileBackground', "Background color for the settings profile entry on the activity bar.")); + // < --- Remote --- > export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.remoteBackground', { From bc07a5d30c3c4bcda4199563bdac0a376909d937 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 13:05:23 +0200 Subject: [PATCH 150/599] Fix #161862 (#162156) --- .../browser/parts/activitybar/activitybarActions.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 25e76eb12dc..1f16d17aea9 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -363,6 +363,11 @@ export class ProfilesActivityActionViewItem extends MenuActivityActionViewItem { super(ManageProfilesSubMenu, action, contextMenuActionsProvider, (action.activity).icon, colors, hoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); } + override render(container: HTMLElement): void { + super.render(container); + this.container.classList.add('profile-activity-item'); + } + protected override async resolveContextMenuActions(disposables: DisposableStore): Promise { const actions = await super.resolveContextMenuActions(disposables); @@ -573,6 +578,10 @@ registerThemingParticipant((theme, collector) => { z-index: 1; } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.profile-activity-item:before { + top: -6px; + } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, From d3f83751e768cabad6fca68e5dd8959db7f90214 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 13:21:34 +0200 Subject: [PATCH 151/599] fix #161791 (#162158) --- .../extensionManagement/common/webExtensionManagementService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index a1c21c2593e..8cc76238682 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -65,6 +65,7 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe } private filterEvent({ profileLocation, applicationScoped }: { profileLocation?: URI; applicationScoped?: boolean }): boolean { + profileLocation = profileLocation ?? this.userDataProfilesService.defaultProfile.extensionsResource; return applicationScoped || this.uriIdentityService.extUri.isEqual(this.userDataProfileService.currentProfile.extensionsResource, profileLocation); } From b0f88c162c745ceeea84bc970e6de1ee7fa1f381 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 28 Sep 2022 13:45:21 +0200 Subject: [PATCH 152/599] Fixes #162005 (#162161) --- .../workbench/contrib/mergeEditor/browser/view/mergeEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index eff805c058f..024c78a0f5b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -444,7 +444,7 @@ export class MergeEditor extends AbstractTextEditor { if (shouldAlignBase && baseViewZoneAccessor) { baseViewZoneIds.push(baseViewZoneAccessor.addZone({ - afterLineNumber, + afterLineNumber: m.left.baseRange.startLineNumber - 1, heightInPx: 16, domNode: $('div.conflict-actions-placeholder'), })); From a1e8a52697de4c109391bdd443066da4e9b81f3a Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 28 Sep 2022 14:10:45 +0200 Subject: [PATCH 153/599] Fixes conflict block rendering bug. (#162162) --- .../blockDecorations/blockDecorations.ts | 18 ++++++++++++++---- src/vs/editor/common/model.ts | 5 +++++ src/vs/editor/common/model/textModel.ts | 2 ++ src/vs/monaco.d.ts | 5 +++++ .../view/editors/inputCodeEditorView.ts | 1 + 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts b/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts index 48f52d6d231..87057ba9ce6 100644 --- a/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts +++ b/src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts @@ -82,10 +82,20 @@ export class BlockDecorations extends ViewPart { block = this.blocks[count] = createFastDomNode(document.createElement('div')); this.domNode.appendChild(block); } - const top = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, true); - const bottom = decoration.range.isEmpty() - ? ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, false) - : ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true); + + let top: number; + let bottom: number; + + if (decoration.options.blockIsAfterEnd) { + // range must be empty + top = ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, false); + bottom = ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true); + } else { + top = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, true); + bottom = decoration.range.isEmpty() + ? ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, false) + : ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true); + } block.setClassName('blockDecorations-block ' + decoration.options.blockClassName); block.setLeft(ctx.scrollLeft); diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index 5cefe83dfc8..6c7badf0b8a 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -92,6 +92,11 @@ export interface IModelDecorationOptions { */ className?: string | null; blockClassName?: string | null; + /** + * Indicates if this block should be rendered after the last line. + * In this case, the range must be empty and set to the last line. + */ + blockIsAfterEnd?: boolean | null; /** * Message to be rendered when hovering over the glyph margin decoration. */ diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 102dc04c973..27ee2e71319 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -2231,6 +2231,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { readonly description: string; readonly blockClassName: string | null; + readonly blockIsAfterEnd: boolean | null; readonly stickiness: model.TrackedRangeStickiness; readonly zIndex: number; readonly className: string | null; @@ -2258,6 +2259,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { private constructor(options: model.IModelDecorationOptions) { this.description = options.description; this.blockClassName = options.blockClassName ? cleanClassName(options.blockClassName) : null; + this.blockIsAfterEnd = options.blockIsAfterEnd ?? null; this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges; this.zIndex = options.zIndex || 0; this.className = options.className ? cleanClassName(options.className) : null; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5c9c1a1a25c..5f5e30d1c3f 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1488,6 +1488,11 @@ declare namespace monaco.editor { */ className?: string | null; blockClassName?: string | null; + /** + * Indicates if this block should be rendered after the last line. + * In this case, the range must be empty and set to the last line. + */ + blockIsAfterEnd?: boolean | null; /** * Message to be rendered when hovering over the glyph margin decoration. */ diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index f8ff9b1055b..1ecc01b7864 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -158,6 +158,7 @@ export class InputCodeEditorView extends CodeEditorView { options: { showIfCollapsed: true, blockClassName: blockClassNames.join(' '), + blockIsAfterEnd: range.startLineNumber > this.editor.getModel()!.getLineCount(), description: 'Merge Editor', minimap: { position: MinimapPosition.Gutter, From 8efbe805a7d68de76e15807e472654dadb32d218 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 28 Sep 2022 14:16:50 +0200 Subject: [PATCH 154/599] Making the stash visible by changing the CSS parameters --- .../editor/contrib/stickyScroll/browser/stickyScroll.css | 2 +- .../contrib/stickyScroll/browser/stickyScrollWidget.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css index 78ce346f864..f3dc213f679 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.css @@ -29,7 +29,7 @@ .monaco-editor .sticky-widget { width : 100%; - box-shadow : var(--vscode-scrollbar-shadow) 0 2px 6px -2px; + box-shadow : var(--vscode-scrollbar-shadow) 0 3px 2px -2px; z-index : 2; background-color : var(--vscode-editorStickyScroll-background); } diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts index f35d88029b6..bc15f45478d 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts @@ -275,7 +275,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { const mouseOverEvent = new StandardMouseEvent(e); const text = mouseOverEvent.target.innerText; this._hoverOnLine = line; - // TODO: workaround to find the column index, perhaps need more solid solution + // TODO: workaround to find the column index, perhaps need a more solid solution this._hoverOnColumn = this._editor.getModel().getLineContent(line).indexOf(text) + 1 || -1; } })); @@ -296,8 +296,9 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { const minimapSide = this._editor.getOption(EditorOption.minimap).side; if (minimapSide === 'left') { this._rootDomNode.style.marginLeft = this._editor.getLayoutInfo().minimap.minimapCanvasOuterWidth + 'px'; - } else if (minimapSide === 'right') { - this._rootDomNode.style.marginLeft = '0px'; + } + else if (minimapSide === 'right') { + this._rootDomNode.style.marginLeft = '1px'; } this._rootDomNode.style.zIndex = '11'; } From 55a5e84230cf8f9072ed201156cfc0f24574e28f Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 28 Sep 2022 14:23:56 +0200 Subject: [PATCH 155/599] Fixes #161967 (#162165) --- .../workbench/contrib/mergeEditor/browser/view/mergeEditor.ts | 4 ++++ .../workbench/contrib/mergeEditor/browser/view/viewModel.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 024c78a0f5b..32216d538b5 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -278,6 +278,10 @@ export class MergeEditor extends AbstractTextEditor { return; } this.input1View.editor.revealLineInCenter(firstConflict.input1Range.startLineNumber); + transaction(tx => { + /** @description setActiveModifiedBaseRange */ + viewModel.setActiveModifiedBaseRange(firstConflict, tx); + }); })); } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts index d16dc21b25d..b4910bbd219 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts @@ -124,6 +124,10 @@ export class MergeEditorViewModel extends Disposable { } ); + public setActiveModifiedBaseRange(range: ModifiedBaseRange | undefined, tx: ITransaction): void { + this.manuallySetActiveModifiedBaseRange.set({ range, counter: this.counter++ }, tx); + } + public setState( baseRange: ModifiedBaseRange, state: ModifiedBaseRangeState, From df0a8572e5e97ba71160c736addf171c671bb9e9 Mon Sep 17 00:00:00 2001 From: Benjamin Simmonds <44439583+benibenj@users.noreply.github.com> Date: Wed, 28 Sep 2022 15:03:05 +0200 Subject: [PATCH 156/599] Install all outdated extensions action (#162170) Install all outdated extensions --- .../browser/extensions.contribution.ts | 28 ++++++++++++------- .../extensions/browser/extensionsViewlet.ts | 4 +-- .../contrib/extensions/common/extensions.ts | 1 + 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 41169964b15..ebac501e17b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -14,7 +14,7 @@ import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsServi import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP } from 'vs/workbench/contrib/extensions/common/extensions'; +import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, OUTDATED_EXTENSIONS_VIEW_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, SetColorThemeAction, SetFileIconThemeAction, SetProductIconThemeAction, ClearLanguageAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; @@ -653,15 +653,23 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi title: { value: localize('updateAll', "Update All Extensions"), original: 'Update All Extensions' }, category: ExtensionsLocalizedLabel, precondition: HasOutdatedExtensionsContext, - menu: [{ - id: MenuId.CommandPalette, - when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)) - }, { - id: MenuId.ViewContainerTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), ContextKeyExpr.or(ContextKeyExpr.has(`config.${AutoUpdateConfigurationKey}`).negate(), ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlyEnabledExtensions'))), - group: '1_updates', - order: 2 - }], + menu: [ + { + id: MenuId.CommandPalette, + when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)) + }, { + id: MenuId.ViewContainerTitle, + when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), ContextKeyExpr.or(ContextKeyExpr.has(`config.${AutoUpdateConfigurationKey}`).negate(), ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlyEnabledExtensions'))), + group: '1_updates', + order: 2 + }, { + id: MenuId.ViewTitle, + when: ContextKeyExpr.equals('view', OUTDATED_EXTENSIONS_VIEW_ID), + group: 'navigation', + order: 1 + } + ], + icon: installWorkspaceRecommendedIcon, run: () => { return Promise.all(this.extensionsWorkbenchService.outdated.map(async extension => { try { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 106da39d421..b986e34b545 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -16,7 +16,7 @@ import { append, $, Dimension, hide, show, DragAndDropObserver } from 'vs/base/b import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, CloseExtensionDetailsOnViewChangeKey, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, AutoCheckUpdatesConfigurationKey } from '../common/extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, CloseExtensionDetailsOnViewChangeKey, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, AutoCheckUpdatesConfigurationKey, OUTDATED_EXTENSIONS_VIEW_ID } from '../common/extensions'; import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -328,7 +328,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio * View used for searching outdated extensions */ viewDescriptors.push({ - id: 'workbench.views.extensions.searchOutdated', + id: OUTDATED_EXTENSIONS_VIEW_ID, name: localize('availableUpdates', "Available Updates"), ctorDescriptor: new SyncDescriptor(OutdatedExtensionsView, [{}]), when: ContextKeyExpr.or(SearchExtensionUpdatesContext, ContextKeyExpr.has('searchOutdatedExtensions')), diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 14312e367c6..e01cdeee918 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -183,6 +183,7 @@ export class ExtensionContainers extends Disposable { } export const WORKSPACE_RECOMMENDATIONS_VIEW_ID = 'workbench.views.extensions.workspaceRecommendations'; +export const OUTDATED_EXTENSIONS_VIEW_ID = 'workbench.views.extensions.searchOutdated'; export const TOGGLE_IGNORE_EXTENSION_ACTION_ID = 'workbench.extensions.action.toggleIgnoreExtension'; export const SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID = 'workbench.extensions.action.installVSIX'; export const INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID = 'workbench.extensions.command.installFromVSIX'; From 2428297798f5a874d0e827a997ee1b391d43ecbb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 15:11:24 +0200 Subject: [PATCH 157/599] fix #161618 (#162171) fixes https://github.com/microsoft/vscode/issues/161618 --- src/vs/base/common/map.ts | 14 ++++++---- src/vs/base/test/common/map.test.ts | 43 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 2a78f7afb18..1c2e42bba59 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -576,12 +576,16 @@ export class TernarySearchTree { if (!node.mid && !node.value) { if (node.left && node.right) { // full node + // replace deleted-node with the min-node of the right branch. + // If there is no true min-node leave things as they are const min = this._min(node.right); - const { key, value, segment } = min; - this._delete(min.key!, false); - node.key = key; - node.value = value; - node.segment = segment; + if (min.key) { + const { key, value, segment } = min; + this._delete(min.key!, false); + node.key = key; + node.value = value; + node.segment = segment; + } } else { // empty or half empty diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index 896d06ec812..0d3f3dfe131 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -862,6 +862,49 @@ suite('Map', () => { } }); + test('TernarySearchTree: Cannot read properties of undefined (reading \'length\'): #161618 (simple)', function () { + const raw = 'config.debug.toolBarLocation,floating,config.editor.renderControlCharacters,true,config.editor.renderWhitespace,selection,config.files.autoSave,off,config.git.enabled,true,config.notebook.globalToolbar,true,config.terminal.integrated.tabs.enabled,true,config.terminal.integrated.tabs.showActions,singleTerminalOrNarrow,config.terminal.integrated.tabs.showActiveTerminal,singleTerminalOrNarrow,config.workbench.activityBar.visible,true,config.workbench.experimental.settingsProfiles.enabled,true,config.workbench.layoutControl.type,both,config.workbench.sideBar.location,left,config.workbench.statusBar.visible,true'; + const array = raw.split(','); + const tuples: [string, string][] = []; + for (let i = 0; i < array.length; i += 2) { + tuples.push([array[i], array[i + 1]]); + } + + const map = TernarySearchTree.forConfigKeys(); + map.fill(tuples); + + assert.strictEqual([...map].join(), raw); + assert.ok(map.has('config.editor.renderWhitespace')); + + const len = [...map].length; + map.delete('config.editor.renderWhitespace'); + assert.ok(map._isBalanced()); + assert.strictEqual([...map].length, len - 1); + }); + + test('TernarySearchTree: Cannot read properties of undefined (reading \'length\'): #161618 (random)', function () { + const raw = 'config.debug.toolBarLocation,floating,config.editor.renderControlCharacters,true,config.editor.renderWhitespace,selection,config.files.autoSave,off,config.git.enabled,true,config.notebook.globalToolbar,true,config.terminal.integrated.tabs.enabled,true,config.terminal.integrated.tabs.showActions,singleTerminalOrNarrow,config.terminal.integrated.tabs.showActiveTerminal,singleTerminalOrNarrow,config.workbench.activityBar.visible,true,config.workbench.experimental.settingsProfiles.enabled,true,config.workbench.layoutControl.type,both,config.workbench.sideBar.location,left,config.workbench.statusBar.visible,true'; + const array = raw.split(','); + const tuples: [string, string][] = []; + for (let i = 0; i < array.length; i += 2) { + tuples.push([array[i], array[i + 1]]); + } + + for (let round = 100; round >= 0; round--) { + shuffle(tuples); + const map = TernarySearchTree.forConfigKeys(); + map.fill(tuples); + + assert.strictEqual([...map].join(), raw); + assert.ok(map.has('config.editor.renderWhitespace')); + + const len = [...map].length; + map.delete('config.editor.renderWhitespace'); + assert.ok(map._isBalanced()); + assert.strictEqual([...map].length, len - 1); + } + }); + test('TernarySearchTree (PathSegments) - lookup', function () { const map = new TernarySearchTree(new PathIterator()); From 582aa29f857825ddff8ea681d5df940adc17c5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 28 Sep 2022 06:20:58 -0700 Subject: [PATCH 158/599] stop shipping build-only dependencies (#162172) --- build/.moduleignore | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/build/.moduleignore b/build/.moduleignore index 438f9b575d1..07e2a0e84e9 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -1,9 +1,13 @@ # cleanup rules for node modules, .gitignore style -# native node modules - nan/** -*/node_modules/nan/** +**/node_modules/nan/** +node-gyp/** +**/node_modules/node-gyp/** +node-gyp-build/** +**/node_modules/node-gyp-build/** +node-addon-api/** +**/node_modules/node-addon-api/** fsevents/binding.gyp fsevents/fsevents.cc From 209328c91aaa0b444f442590146ac743b319b302 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 28 Sep 2022 06:31:28 -0700 Subject: [PATCH 159/599] Scan up 30 lines for free port quick fix Fixes #162175 --- .../contrib/terminal/browser/terminalQuickFixBuiltinActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 61d15833cfb..889776fb25a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -54,7 +54,7 @@ export function freePort(terminalInstance?: Partial): ITermin lineMatcher: FreePortOutputRegex, anchor: 'bottom', offset: 0, - length: 20 + length: 30 }, exitStatus: false, getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { From d31d71d8cc480313088a384ebb2c9e4f682601ae Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 15:40:48 +0200 Subject: [PATCH 160/599] check basename, not separator and name (#162174) fixes https://github.com/microsoft/vscode/issues/162141 --- src/vs/platform/protocol/electron-main/protocolMainService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/protocol/electron-main/protocolMainService.ts b/src/vs/platform/protocol/electron-main/protocolMainService.ts index b4b9544fccf..43ad2167684 100644 --- a/src/vs/platform/protocol/electron-main/protocolMainService.ts +++ b/src/vs/platform/protocol/electron-main/protocolMainService.ts @@ -8,7 +8,7 @@ import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; import { COI, FileAccess, Schemas } from 'vs/base/common/network'; -import { extname, normalize } from 'vs/base/common/path'; +import { basename, extname, normalize } from 'vs/base/common/path'; import { isLinux } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; @@ -96,7 +96,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ let headers: Record | undefined; if (this.environmentService.crossOriginIsolated) { - if (path.endsWith('/workbench.html') || path.endsWith('/workbench-dev.html')) { + if (basename(path) === 'workbench.html' || basename(path) === 'workbench-dev.html') { headers = COI.CoopAndCoep; } else { headers = COI.getHeadersFromQuery(request.url); From 781fb481784322fe24d1096fe807e337d9fac40c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 16:25:54 +0200 Subject: [PATCH 161/599] disable `EditorContent`-menu for embedded editors, ignore the `FloatingClickMenu`-contribution for notebook code edtors (#162186) fixes https://github.com/microsoft/vscode/issues/160910 --- src/vs/workbench/browser/codeeditor.ts | 50 ++++++++++--------- .../notebook/browser/notebookEditorWidget.ts | 3 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/browser/codeeditor.ts b/src/vs/workbench/browser/codeeditor.ts index 00be0866e3e..3a77af1f995 100644 --- a/src/vs/workbench/browser/codeeditor.ts +++ b/src/vs/workbench/browser/codeeditor.ts @@ -26,6 +26,7 @@ import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IAction } from 'vs/base/common/actions'; +import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; export interface IRangeHighlightDecoration { resource: URI; @@ -224,28 +225,31 @@ export class FloatingClickMenu extends Disposable implements IEditorContribution ) { super(); - const menu = menuService.createMenu(MenuId.EditorContent, contextKeyService); - const menuDisposables = new DisposableStore(); - const renderMenuAsFloatingClickBtn = () => { - menuDisposables.clear(); - if (!editor.hasModel() || editor.getOption(EditorOption.inDiffEditor)) { - return; - } - const actions: IAction[] = []; - createAndFillInActionBarActions(menu, { renderShortTitle: true, shouldForwardArgs: true }, actions); - if (actions.length === 0) { - return; - } - // todo@jrieken find a way to handle N actions, like showing a context menu - const [first] = actions; - const widget = instantiationService.createInstance(FloatingClickWidget, editor, first.label, first.id); - menuDisposables.add(widget); - menuDisposables.add(widget.onClick(() => first.run(editor.getModel().uri))); - widget.render(); - }; - this._store.add(menu); - this._store.add(menuDisposables); - this._store.add(menu.onDidChange(renderMenuAsFloatingClickBtn)); - renderMenuAsFloatingClickBtn(); + // DISABLED for embedded editors. In the future we can use a different MenuId for embedded editors + if (!(editor instanceof EmbeddedCodeEditorWidget)) { + const menu = menuService.createMenu(MenuId.EditorContent, contextKeyService); + const menuDisposables = new DisposableStore(); + const renderMenuAsFloatingClickBtn = () => { + menuDisposables.clear(); + if (!editor.hasModel() || editor.getOption(EditorOption.inDiffEditor)) { + return; + } + const actions: IAction[] = []; + createAndFillInActionBarActions(menu, { renderShortTitle: true, shouldForwardArgs: true }, actions); + if (actions.length === 0) { + return; + } + // todo@jrieken find a way to handle N actions, like showing a context menu + const [first] = actions; + const widget = instantiationService.createInstance(FloatingClickWidget, editor, first.label, first.id); + menuDisposables.add(widget); + menuDisposables.add(widget.onClick(() => first.run(editor.getModel().uri))); + widget.render(); + }; + this._store.add(menu); + this._store.add(menuDisposables); + this._store.add(menu.onDidChange(renderMenuAsFloatingClickBtn)); + renderMenuAsFloatingClickBtn(); + } } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 09d6ffab345..eab8921da11 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -86,12 +86,13 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { NotebookPerfMarks } from 'vs/workbench/contrib/notebook/common/notebookPerformance'; import { BaseCellEditorOptions } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEditorOptions'; import { ILogService } from 'vs/platform/log/common/log'; +import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor'; const $ = DOM.$; export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOptions { // We inlined the id to avoid loading comment contrib in tests - const skipContributions = ['editor.contrib.review']; + const skipContributions = ['editor.contrib.review', FloatingClickMenu.ID]; const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); return { From 3918cc137a56b4c35cbc1286e728afdd598fd18d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 16:29:53 +0200 Subject: [PATCH 162/599] tweak animation for menu items that are currently being configured (#162193) fixes https://github.com/microsoft/vscode/issues/161999 --- .../actions/browser/menuEntryActionViewItem.css | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.css b/src/vs/platform/actions/browser/menuEntryActionViewItem.css index 31eb20ba8a8..5f0134dfeae 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.css +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.css @@ -11,27 +11,29 @@ background-size: 16px; } - @keyframes shift { 0% { - transform: scale(1); + transform: translateX(0px); } - 15%{ - transform: scale(1.1); + 33%{ + transform: translateX(0.5px); } - 100% { - transform: scale(1); + 66% { + transform: translateX(-0.5px); } } .monaco-toolbar.config .monaco-action-bar .action-item { animation-duration: 1.2s; - animation-iteration-count: 1; + animation-iteration-count: infinite; animation-name: shift; } +.monaco-toolbar.config .monaco-action-bar .action-item:nth-child(odd) { + animation-delay: 0.6s; +} .monaco-dropdown-with-default { display: flex !important; From 7fc4f97bbb8e73e8bcabdfb47f1692e51edb9ea9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 16:57:19 +0200 Subject: [PATCH 163/599] Fix #162103 (#162199) --- .../common/extensionManagementService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index d39ae8f4315..a8d11483188 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -96,26 +96,26 @@ export class ExtensionManagementService extends Disposable implements IWorkbench } if (this.servers.length > 1) { if (isLanguagePackExtension(extension.manifest)) { - return this.uninstallEverywhere(extension); + return this.uninstallEverywhere(extension, options); } return this.uninstallInServer(extension, server, options); } - return server.extensionManagementService.uninstall(extension); + return server.extensionManagementService.uninstall(extension, options); } - private async uninstallEverywhere(extension: ILocalExtension): Promise { + private async uninstallEverywhere(extension: ILocalExtension, options?: UninstallOptions): Promise { const server = this.getServer(extension); if (!server) { return Promise.reject(`Invalid location ${extension.location.toString()}`); } - const promise = server.extensionManagementService.uninstall(extension); + const promise = server.extensionManagementService.uninstall(extension, options); const otherServers: IExtensionManagementServer[] = this.servers.filter(s => s !== server); if (otherServers.length) { for (const otherServer of otherServers) { const installed = await otherServer.extensionManagementService.getInstalled(); extension = installed.filter(i => !i.isBuiltin && areSameExtensions(i.identifier, extension.identifier))[0]; if (extension) { - await otherServer.extensionManagementService.uninstall(extension); + await otherServer.extensionManagementService.uninstall(extension, options); } } } From 29c5839eacc04b6e80178b6f5fabbb1bc95ec245 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 28 Sep 2022 08:15:53 -0700 Subject: [PATCH 164/599] Fix matching against unwrapped lines Part of #162070 --- .../capabilities/commandDetectionCapability.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 0beddabbf59..f2528c91300 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -663,7 +663,13 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en let line: string | undefined; if (outputMatcher?.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { - line = getXtermLineContent(buffer, i, i, cols); + let wrappedLineStart = i; + const wrappedLineEnd = i; + while (wrappedLineStart >= startLine && buffer.getLine(wrappedLineStart)?.isWrapped) { + wrappedLineStart--; + } + i = wrappedLineStart; + line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); const match = line.match(outputMatcher.lineMatcher); if (match) { return match; @@ -671,7 +677,13 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en } } else { for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) { - line = getXtermLineContent(buffer, i, i, cols); + const wrappedLineStart = i; + let wrappedLineEnd = i; + while (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) { + wrappedLineEnd++; + } + i = wrappedLineEnd; + line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); if (outputMatcher) { const match = line.match(outputMatcher.lineMatcher); if (match) { From 8697f846517863d4c7bb346142dba1697f2bed84 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 17:30:54 +0200 Subject: [PATCH 165/599] add logging for #162124 (#162202) --- .../userDataSync/common/userDataAutoSyncService.ts | 2 +- .../userDataSync/common/userDataSyncService.ts | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 1cae7582e56..3cf12e871af 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -204,8 +204,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto await this.userDataSyncService.resetLocal(); } } catch (error) { + this.logService.error(error); if (softTurnOffOnError) { - this.logService.error(error); this.updateEnablement(false); } else { throw error; diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 49b22b246ad..828b37cef34 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -391,16 +391,14 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ async resetLocal(): Promise { this.checkEnablement(); this.storageService.remove(LAST_SYNC_TIME_KEY, StorageScope.APPLICATION); - if (this.activeProfileSynchronizers) { - for (const [synchronizer] of this.activeProfileSynchronizers.values()) { - try { - await synchronizer.resetLocal(); - } catch (e) { - this.logService.error(e); - } + for (const [synchronizer] of this.activeProfileSynchronizers.values()) { + try { + await synchronizer.resetLocal(); + } catch (e) { + this.logService.error(e); } - this.clearActiveProfileSynchronizers(); } + this.clearActiveProfileSynchronizers(); this._onDidResetLocal.fire(); this.logService.info('Did reset the local sync state.'); } From 359a67e99f317755df280bf25956dae9de98ff04 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 17:39:22 +0200 Subject: [PATCH 166/599] Fix #162045 (#162205) --- .../userDataProfile/browser/userDataProfile.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 602b490276f..2fec1eb7b7a 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -27,6 +27,7 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { joinPath } from 'vs/base/common/resources'; +import { Codicon } from 'vs/base/common/codicons'; export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution { @@ -188,7 +189,17 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements value: that.userDataProfileService.getShortName(profile), title: localize('change short name', "Change Short Name..."), validateInput: async (value: string) => { - if (profile.shortName !== value && !ThemeIcon.fromString(value) && charCount(value) > 2) { + if (profile.shortName === value) { + return undefined; + } + const themeIcon = ThemeIcon.fromString(value); + if (themeIcon) { + if (Codicon.getAll().some(c => c.id === themeIcon.id)) { + return undefined; + } + return localize('invalid codicon', "Invalid codicon. Please use a valid codicon id."); + } + if (charCount(value) > 2) { return localize('invalid short name', "Short name should be at most 2 characters long."); } return undefined; From c72bd548732d338a1702ae5ab59edbf3e821a149 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 17:44:29 +0200 Subject: [PATCH 167/599] Fix #162049 (#162207) --- .../contrib/userDataProfile/browser/userDataProfile.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 2fec1eb7b7a..848594527db 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -164,11 +164,13 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements const that = this; return registerAction2(class UpdateCurrentProfileShortName extends Action2 { constructor() { + const shortName = that.userDataProfileService.getShortName(that.userDataProfileService.currentProfile); + const themeIcon = ThemeIcon.fromString(shortName); super({ id: `workbench.profiles.actions.updateCurrentProfileShortName`, title: { - value: localize('change short name profile', "Change Short Name ({0})...", that.userDataProfileService.getShortName(that.userDataProfileService.currentProfile)), - original: `Change Short Name (${that.userDataProfileService.currentProfile.shortName})...` + value: localize('change short name profile', "Change Short Name ({0})...", themeIcon?.id ?? shortName), + original: `Change Short Name (${themeIcon?.id ?? shortName})...` }, menu: [ { From 8fcdf4e417597ad54341dc2811b2d5af89c99188 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 17:52:39 +0200 Subject: [PATCH 168/599] Fix #162046 (#162209) --- .../workbench/browser/parts/activitybar/media/activityaction.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 84d5729892d..395d1193e74 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -184,7 +184,6 @@ justify-content: center; align-items: center; font-size: 14px; - line-height: 16px; border-radius: 8px; } From eb99a782ff563ca3f6ed400ab700e3ab41f2243b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 17:58:15 +0200 Subject: [PATCH 169/599] fix https://github.com/microsoft/vscode/issues/161394 (#162213) --- src/vs/base/browser/defaultWorkerFactory.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/defaultWorkerFactory.ts b/src/vs/base/browser/defaultWorkerFactory.ts index 9d2a34494be..87103de1a54 100644 --- a/src/vs/base/browser/defaultWorkerFactory.ts +++ b/src/vs/base/browser/defaultWorkerFactory.ts @@ -43,11 +43,20 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string return URL.createObjectURL(blob); } - const result = new URL(scriptPath); - COI.addSearchParam(result.searchParams, true, true); - result.hash = label; - return result.href; + const start = scriptPath.lastIndexOf('?'); + const end = scriptPath.lastIndexOf('#', start); + const params = start > 0 + ? new URLSearchParams(scriptPath.substring(start + 1, ~end ? end : undefined)) + : new URLSearchParams(); + COI.addSearchParam(params, true, true); + const search = params.toString(); + + if (!search) { + return `${scriptPath}#${label}`; + } else { + return `${scriptPath}?${params.toString()}#${label}`; + } } // ESM-comment-end From c532da7b3de7dc16c619309e370657dba22de9d9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 28 Sep 2022 18:01:43 +0200 Subject: [PATCH 170/599] fix #162044 (#162215) * Fix #162044 * Fix #162044 - wait unti all are settled --- src/vs/platform/userDataProfile/common/userDataProfile.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 668a16b7c50..c68e5cf1c99 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -354,7 +354,12 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf joiners.push(promise); } }); - await Promises.settled(joiners); + + try { + await Promise.allSettled(joiners); + } catch (error) { + this.logService.error(error); + } if (profile.id === this.profilesObject.emptyWindow?.id) { this.profilesObject.emptyWindow = undefined; From 8efe4be923d0e2b163ab19da01c927154ed58550 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 28 Sep 2022 18:49:12 +0200 Subject: [PATCH 171/599] - Add `_isFakeAction` as a workaround to noop-actions that are contributed to menus but that don't do anything (#162220) - Mark esp filtering/switching actions as fake actions https://github.com/microsoft/vscode/issues/162004 --- src/vs/platform/action/common/action.ts | 2 ++ src/vs/platform/actions/browser/toolbar.ts | 8 +++++++- src/vs/platform/actions/common/actions.ts | 7 +++++++ src/vs/platform/actions/common/menuService.ts | 3 ++- .../contrib/comments/browser/commentsViewActions.ts | 1 + src/vs/workbench/contrib/debug/browser/repl.ts | 3 ++- .../contrib/markers/browser/markers.contribution.ts | 1 + .../contrib/output/browser/output.contribution.ts | 1 + .../contrib/testing/browser/testingExplorerFilter.ts | 1 + 9 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/action/common/action.ts b/src/vs/platform/action/common/action.ts index 4b3f1b5f0ff..d931781183b 100644 --- a/src/vs/platform/action/common/action.ts +++ b/src/vs/platform/action/common/action.ts @@ -40,6 +40,8 @@ export interface ICommandAction { source?: string; precondition?: ContextKeyExpression; toggled?: ContextKeyExpression | { condition: ContextKeyExpression; icon?: Icon; tooltip?: string; title?: string | ILocalizedString }; + /** @deprecated see https://github.com/microsoft/vscode/issues/162004 */ + _isFakeAction?: true; } export type ISerializableCommandAction = UriDto; diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index be59a56d5a3..63bc9d27504 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -151,8 +151,14 @@ export class WorkbenchToolBar extends ToolBar { // add "hide foo" actions let hideAction: IAction; - if ((action instanceof MenuItemAction || action instanceof SubmenuItemAction) && action.hideActions) { + if (action instanceof MenuItemAction || action instanceof SubmenuItemAction) { + if (!action.hideActions) { + // no context menu for MenuItemAction instances that support no hiding + // those are fake actions and need to be cleaned up + return; + } hideAction = action.hideActions.hide; + } else { hideAction = toAction({ id: 'label', diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index e32071c164c..3c3353f52d6 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -554,6 +554,13 @@ export interface IAction2Options extends ICommandAction { * showing keybindings that have no other UX. */ description?: ICommandHandlerDescription; + + /** + * @deprecated workaround added for https://github.com/microsoft/vscode/issues/162004 + * This action doesn't do anything is just a workaround for rendering "something" + * inside a specific toolbar + */ + _isFakeAction?: true; } export abstract class Action2 { diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index 86ff1bd3b7e..d3671f623f8 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -229,7 +229,8 @@ class MenuInfo { const menuHide = createMenuHide(this._id, isMenuItem ? item.command : item, this._hiddenStates); if (isMenuItem) { // MenuItemAction - activeActions.push(new MenuItemAction(item.command, item.alt, options, menuHide, this._contextKeyService, this._commandService)); + const actualMenuHide = item.command._isFakeAction ? undefined : menuHide; + activeActions.push(new MenuItemAction(item.command, item.alt, options, actualMenuHide, this._contextKeyService, this._commandService)); } else { // SubmenuItemAction diff --git a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts index 4445e3a05b0..420029d895e 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts @@ -412,6 +412,7 @@ registerAction2(class extends ViewAction { registerAction2(class extends Action2 { constructor() { super({ + _isFakeAction: true, id: `workbench.actions.treeView.${COMMENTS_VIEW_ID}.filter`, title: localize('filter', "Filter"), menu: { diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index dfcdd381ef0..971f1e341f8 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -879,6 +879,7 @@ function getReplView(viewsService: IViewsService): Repl | undefined { registerAction2(class extends Action2 { constructor() { super({ + _isFakeAction: true, id: FILTER_ACTION_ID, title: localize('filter', "Filter"), f1: false, @@ -887,7 +888,7 @@ registerAction2(class extends Action2 { group: 'navigation', when: ContextKeyExpr.equals('view', REPL_VIEW_ID), order: 10 - } + }, }); } diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index f19aa0a7492..58105365186 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -409,6 +409,7 @@ registerAction2(class extends ViewAction { registerAction2(class extends Action2 { constructor() { super({ + _isFakeAction: true, id: `workbench.actions.treeView.${Markers.MARKERS_VIEW_ID}.filter`, title: localize('filter', "Filter"), menu: { diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index d7c89247cde..5e24f0af009 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -107,6 +107,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi registerAction2(class extends Action2 { constructor() { super({ + _isFakeAction: true, id: `workbench.output.action.switchBetweenOutputs`, title: nls.localize('switchToOutput.label', "Switch to Output"), menu: { diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index 23ced5391da..e2054a472cc 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -246,6 +246,7 @@ class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem { registerAction2(class extends Action2 { constructor() { super({ + _isFakeAction: true, id: TestCommandId.FilterAction, title: { value: localize('filter', "Filter"), original: 'Filter' }, }); From f244628c42a7e8d5f5cc83fd9477fcfac767eb10 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 28 Sep 2022 10:27:38 -0700 Subject: [PATCH 172/599] experiment setting for nb overview (#162223) exp setting for nb overview --- .../browser/diff/notebookTextDiffEditor.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 977573bf87d..bcab942c8cc 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -157,6 +157,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._revealFirst = true; } + private isOverviewRulerEnabled(): boolean { + return this.configurationService.getValue('notebook.experimental.diffOverviewRuler.enabled') ?? false; + } + getSelection(): IEditorPaneSelection | undefined { const selections = this._list.getFocus(); return new NotebookDiffEditorSelection(selections); @@ -559,7 +563,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _setViewModel(viewModels: DiffElementViewModelBase[]) { this._diffElementViewModels = viewModels; this._list.splice(0, this._list.length, this._diffElementViewModels); - this._overviewRuler.updateViewModels(this._diffElementViewModels, this._eventDispatcher); + if (this.isOverviewRulerEnabled()) { + this._overviewRuler.updateViewModels(this._diffElementViewModels, this._eventDispatcher); + } } /** @@ -976,7 +982,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD layout(dimension: DOM.Dimension): void { this._rootElement.classList.toggle('mid-width', dimension.width < 1000 && dimension.width >= 600); this._rootElement.classList.toggle('narrow-width', dimension.width < 600); - this._dimension = dimension.with(dimension.width - NotebookTextDiffEditor.ENTIRE_DIFF_OVERVIEW_WIDTH); + const overviewRulerEnabled = this.isOverviewRulerEnabled(); + this._dimension = dimension.with(dimension.width - (overviewRulerEnabled ? NotebookTextDiffEditor.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)); this._listViewContainer.style.height = `${dimension.height}px`; this._listViewContainer.style.width = `${this._dimension.width}px`; @@ -998,7 +1005,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._webviewTransparentCover.style.width = `${this._dimension.width}px`; } - this._overviewRuler.layout(); + if (overviewRulerEnabled) { + this._overviewRuler.layout(); + } this._eventDispatcher?.emit([new NotebookDiffLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } From 0f6d665434f8655350442ea0934cdaa88e3634eb Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 28 Sep 2022 10:55:17 -0700 Subject: [PATCH 173/599] rm length conditional from get output match (#162225) fix 162211 --- .../common/capabilities/commandDetectionCapability.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index f2528c91300..5b6a8ca79ac 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -657,9 +657,7 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en if (startLine === endLine) { return undefined; } - if (outputMatcher?.length && (endLine - startLine) < outputMatcher.length) { - return undefined; - } + let line: string | undefined; if (outputMatcher?.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { From 06f29ea59f0e9df6c7751ab5160f09ab90937a4c Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 28 Sep 2022 11:07:38 -0700 Subject: [PATCH 174/599] remove unused entry (#162237) fix 162230 --- .../workbench/contrib/terminal/browser/xterm/decorationAddon.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index e520738108a..22cc61d788b 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -496,6 +496,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } await this._configurationService.updateValue(TerminalSettingId.ShellIntegrationDecorationsEnabled, newValue); }); + quickPick.ok = false; quickPick.show(); } } From 5296b0faf3f957461335132ff2239ebec349e62f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 28 Sep 2022 11:08:03 -0700 Subject: [PATCH 175/599] Add explicit "inherit" setting for fragments links (#162231) Fixes #162129 --- extensions/markdown-language-features/package.json | 3 ++- extensions/markdown-language-features/server/README.md | 2 +- .../markdown-language-features/server/src/configuration.ts | 2 +- .../server/src/languageFeatures/diagnostics.ts | 5 +++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 605ee9c1429..059fe5d1a61 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -477,8 +477,9 @@ "type": "string", "scope": "resource", "markdownDescription": "%configuration.markdown.validate.fileLinks.markdownFragmentLinks.description%", - "default": "ignore", + "default": "inherit", "enum": [ + "inherit", "ignore", "warning", "error" diff --git a/extensions/markdown-language-features/server/README.md b/extensions/markdown-language-features/server/README.md index 761baf37719..a4935ad3ebb 100644 --- a/extensions/markdown-language-features/server/README.md +++ b/extensions/markdown-language-features/server/README.md @@ -64,7 +64,7 @@ The server supports the following settings: - `enabled` — Enable/disable validation of links to fragments in the current files: `[text](#head)` - `fileLinks` - `enabled` — Enable/disable validation of links to file in the workspace. - - `markdownFragmentLinks` — Enable/disable validation of links to headers in other Markdown files. + - `markdownFragmentLinks` — Enable/disable validation of links to headers in other Markdown files. Use `inherit` to inherit the `fragmentLinks` setting. - `ignoredLinks` — Array of glob patterns for files that should not be validated. ### Custom requests diff --git a/extensions/markdown-language-features/server/src/configuration.ts b/extensions/markdown-language-features/server/src/configuration.ts index 69358261f82..8bd3fcc730b 100644 --- a/extensions/markdown-language-features/server/src/configuration.ts +++ b/extensions/markdown-language-features/server/src/configuration.ts @@ -26,7 +26,7 @@ interface Settings { }; readonly fileLinks: { readonly enabled: ValidateEnabled; - readonly markdownFragmentLinks: ValidateEnabled; + readonly markdownFragmentLinks: ValidateEnabled | 'inherit'; }; readonly ignoredLinks: readonly string[]; }; diff --git a/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts index d0f4d9c73af..a7b43877f5d 100644 --- a/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts +++ b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts @@ -33,11 +33,12 @@ function getDiagnosticsOptions(config: ConfigurationManager): md.DiagnosticOptio return defaultDiagnosticOptions; } + const validateFragmentLinks = convertDiagnosticLevel(settings.markdown.validate.fragmentLinks.enabled); return { validateFileLinks: convertDiagnosticLevel(settings.markdown.validate.fileLinks.enabled), validateReferences: convertDiagnosticLevel(settings.markdown.validate.referenceLinks.enabled), - validateFragmentLinks: convertDiagnosticLevel(settings.markdown.validate.fragmentLinks.enabled), - validateMarkdownFileLinkFragments: convertDiagnosticLevel(settings.markdown.validate.fileLinks.markdownFragmentLinks), + validateFragmentLinks, + validateMarkdownFileLinkFragments: settings.markdown.validate.fileLinks.markdownFragmentLinks === 'inherit' ? validateFragmentLinks : convertDiagnosticLevel(settings.markdown.validate.fileLinks.markdownFragmentLinks), ignoreLinks: settings.markdown.validate.ignoredLinks, }; } From dd4d29dd8b25e4eac62f6b54e9b7f751be3f30de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?6=E2=AD=90=20Sygna=20Suit=20Red-EX?= Date: Thu, 29 Sep 2022 04:29:18 +1000 Subject: [PATCH 176/599] Update Python source highlighting example to be more idiomatic (#154013) --- .../python/test/colorize-fixtures/test.py | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/extensions/python/test/colorize-fixtures/test.py b/extensions/python/test/colorize-fixtures/test.py index c92f2c70a8b..c32f12e4f8b 100644 --- a/extensions/python/test/colorize-fixtures/test.py +++ b/extensions/python/test/colorize-fixtures/test.py @@ -19,13 +19,10 @@ class Monkey: }=42): pass -if 1900 < year < 2100 and 1 <= month <= 12 \ - and 1 <= day <= 31 and 0 <= hour < 24 \ - and 0 <= minute < 60 and 0 <= second < 60: # Looks like a valid date - return 1 +pass def firstn(g, n): - for i in range(n): + for _ in range(n): yield g.next() reduce(lambda x,y: x+y, [47,11,42,13]) @@ -37,15 +34,14 @@ mydictionary = { } def steuern(einkommen): - """Berechnung der zu zahlenden Steuern fuer ein zu versteuerndes Einkommen von x""" - if einkommen <= 8004: - steuer = 0 - elif einkommen <= 13469: - y = (einkommen -8004.0)/10000.0 - steuer = (912.17 * y + 1400)*y - else: - steuer = einkommen * 0.44 - 15694 - return steuer + """Berechnung der zu zahlenden Steuern fuer ein zu versteuerndes Einkommen von x""" + if einkommen <= 8004: + return 0 + elif einkommen <= 13469: + y = (einkommen -8004.0)/10000.0 + return (912.17 * y + 1400)*y + else: + return einkommen * 0.44 - 15694 def beliebig(x, y, *mehr): print "x=", x, ", x=", y From fec2b499d5cfee8622bd849cc3cf573ca1e5ada6 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:30:09 -0700 Subject: [PATCH 177/599] fixed bug with collapsing compressed nodes (#162222) fixed bug with collapsing compression nodes --- .../contrib/search/browser/searchActions.ts | 20 ++++++++++++++++--- .../search/browser/searchResultsView.ts | 2 ++ .../contrib/search/common/searchModel.ts | 4 ++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index cddc3dd9e41..6f121ec4d6f 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -292,14 +292,21 @@ export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { let canCollapseFileMatchLevel = false; let canCollapseFirstLevel = false; - if (node instanceof FolderMatch) { + if (node instanceof FolderMatchWorkspaceRoot) { while (node = navigator.next()) { if (node instanceof Match) { canCollapseFileMatchLevel = true; break; } if (searchView.isTreeLayoutViewVisible && !canCollapseFirstLevel) { - const immediateParent = node.parent(); + let nodeToTest = node; + + if (node instanceof FolderMatch) { + nodeToTest = node.compressionStartParent ?? node; + } + + const immediateParent = nodeToTest.parent(); + if (!(immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot || immediateParent instanceof SearchResult)) { canCollapseFirstLevel = true; } @@ -318,7 +325,14 @@ export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { node = navigator.first(); if (node) { do { - const immediateParent = node.parent(); + + let nodeToTest = node; + + if (node instanceof FolderMatch) { + nodeToTest = node.compressionStartParent ?? node; + } + const immediateParent = nodeToTest.parent(); + if (immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot) { if (viewer.hasElement(node)) { viewer.collapse(node, true); diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index 61e04bbf36a..5ddcc2e1134 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -95,6 +95,7 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree renderCompressedElements(node: ITreeNode, any>, index: number, templateData: IFolderMatchTemplate, height: number | undefined): void { const compressed = node.element; const folder = compressed.elements[compressed.elements.length - 1]; + folder.compressionStartParent = compressed.elements[0]; const label = compressed.elements.map(e => e.name()); if (folder.resource) { @@ -134,6 +135,7 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree renderElement(node: ITreeNode, index: number, templateData: IFolderMatchTemplate): void { const folderMatch = node.element; + folderMatch.compressionStartParent = undefined; if (folderMatch.resource) { const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource); if (workspaceFolder && isEqual(workspaceFolder.uri, folderMatch.resource)) { diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 0aafd7dbff6..daadea9af49 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -492,6 +492,10 @@ export class FolderMatch extends Disposable { protected _unDisposedFileMatches: ResourceMap; protected _unDisposedFolderMatches: ResourceMap; private _replacingAll: boolean = false; + + // if this is compressed in a node with other FolderMatches, then this is set to the parent where compression starts + public compressionStartParent: FolderMatch | undefined; + constructor( protected _resource: URI | null, private _id: string, From baf4f094367bd9d06a285e8c2264d93d243c9274 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 28 Sep 2022 11:39:10 -0700 Subject: [PATCH 178/599] Use correct theme color name (#162238) For #162125 --- src/vs/editor/contrib/codeAction/browser/codeActionWidget.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css index 2561c7f4f04..0f0e9b3c299 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css +++ b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css @@ -14,7 +14,7 @@ border: 1px solid var(--vscode-editorWidget-border) !important; border-color: none; background-color: var(--vscode-editorWidget-background); - color: var(--vscode--editorWidget-foreground); + color: var(--vscode-editorWidget-foreground); box-shadow: var(--vscode-widget-shadow) 0 2px 8px; } From a1b0e0eacf9825b78a1b098dbd8986a2e0e0b550 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 28 Sep 2022 21:40:32 +0200 Subject: [PATCH 179/599] Deprecated settings show up with undefined label (#162145) Deprecated settings show up with undefined label --- .../contrib/extensions/browser/extensionEditor.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 33ac92c4aed..746a1af95ba 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -1172,7 +1172,14 @@ export class ExtensionEditor extends EditorPane { } else if (configuration) { properties = configuration.properties; } - const contrib = properties ? Object.keys(properties) : []; + + let contrib = properties ? Object.keys(properties) : []; + + // filter deprecated settings + contrib = contrib.filter(key => { + const config = properties[key]; + return !config.deprecationMessage && !config.markdownDeprecationMessage; + }); if (!contrib.length) { return false; @@ -1187,7 +1194,7 @@ export class ExtensionEditor extends EditorPane { $('th', undefined, localize('default', "Default")) ), ...contrib.map(key => { - let description: (Node | string) = properties[key].description; + let description: (Node | string) = properties[key].description || ''; if (properties[key].markdownDescription) { const { element, dispose } = renderMarkdown({ value: properties[key].markdownDescription }, { actionHandler: { callback: (content) => this.openerService.open(content).catch(onUnexpectedError), disposables: this.contentDisposables } }); description = element; From 4bfd9eb6e66fc25eb7d5df55a31f455f1c9b1ab7 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 28 Sep 2022 20:00:40 +0000 Subject: [PATCH 180/599] Fix https://github.com/microsoft/vscode/issues/162116 (#162244) * Fix conflicting changes count warning when resuming edit session * Don't use custom dialog --- .../editSessions/browser/editSessions.contribution.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index cb6dcacc810..fb5487270ba 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -414,13 +414,12 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo const result = await this.dialogService.show( Severity.Warning, - changes.length > 1 ? - localize('resume edit session warning many', 'Resuming your edit session will overwrite the following {0} files. Do you want to proceed?', changes.length) : - localize('resume edit session warning 1', 'Resuming your edit session will overwrite {0}. Do you want to proceed?', basename(changes[0].uri)), + conflictingChanges.length > 1 ? + localize('resume edit session warning many', 'Resuming your edit session will overwrite the following {0} files. Do you want to proceed?', conflictingChanges.length) : + localize('resume edit session warning 1', 'Resuming your edit session will overwrite {0}. Do you want to proceed?', basename(conflictingChanges[0].uri)), [cancel, yes], { - custom: true, - detail: changes.length > 1 ? getFileNamesMessage(conflictingChanges.map((c) => c.uri)) : undefined, + detail: conflictingChanges.length > 1 ? getFileNamesMessage(conflictingChanges.map((c) => c.uri)) : undefined, cancelId: 0 }); From 9ec34a5b60ad75f831f65fd009f045d16ed94179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 28 Sep 2022 13:50:35 -0700 Subject: [PATCH 181/599] Revert "stop shipping build-only dependencies (#162172)" (#162254) This reverts commit 582aa29f857825ddff8ea681d5df940adc17c5ff. --- build/.moduleignore | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/build/.moduleignore b/build/.moduleignore index 07e2a0e84e9..438f9b575d1 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -1,13 +1,9 @@ # cleanup rules for node modules, .gitignore style +# native node modules + nan/** -**/node_modules/nan/** -node-gyp/** -**/node_modules/node-gyp/** -node-gyp-build/** -**/node_modules/node-gyp-build/** -node-addon-api/** -**/node_modules/node-addon-api/** +*/node_modules/nan/** fsevents/binding.gyp fsevents/fsevents.cc From cbb0a982fdb9c84cbf60b431be7b2437ce84c1e0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 28 Sep 2022 14:02:26 -0700 Subject: [PATCH 182/599] Pick up final markdown language service 0.1 release (#162256) Just pulling in the stable release --- extensions/markdown-language-features/server/package.json | 2 +- extensions/markdown-language-features/server/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json index f6a832c69ce..2f6f3a5981a 100644 --- a/extensions/markdown-language-features/server/package.json +++ b/extensions/markdown-language-features/server/package.json @@ -13,7 +13,7 @@ "vscode-languageserver": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.5", "vscode-languageserver-types": "^3.17.1", - "vscode-markdown-languageservice": "^0.1.0-alpha.10", + "vscode-markdown-languageservice": "^0.1.0", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index 65426cb72a5..c99899494bc 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -42,10 +42,10 @@ vscode-languageserver@^8.0.2: dependencies: vscode-languageserver-protocol "3.17.2" -vscode-markdown-languageservice@^0.1.0-alpha.10: - version "0.1.0-alpha.10" - resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.1.0-alpha.10.tgz#012dcf600b9d1a738cd7071f17627285342d17c7" - integrity sha512-GZTxGZp49BIf/k5plc5x+Bp70kmwaTdt523p+wifG9AQ0uKMSRcwmlKu8mOcJUd0ZvDR3ORI/Cze90Dy5HCM2A== +vscode-markdown-languageservice@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.1.0.tgz#6027e15094da005b66318e8edb099644c7557b25" + integrity sha512-fMUFjM7AZo7Mto7NS8PEDNJ5IpJQUvVemhlnLs3AP2jC59pOHwpeciuTEINF0ymjWQwu94OIbilBn7OB/Z1sUg== dependencies: picomatch "^2.3.1" vscode-languageserver-textdocument "^1.0.5" From 719461b2730d3611ecbfe2cfe83aa02f8008fd32 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 28 Sep 2022 23:27:23 +0200 Subject: [PATCH 183/599] bump distro (recommender-wsl update) (#162258) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50ebfd5ab89..96dd2c607ed 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.72.0", - "distro": "a241d92bfe3ed59289ea4922a282d747f8e59a9e", + "distro": "a75e0e9bdfca0851f24bfad4a244226c87a0c2c4", "author": { "name": "Microsoft Corporation" }, From 5a2baf9017f15d4950412466e202948618ddf843 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 28 Sep 2022 14:47:28 -0700 Subject: [PATCH 184/599] Search Tree Performance - FolderMatches and FileMatches (#162257) * Search Tree Performance - FolderMatches and FileMatches Fixes #162246 --- .../contrib/search/common/searchModel.ts | 38 +++++++++------ .../search/test/common/searchResult.test.ts | 46 +++++++++++-------- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index daadea9af49..f071e78c421 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -559,9 +559,10 @@ export class FolderMatch extends Disposable { if (fileMatch) { fileMatch.bindModel(model); } else { - this.folderMatches().forEach(e => { - e.bindModel(model); - }); + const folderMatches = this.folderMatchesIterator(); + for (const elem of folderMatches) { + elem.bindModel(model); + } } } @@ -603,15 +604,15 @@ export class FolderMatch extends Disposable { } matches(): (FileMatch | FolderMatchWithResource)[] { - return [...this.fileMatches(), ...this.folderMatches()]; + return [...this.fileMatchesIterator(), ...this.folderMatchesIterator()]; } - fileMatches(): FileMatch[] { - return [...this._fileMatches.values()]; + fileMatchesIterator(): IterableIterator { + return this._fileMatches.values(); } - folderMatches(): FolderMatchWithResource[] { - return [...this._folderMatches.values()]; + folderMatchesIterator(): IterableIterator { + return this._folderMatches.values(); } isEmpty(): boolean { @@ -623,8 +624,10 @@ export class FolderMatch extends Disposable { if (directChildFileMatch) { return directChildFileMatch; } - for (let i = 0; i < this.folderMatches().length; i++) { - const match = this.folderMatches()[i].hasFileUriDownstream(uri); + + const folderMatches = this.folderMatchesIterator(); + for (const elem of folderMatches) { + const match = elem.hasFileUriDownstream(uri); if (match) { return match; } @@ -633,8 +636,13 @@ export class FolderMatch extends Disposable { } downstreamFileMatches(): FileMatch[] { - const recursiveChildren = this.folderMatches().map(e => e.downstreamFileMatches()).flat(); - return [...this.fileMatches(), ...recursiveChildren]; + let recursiveChildren: FileMatch[] = []; + const iterator = this.folderMatchesIterator(); + for (const elem of iterator) { + recursiveChildren = recursiveChildren.concat(elem.downstreamFileMatches()); + } + + return [...this.fileMatchesIterator(), ...recursiveChildren]; } private fileCount(): number { @@ -712,7 +720,7 @@ export class FolderMatch extends Disposable { return false; } - private getFolderMatch(resource: URI): FolderMatchWithResource | undefined { + public getFolderMatch(resource: URI): FolderMatchWithResource | undefined { const folderMatch = this._folderMatchesMap.findSubstr(resource); return folderMatch; } @@ -770,7 +778,7 @@ export class FolderMatch extends Disposable { const removed = []; for (const match of fileMatches as FileMatch[]) { - if (this.fileMatches().includes(match)) { + if (this._fileMatches.get(match.resource)) { this._fileMatches.delete(match.resource); if (dispose) { match.dispose(); @@ -877,7 +885,7 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource { const root = this.closestRoot ?? this; let parent: FolderMatch = this; for (let i = 0; i < fileMatchParentParts.length; i++) { - let folderMatch: FolderMatchWithResource | undefined = parent.folderMatches().find(e => e.resource && (this.uriEquals(e.resource, fileMatchParentParts[i]))); + let folderMatch: FolderMatchWithResource | undefined = parent.getFolderMatch(fileMatchParentParts[i]); if (!folderMatch) { folderMatch = parent.createIntermediateFolderMatch(fileMatchParentParts[i], fileMatchParentParts[i].toString(), null, this._query, root); } diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index d9d8bcf32dd..fcbce0a9f36 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { Match, FileMatch, SearchResult, SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; +import { Match, FileMatch, SearchResult, SearchModel, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel'; import { URI } from 'vs/base/common/uri'; import { IFileMatch, TextSearchMatch, OneLineRange, ITextSearchMatch, QueryType } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -402,36 +402,36 @@ suite('SearchResult', () => { const root3 = testObject.folderMatches()[3]; const root0DownstreamFiles = root0.downstreamFileMatches(); - assert.deepStrictEqual(root0DownstreamFiles, root0.fileMatches().concat(root0.folderMatches()[0].fileMatches())); - assert.deepStrictEqual(root0.folderMatches()[0].downstreamFileMatches(), root0.folderMatches()[0].fileMatches()); - assert.deepStrictEqual(root0.folderMatches()[0].fileMatches()[0].parent(), root0.folderMatches()[0]); - assert.deepStrictEqual(root0.folderMatches()[0].parent(), root0); - assert.deepStrictEqual(root0.folderMatches()[0].closestRoot, root0); + assert.deepStrictEqual(root0DownstreamFiles, [...root0.fileMatchesIterator(), ...getFolderMatchAtIndex(root0, 0).fileMatchesIterator()]); + assert.deepStrictEqual(getFolderMatchAtIndex(root0, 0).downstreamFileMatches(), Array.from(getFolderMatchAtIndex(root0, 0).fileMatchesIterator())); + assert.deepStrictEqual(getFileMatchAtIndex(getFolderMatchAtIndex(root0, 0), 0).parent(), getFolderMatchAtIndex(root0, 0)); + assert.deepStrictEqual(getFolderMatchAtIndex(root0, 0).parent(), root0); + assert.deepStrictEqual(getFolderMatchAtIndex(root0, 0).closestRoot, root0); root0DownstreamFiles.forEach((e) => { assert.deepStrictEqual(e.closestRoot, root0); }); const root1DownstreamFiles = root1.downstreamFileMatches(); - assert.deepStrictEqual(root1.downstreamFileMatches(), root1.fileMatches().concat(root1.folderMatches()[0].fileMatches())); // excludes the matches from nested root - assert.deepStrictEqual(root1.folderMatches()[0].fileMatches()[0].parent(), root1.folderMatches()[0]); + assert.deepStrictEqual(root1.downstreamFileMatches(), [...root1.fileMatchesIterator(), ...getFolderMatchAtIndex(root1, 0).fileMatchesIterator()]); // excludes the matches from nested root + assert.deepStrictEqual(getFileMatchAtIndex(getFolderMatchAtIndex(root1, 0), 0).parent(), getFolderMatchAtIndex(root1, 0)); root1DownstreamFiles.forEach((e) => { assert.deepStrictEqual(e.closestRoot, root1); }); const root2DownstreamFiles = root2.downstreamFileMatches(); - assert.deepStrictEqual(root2DownstreamFiles, root2.fileMatches()); - assert.deepStrictEqual(root2.fileMatches()[0].parent(), root2); - assert.deepStrictEqual(root2.fileMatches()[0].closestRoot, root2); + assert.deepStrictEqual(root2DownstreamFiles, Array.from(root2.fileMatchesIterator())); + assert.deepStrictEqual(getFileMatchAtIndex(root2, 0).parent(), root2); + assert.deepStrictEqual(getFileMatchAtIndex(root2, 0).closestRoot, root2); const root3DownstreamFiles = root3.downstreamFileMatches(); - const root3Level3Folder = root3.folderMatches()[0].folderMatches()[0]; - assert.deepStrictEqual(root3DownstreamFiles, [root3.fileMatches(), ...root3Level3Folder.folderMatches()[0].fileMatches(), ...root3Level3Folder.folderMatches()[1].fileMatches()].flat()); - assert.deepStrictEqual(root3Level3Folder.downstreamFileMatches(), root3.folderMatches()[0].downstreamFileMatches()); + const root3Level3Folder = getFolderMatchAtIndex(getFolderMatchAtIndex(root3, 0), 0); + assert.deepStrictEqual(root3DownstreamFiles, [...root3.fileMatchesIterator(), ...getFolderMatchAtIndex(root3Level3Folder, 0).fileMatchesIterator(), ...getFolderMatchAtIndex(root3Level3Folder, 1).fileMatchesIterator()].flat()); + assert.deepStrictEqual(root3Level3Folder.downstreamFileMatches(), getFolderMatchAtIndex(root3, 0).downstreamFileMatches()); - assert.deepStrictEqual(root3Level3Folder.folderMatches()[1].fileMatches()[0].parent(), root3Level3Folder.folderMatches()[1]); - assert.deepStrictEqual(root3Level3Folder.folderMatches()[1].parent(), root3Level3Folder); - assert.deepStrictEqual(root3Level3Folder.parent(), root3.folderMatches()[0]); + assert.deepStrictEqual(getFileMatchAtIndex(getFolderMatchAtIndex(root3Level3Folder, 1), 0).parent(), getFolderMatchAtIndex(root3Level3Folder, 1)); + assert.deepStrictEqual(getFolderMatchAtIndex(root3Level3Folder, 1).parent(), root3Level3Folder); + assert.deepStrictEqual(root3Level3Folder.parent(), getFolderMatchAtIndex(root3, 0)); root3DownstreamFiles.forEach((e) => { assert.deepStrictEqual(e.closestRoot, root3); @@ -442,7 +442,7 @@ suite('SearchResult', () => { const target = sinon.spy(); const testObject = getPopulatedSearchResultForTreeTesting(); - const folderMatch = testObject.folderMatches()[3].folderMatches()[0].folderMatches()[0].folderMatches()[0]; + const folderMatch = getFolderMatchAtIndex(getFolderMatchAtIndex(getFolderMatchAtIndex(testObject.folderMatches()[3], 0), 0), 0); const expectedArrayResult = folderMatch.downstreamFileMatches(); @@ -456,7 +456,7 @@ suite('SearchResult', () => { const target = sinon.spy(); const testObject = getPopulatedSearchResultForTreeTesting(); - const folderMatch = testObject.folderMatches()[3].folderMatches()[0]; + const folderMatch = getFolderMatchAtIndex(testObject.folderMatches()[3], 0); const expectedArrayResult = folderMatch.downstreamFileMatches(); @@ -600,4 +600,12 @@ suite('SearchResult', () => { ]); return testObject; } + + function getFolderMatchAtIndex(parent: FolderMatch, index: number) { + return Array.from(parent.folderMatchesIterator())[index]; + } + + function getFileMatchAtIndex(parent: FolderMatch, index: number) { + return Array.from(parent.fileMatchesIterator())[index]; + } }); From 07ef05f7c81a6f2e7845bf8e385e13541cafea02 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 28 Sep 2022 14:47:52 -0700 Subject: [PATCH 185/599] Update xterm - Fixes a performance regression related to microtasks - Fixes trusted types error breaking DOM renderer Fixes #161970 --- package.json | 4 ++-- remote/package.json | 4 ++-- remote/web/package.json | 2 +- remote/web/yarn.lock | 8 ++++---- remote/yarn.lock | 16 ++++++++-------- yarn.lock | 16 ++++++++-------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 96dd2c607ed..4ad73f96dd9 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.13", + "xterm": "5.1.0-beta.15", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.13", + "xterm-headless": "5.1.0-beta.15", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index f2e0e2c39e6..5a2b2bb40a5 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.13", + "xterm": "5.1.0-beta.15", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.13", + "xterm-headless": "5.1.0-beta.15", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index e4145725bfe..090bd1fb4ce 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,7 +11,7 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.13", + "xterm": "5.1.0-beta.15", "xterm-addon-canvas": "0.3.0-beta.1", "xterm-addon-search": "0.11.0-beta.1", "xterm-addon-unicode11": "0.5.0-beta.1", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 2227e164923..246b60bc896 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -88,7 +88,7 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm@5.1.0-beta.13: - version "5.1.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" - integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== +xterm@5.1.0-beta.15: + version "5.1.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" + integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 2faad009179..09e066c08c8 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -813,15 +813,15 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.13: - version "5.1.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.13.tgz#ff1ae4bf9a9962410fb46dbe19c73f9b93ae4539" - integrity sha512-jbCCuJgpnv1Ncda45J08wlEAVEReYQonFx9Nu9YvjQyvnN5h0PkIAztFHHO3bjRPFHCC44fPfcmvJOvA4pZAZA== +xterm-headless@5.1.0-beta.15: + version "5.1.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.15.tgz#fba76c8e95b552e922354409864c0f55d3b499f7" + integrity sha512-LVtB+KkHs1R2RG8ug3IfOOU0J+qEGttfXagGxfzNq8zxxoSsgoY4D0YvLpM7M/5FK6eGK5K8/yol9XAK63ENog== -xterm@5.1.0-beta.13: - version "5.1.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" - integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== +xterm@5.1.0-beta.15: + version "5.1.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" + integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index 879f9671836..ebf28175131 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11653,15 +11653,15 @@ xterm-addon-webgl@0.14.0-beta.8: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== -xterm-headless@5.1.0-beta.13: - version "5.1.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.13.tgz#ff1ae4bf9a9962410fb46dbe19c73f9b93ae4539" - integrity sha512-jbCCuJgpnv1Ncda45J08wlEAVEReYQonFx9Nu9YvjQyvnN5h0PkIAztFHHO3bjRPFHCC44fPfcmvJOvA4pZAZA== +xterm-headless@5.1.0-beta.15: + version "5.1.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.15.tgz#fba76c8e95b552e922354409864c0f55d3b499f7" + integrity sha512-LVtB+KkHs1R2RG8ug3IfOOU0J+qEGttfXagGxfzNq8zxxoSsgoY4D0YvLpM7M/5FK6eGK5K8/yol9XAK63ENog== -xterm@5.1.0-beta.13: - version "5.1.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.13.tgz#efbc350a819ec7ff77ff340545178ee48d048e2d" - integrity sha512-p2E0XwuuIG6sFLy5/4gkPiesX6BdlR6+3Ew+Tcj+1aTvvum/1jKzmuKprZvQn1RRyCsQTpMrvOB0x5Tj7F9wEw== +xterm@5.1.0-beta.15: + version "5.1.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" + integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== y18n@^3.2.1: version "3.2.2" From a4071cf8deeea2b47072a2ebbe6802dc6fa27fd6 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 28 Sep 2022 14:57:54 -0700 Subject: [PATCH 186/599] add audio cue for terminal quick fix (#162226) --- .../workbench/contrib/audioCues/browser/audioCueService.ts | 6 ++++++ .../contrib/audioCues/browser/audioCues.contribution.ts | 4 ++++ .../contrib/terminal/browser/xterm/quickFixAddon.ts | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts b/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts index 1c26424410f..d8b25e74470 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts @@ -201,6 +201,12 @@ export class AudioCue { settingsKey: 'audioCues.lineHasInlineSuggestion', }); + public static readonly terminalQuickFix = AudioCue.register({ + name: localize('audioCues.terminalQuickFix.name', 'Terminal Quick Fix'), + sound: Sound.quickFixes, + settingsKey: 'audioCues.terminalQuickFix', + }); + public static readonly onDebugBreak = AudioCue.register({ name: localize('audioCues.onDebugBreak.name', 'Debugger Stopped on Breakpoint'), sound: Sound.break, diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index facb74870e4..061845f3af8 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -76,6 +76,10 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'description': localize('audioCues.taskEnded', "Plays a sound when a task ends."), ...audioCueFeatureBase, }, + 'audioCues.terminalQuickFix': { + 'description': localize('audioCues.terminalQuickFix', "Plays a sound when a terminal quick fixes are available"), + ...audioCueFeatureBase, + }, } }); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index d988516c0ac..e9f2e91fe93 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -19,6 +19,7 @@ import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/ import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; +import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService'; export interface ITerminalQuickFix { showMenu(): void; @@ -51,7 +52,8 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, constructor(private readonly _capabilities: ITerminalCapabilityStore, @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IConfigurationService private readonly _configurationService: IConfigurationService) { + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IAudioCueService private readonly _audioCueService: IAudioCueService) { super(); const commandDetectionCapability = this._capabilities.get(TerminalCapability.CommandDetection); if (commandDetectionCapability) { @@ -121,6 +123,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, this._currentQuickFixElement = e; e.classList.add(DecorationSelector.QuickFix, DecorationSelector.LightBulb, DecorationSelector.Codicon, DecorationSelector.CommandDecoration, DecorationSelector.XtermDecoration); updateLayout(this._configurationService, e); + this._audioCueService.playAudioCue(AudioCue.terminalQuickFix); if (actions) { this._decorationMarkerIds.add(decoration.marker.id); dom.addDisposableListener(e, dom.EventType.CLICK, () => { From 78d4808f29dadf96a9b334c45171bac3080cb40a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 28 Sep 2022 15:09:06 -0700 Subject: [PATCH 187/599] bind `configure` function so `this` is not undefined (#162245) --- src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 4c78b403fa1..2b90f232779 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2953,7 +2953,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer // eat the error, it has already been surfaced to the user and we don't care about it here }); } - const chooseAndRunTask = (tasks: Task[]) => { this._showIgnoredFoldersMessage().then(() => { this._showQuickPick(tasks, @@ -2968,7 +2967,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } if (task === null) { - configure(); + configure.apply(this); return; } runSingleTask(task, { attachProblemMatcher: true }, this); From 0c22a33a9d670a84309447b36abdbd8c04ee6219 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 28 Sep 2022 15:29:15 -0700 Subject: [PATCH 188/599] Allow opt-in multi-line quick fixes (#162189) Fixes #161997 Co-authored-by: meganrogge --- .../commandDetectionCapability.ts | 52 +++++++++++-------- .../contrib/terminal/browser/terminal.ts | 25 +-------- .../browser/terminalQuickFixBuiltinActions.ts | 2 +- .../contrib/terminal/common/terminal.ts | 23 ++++++-- .../test/browser/quickFixAddon.test.ts | 3 +- 5 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 5b6a8ca79ac..5257fd8352e 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -490,7 +490,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { commandStartLineContent: this._currentCommand.commandStartLineContent, hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), - getOutputMatch: (outputMatcher?: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), + getOutputMatch: (outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), markProperties: options?.markProperties }; this._commands.push(newCommand); @@ -647,43 +647,35 @@ function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMa return output === '' ? undefined : output; } -export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number } | undefined): RegExpMatchArray | undefined { +export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }): RegExpMatchArray | undefined { if (!executedMarker || !endMarker) { return undefined; } const startLine = executedMarker.line; const endLine = endMarker.line; - if (startLine === endLine) { - return undefined; - } - - let line: string | undefined; - if (outputMatcher?.anchor === 'bottom') { + const matcher = outputMatcher.lineMatcher; + const linesToCheck = typeof matcher === 'string' ? 1 : countNewLines(matcher); + const lines: string[] = []; + if (outputMatcher.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { - let wrappedLineStart = i; - const wrappedLineEnd = i; - while (wrappedLineStart >= startLine && buffer.getLine(wrappedLineStart)?.isWrapped) { - wrappedLineStart--; + lines.unshift(getXtermLineContent(buffer, i, i, cols)); + if (lines.length > linesToCheck) { + lines.pop(); } - i = wrappedLineStart; - line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); - const match = line.match(outputMatcher.lineMatcher); + const match = lines.join('\n').match(matcher); if (match) { return match; } } } else { - for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) { - const wrappedLineStart = i; - let wrappedLineEnd = i; - while (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) { - wrappedLineEnd++; + for (let i = startLine + (outputMatcher.offset || 0); i < endLine; i++) { + lines.push(getXtermLineContent(buffer, i, i, cols)); + if (lines.length === linesToCheck) { + lines.shift(); } - i = wrappedLineEnd; - line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); if (outputMatcher) { - const match = line.match(outputMatcher.lineMatcher); + const match = lines.join('\n').match(matcher); if (match) { return match; } @@ -709,3 +701,17 @@ function getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number } return content; } + +function countNewLines(regex: RegExp): number { + if (!regex.multiline) { + return 1; + } + const source = regex.source; + let count = 1; + let i = source.indexOf('\\n'); + while (i !== -1) { + count++; + i = source.indexOf('\\n', i + 1); + } + return count; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 9bb8e35938c..a7f3c931277 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -20,7 +20,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import { ITerminalQuickFix } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalOutputMatcher, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IMarker } from 'xterm'; @@ -933,29 +933,6 @@ export interface ITerminalQuickFixAction extends IAction { addNewLine?: boolean; } -/** - * A matcher that runs on a sub-section of a terminal command's output - */ -export interface ITerminalOutputMatcher { - /** - * A string or regex to match against the unwrapped line. - */ - lineMatcher: string | RegExp; - /** - * Which side of the output to anchor the {@link offset} and {@link length} against. - */ - anchor: 'top' | 'bottom'; - /** - * How far from either the top or the bottom of the butter to start matching against. - */ - offset: number; - /** - * The number of rows to match against, this should be as small as possible for performance - * reasons. - */ - length: number; -} - export interface IXtermTerminal { /** * An object that tracks when commands are run and enables navigating and selecting between diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 889776fb25a..f3d6241a16e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -12,7 +12,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.+/; -export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; +export const GitSimilarOutputRegex = /most similar command is\s*\n\s*([^\s]{3,})/m; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; // The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*", diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index c165c6cc43e..319de723435 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -96,11 +96,28 @@ export interface IShellLaunchConfigResolveOptions { allowAutomationShell?: boolean; } +/** + * A matcher that runs on a sub-section of a terminal command's output + */ export interface ITerminalOutputMatcher { + /** + * A string or regex to match against the unwrapped line. If this is a regex with the multiline + * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1. + */ lineMatcher: string | RegExp; - anchor?: 'top' | 'bottom'; - offset?: number; - length?: number; + /** + * Which side of the output to anchor the {@link offset} and {@link length} against. + */ + anchor: 'top' | 'bottom'; + /** + * How far from either the top or the bottom of the butter to start matching against. + */ + offset: number; + /** + * The number of rows to match against, this should be as small as possible for performance + * reasons. + */ + length: number; } export interface ITerminalBackend { diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 6de36f45a01..415a9d0663a 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -14,9 +14,10 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; -import { ITerminalQuickFixAction, ITerminalInstance, ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; +import { ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal } from 'xterm'; suite('QuickFixAddon', () => { From b16578ff6526793f81652cc31a9bd70dee1c4851 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 28 Sep 2022 16:15:45 -0700 Subject: [PATCH 189/599] Make sure we always reset the code action widget context when the widget is hidden (#162278) Make sure we always reset the `ctxMenuWidgetVisible` widget context when the widget is hidden We've seen a handful of reports of keybindings not working. I'm not able to repo this, but the root cause may be that code action's context keys are not being cleared properly This fixes it to make sure we always reset the context when the widget is closed --- src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts index 7c3180aa563..559128914f4 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts @@ -419,7 +419,6 @@ export class CodeActionWidget extends Disposable { } public hide() { - this._ctxMenuWidgetVisible.reset(); this.codeActionList.clear(); this._contextViewService.hideContextView(); } @@ -530,6 +529,7 @@ export class CodeActionWidget extends Disposable { }); this.currentShowingContext = undefined; + this._ctxMenuWidgetVisible.reset(); delegate.onHide(cancelled); } From a1a877b80b762c80c45b020179a0b8dc7cb4666c Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Wed, 28 Sep 2022 16:27:26 -0700 Subject: [PATCH 190/599] add to my-endgame (#162280) --- .vscode/notebooks/my-endgame.github-issues | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 4fb0550ed8d..19381c385ae 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -87,7 +87,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed -label:verification-steps-needed -label:unreleased" }, { "kind": 1, From 96dda01dafdf4badf360d8dcc3c7eaf448fae7f9 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 28 Sep 2022 17:34:22 -0700 Subject: [PATCH 191/599] Search Tree - file order changes when switching from list to tree (#162270) Fixes #162155 --- .../contrib/search/common/searchModel.ts | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index f071e78c421..4b7a435742c 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -928,12 +928,38 @@ export class FolderMatchNoRoot extends FolderMatch { * and their sort order is undefined. */ export function searchMatchComparer(elementA: RenderableMatch, elementB: RenderableMatch, sortOrder: SearchSortOrder = SearchSortOrder.Default): number { + + if (elementA instanceof FileMatch && elementB instanceof FolderMatch) { + return 1; + } + + if (elementB instanceof FileMatch && elementA instanceof FolderMatch) { + return -1; + } + if (elementA instanceof FolderMatch && elementB instanceof FolderMatch) { const elemAIndex = elementA.index(); const elemBIndex = elementB.index(); if (elemAIndex !== null && elemBIndex !== null) { return elemAIndex - elemBIndex; } + + switch (sortOrder) { + case SearchSortOrder.CountDescending: + return elementB.count() - elementA.count(); + case SearchSortOrder.CountAscending: + return elementA.count() - elementB.count(); + case SearchSortOrder.Type: + return compareFileExtensions(elementA.name(), elementB.name()); + case SearchSortOrder.FileNames: + return compareFileNames(elementA.name(), elementB.name()); + // Fall through otherwise + default: + if (!elementA.resource || !elementB.resource) { + return 0; + } + return comparePaths(elementA.resource.fsPath, elementB.resource.fsPath) || compareFileNames(elementA.name(), elementB.name()); + } } if (elementA instanceof FileMatch && elementB instanceof FileMatch) { @@ -947,12 +973,11 @@ export function searchMatchComparer(elementA: RenderableMatch, elementB: Rendera case SearchSortOrder.FileNames: return compareFileNames(elementA.name(), elementB.name()); case SearchSortOrder.Modified: { - if (!(elementA instanceof FolderMatch) || !(elementB instanceof FolderMatch)) { - const fileStatA = elementA.fileStat; - const fileStatB = elementB.fileStat; - if (fileStatA && fileStatB) { - return fileStatB.mtime - fileStatA.mtime; - } + const fileStatA = elementA.fileStat; + const fileStatB = elementB.fileStat; + if (fileStatA && fileStatB) { + return fileStatB.mtime - fileStatA.mtime; + } } // Fall through otherwise From d3e330e4dae798d13938b75263cef468bacb3319 Mon Sep 17 00:00:00 2001 From: Josh Abernathy Date: Thu, 29 Sep 2022 03:02:29 -0400 Subject: [PATCH 192/599] Update devcontainer schema for `customizations.codespaces.openFiles` (#161637) --- .../devContainer.codespaces.schema.json | 7 ++++ .../devContainer.schema.generated.json | 35 +++++++++++++++++++ .../schemas/devContainer.schema.src.json | 7 ++++ 3 files changed, 49 insertions(+) diff --git a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json index d224f919109..681ca6105cf 100644 --- a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json @@ -173,6 +173,13 @@ ] } } + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } } } diff --git a/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json index 4ae5033f3f1..14fdc3648b3 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -600,6 +600,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -1210,6 +1217,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -1786,6 +1800,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -2336,6 +2357,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false @@ -2851,6 +2879,13 @@ } }, "additionalProperties": false + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } }, "additionalProperties": false diff --git a/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json index 73456101bb9..e8bb724d8cb 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -501,6 +501,13 @@ ] } } + }, + "openFiles": { + "type": "array", + "description": "The paths to the files to open when the codespace is created. Paths are relative to the workspace.", + "items": { + "type": "string" + } } } } From 2c801254ebf547baaee771b99aa76d202f999622 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 29 Sep 2022 09:10:52 +0200 Subject: [PATCH 193/599] remove forgotten console.log (#162297) https://github.com/microsoft/vscode/issues/162295 --- src/vs/platform/profiling/electron-main/windowProfiling.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/platform/profiling/electron-main/windowProfiling.ts b/src/vs/platform/profiling/electron-main/windowProfiling.ts index 2b6971c3dd9..18549159fe4 100644 --- a/src/vs/platform/profiling/electron-main/windowProfiling.ts +++ b/src/vs/platform/profiling/electron-main/windowProfiling.ts @@ -254,8 +254,6 @@ export class WindowProfiler { callstack: callstack.join('\n') }; this._telemetryService.publicLog2('prof.freeze.sample', data); - - console.log(data); } } } From ea86537df2a54474b52cdecb118962b37e50df9f Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 26 Sep 2022 09:42:08 -0700 Subject: [PATCH 194/599] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eb76f98421e..0c7c6236c42 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,10 @@ VS Code includes a set of built-in extensions located in the [extensions](extens ## Development Container -This repository includes a Visual Studio Code Remote - Containers / GitHub Codespaces development container. +This repository includes a Visual Studio Code Dev Containers / GitHub Codespaces development container. -- For [Remote - Containers](https://aka.ms/vscode-remote/download/containers), use the **Remote-Containers: Clone Repository in Container Volume...** command which creates a Docker volume for better disk I/O on macOS and Windows. - - If you already have VS Code and Docker installed, you can also click [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. This will cause VS Code to automatically install the Remote - Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. +- For [Dev Containers](https://aka.ms/vscode-remote/download/containers), use the **Dev Containers: Clone Repository in Container Volume...** command which creates a Docker volume for better disk I/O on macOS and Windows. + - If you already have VS Code and Docker installed, you can also click [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. This will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. - For Codespaces, install the [GitHub Codespaces](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces) extension in VS Code, and use the **Codespaces: Create New Codespace** command. Docker / the Codespace should have at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. See the [development container README](.devcontainer/README.md) for more information. From f88fb9102e8f724c208ea97e7108a29935e58c36 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 26 Sep 2022 09:43:54 -0700 Subject: [PATCH 195/599] Update README.md --- .devcontainer/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 9050664fcee..7fd5854208c 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -1,6 +1,6 @@ # Code - OSS Development Container -[![Open in Remote - Containers](https://img.shields.io/static/v1?label=Remote%20-%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) This repository includes configuration for a development container for working with Code - OSS in a local container or using [GitHub Codespaces](https://github.com/features/codespaces). @@ -8,7 +8,7 @@ This repository includes configuration for a development container for working w ## Quick start - local -If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. Clicking these links will cause VS Code to automatically install the Remote - Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. +If you already have VS Code and Docker installed, you can click the badge above or [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/vscode) to get started. Clicking these links will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use. 1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.) @@ -16,13 +16,13 @@ If you already have VS Code and Docker installed, you can click the badge above > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar. -3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. +3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Dev Containers](https://aka.ms/vscode-remote/download/containers) extension. - ![Image of Remote - Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) + ![Image of Dev Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) - > **Note:** The Remote - Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. + > **Note:** The Dev Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. -4. Press Ctrl/Cmd + Shift + P or F1 and select **Remote-Containers: Clone Repository in Container Volume...**. +4. Press Ctrl/Cmd + Shift + P or F1 and select **Dev Containers: Clone Repository in Container Volume...**. > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or when using the Hyper-V engine on Windows. We recommend the "clone repository in container" approach instead since it uses "named volume" rather than the local filesystem. From 197bfd908820ffae39ebfe124434bc81e9ce0c54 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 29 Sep 2022 10:01:29 +0200 Subject: [PATCH 196/599] Git - Use modal dialog after cloning a repository (#162306) Use modal dialog after cloning a repository --- extensions/git/src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 1b002799be9..6591bf1bef3 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -599,7 +599,7 @@ export class CommandCenter { choices.push(addToWorkspace); } - const result = await window.showInformationMessage(message, ...choices); + const result = await window.showInformationMessage(message, { modal: true }, ...choices); action = result === open ? PostCloneAction.Open : result === openNewWindow ? PostCloneAction.OpenNewWindow From e05324c3e4a055313a3f5b8eb879f8e6ebc4848d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 29 Sep 2022 01:29:18 -0700 Subject: [PATCH 197/599] Swap auto scroll lock/unlock icons (#162264) Fixes #162263 --- .../workbench/contrib/output/browser/output.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 5e24f0af009..c067ceadfd7 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -166,10 +166,10 @@ registerAction2(class extends Action2 { group: 'navigation', order: 3, }, - icon: Codicon.unlock, + icon: Codicon.lock, toggled: { condition: CONTEXT_OUTPUT_SCROLL_LOCK, - icon: Codicon.lock, + icon: Codicon.unlock, tooltip: nls.localize('outputScrollOn', "Turn Auto Scrolling On") } }); From b784e0514d4608cc20a0e7ce62baf7bc8131158c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 29 Sep 2022 01:38:28 -0700 Subject: [PATCH 198/599] Revert "perf - log slow running workbench contribs (#159656)" (#162312) * Revert "perf - log slow running workbench contribs (#159656)" This reverts commit b7d5b65a13299083e92bca91be8fa1289e95d5c1. * stop logging slownes * still log perf but only running out of sources --- .../api/browser/extensionHost.contribution.ts | 2 +- .../api/browser/viewsExtensionPoint.ts | 2 +- .../browser/actions/textInputActions.ts | 2 +- .../parts/dialogs/dialog.web.contribution.ts | 2 +- .../parts/editor/editor.contribution.ts | 8 ++-- .../browser/workbench.contribution.ts | 2 +- src/vs/workbench/common/contributions.ts | 48 +++++++++---------- .../browser/audioCues.contribution.ts | 4 +- ...ketPairColorizer2Telemetry.contribution.ts | 2 +- .../browser/preview/bulkEdit.contribution.ts | 4 +- .../browser/codeActions.contribution.ts | 2 +- .../browser/outline/documentSymbolsOutline.ts | 2 +- .../codeEditor/browser/saveParticipants.ts | 2 +- .../browser/toggleMultiCursorModifier.ts | 2 +- .../codeEditor/browser/toggleWordWrap.ts | 2 +- .../displayChangeRemeasureFonts.ts | 2 +- .../electron-sandbox/selectionClipboard.ts | 2 +- .../sleepResumeRepaintMinimap.ts | 2 +- .../configurationExportHelper.contribution.ts | 2 +- .../browser/contextmenu.contribution.ts | 2 +- .../browser/customEditor.contribution.ts | 2 +- .../debug/browser/debug.contribution.ts | 16 +++---- ...eprecatedExtensionMigrator.contribution.ts | 2 +- .../browser/editSessions.contribution.ts | 2 +- .../browser/experiments.contribution.ts | 2 +- .../browser/extensions.contribution.ts | 22 ++++----- .../extensions.contribution.ts | 6 +-- .../browser/externalTerminal.contribution.ts | 2 +- .../externalTerminal.contribution.ts | 2 +- .../feedback/browser/feedback.contribution.ts | 2 +- .../files/browser/files.contribution.ts | 14 +++--- .../format/browser/formatActionsMultiple.ts | 1 - .../browser/interactive.contribution.ts | 4 +- .../issue/browser/issue.web.contribution.ts | 2 +- .../browser/languageDetection.contribution.ts | 2 +- .../browser/languageStatus.contribution.ts | 2 +- .../contrib/list/browser/list.contribution.ts | 2 +- .../browser/localHistory.contribution.ts | 2 +- .../localization.contribution.ts | 2 +- .../contrib/logs/browser/logs.contribution.ts | 2 +- .../contrib/logs/common/logs.contribution.ts | 2 +- .../electron-sandbox/logs.contribution.ts | 2 +- .../markers/browser/markers.contribution.ts | 4 +- .../markers/browser/markersFileDecorations.ts | 2 +- .../browser/mergeEditor.contribution.ts | 4 +- .../breakpoints/notebookBreakpoints.ts | 4 +- .../cellStatusBar/statusBarProviders.ts | 2 +- .../contrib/clipboard/notebookClipboard.ts | 2 +- .../editorStatusBar/editorStatusBar.ts | 4 +- .../gettingStarted/notebookGettingStarted.ts | 2 +- .../browser/contrib/marker/markerProvider.ts | 2 +- .../contrib/outline/notebookOutline.ts | 2 +- .../contrib/profile/notebookProfile.ts | 2 +- .../contrib/undoRedo/notebookUndoRedo.ts | 2 +- .../notebook/browser/notebook.contribution.ts | 16 +++---- .../offline/browser/offline.contribution.ts | 2 +- .../output/browser/output.contribution.ts | 2 +- .../browser/performance.contribution.ts | 1 - .../browser/performance.web.contribution.ts | 1 - .../performance.contribution.ts | 3 -- .../browser/keyboardLayoutPicker.ts | 2 +- .../browser/preferences.contribution.ts | 4 +- .../browser/relauncher.contribution.ts | 4 +- .../remote/browser/remote.contribution.ts | 16 +++---- .../remote/common/remote.contribution.ts | 10 ++-- .../electron-sandbox/remote.contribution.ts | 10 ++-- .../contrib/sash/browser/sash.contribution.ts | 2 +- .../contrib/scm/browser/scm.contribution.ts | 6 +-- .../search/browser/replaceContributions.ts | 2 +- .../search/browser/search.contribution.ts | 2 +- .../browser/searchEditor.contribution.ts | 4 +- .../snippets/browser/snippets.contribution.ts | 2 +- .../splash/browser/splash.contribution.ts | 1 - .../electron-sandbox/splash.contribution.ts | 1 - .../surveys/browser/ces.contribution.ts | 2 +- .../browser/languageSurveys.contribution.ts | 2 +- .../surveys/browser/nps.contribution.ts | 2 +- .../electron-sandbox/tags.contribution.ts | 2 +- .../tasks/browser/task.contribution.ts | 4 +- .../browser/telemetry.contribution.ts | 2 +- .../terminal/browser/terminal.contribution.ts | 4 +- .../electron-sandbox/terminal.contribution.ts | 4 +- .../testing/browser/testing.contribution.ts | 6 +-- .../update/browser/update.contribution.ts | 6 +-- .../contrib/url/browser/url.contribution.ts | 3 -- .../browser/userDataProfile.contribution.ts | 2 +- .../browser/userDataSync.contribution.ts | 6 +-- .../userDataSync.contribution.ts | 2 +- .../contrib/watermark/browser/watermark.ts | 2 +- .../browser/webviewPanel.contribution.ts | 2 +- .../browser/welcomeBanner.contribution.ts | 2 +- .../browser/gettingStarted.contribution.ts | 4 +- .../common/newFile.contribution.ts | 2 +- .../common/viewsWelcome.contribution.ts | 2 +- .../browser/walkThrough.contribution.ts | 2 +- .../browser/workspace.contribution.ts | 8 ++-- .../browser/workspaces.contribution.ts | 2 +- .../parts/dialogs/dialog.contribution.ts | 2 +- .../electron-sandbox/accessibilityService.ts | 2 +- .../browser/configurationService.ts | 6 +-- .../browser/extensionBisect.ts | 1 - .../extensions/browser/extensionUrlHandler.ts | 2 +- .../services/label/common/labelService.ts | 2 +- .../remote/browser/remoteAgentService.ts | 2 +- .../electron-sandbox/remoteAgentService.ts | 2 +- .../services/userData/browser/userDataInit.ts | 2 +- .../browser/workingCopyBackupService.ts | 2 +- .../common/workingCopyHistoryService.ts | 2 +- .../workingCopyBackupService.ts | 2 +- 109 files changed, 198 insertions(+), 216 deletions(-) diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index 203f680485c..38a27b2cea4 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -90,4 +90,4 @@ export class ExtensionPoints implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, 'ExtensionPoints', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, LifecyclePhase.Starting); diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 92b4f91954d..87e69afc783 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -642,4 +642,4 @@ class ViewsExtensionHandler implements IWorkbenchContribution { } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ViewsExtensionHandler, 'ViewsExtensionHandler', LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(ViewsExtensionHandler, LifecyclePhase.Starting); diff --git a/src/vs/workbench/browser/actions/textInputActions.ts b/src/vs/workbench/browser/actions/textInputActions.ts index 993f595d69e..60dad795312 100644 --- a/src/vs/workbench/browser/actions/textInputActions.ts +++ b/src/vs/workbench/browser/actions/textInputActions.ts @@ -99,4 +99,4 @@ export class TextInputActionsProvider extends Disposable implements IWorkbenchCo } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextInputActionsProvider, 'TextInputActionsProvider', LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextInputActionsProvider, LifecyclePhase.Ready); diff --git a/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts b/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts index 2781c45869f..4fa42a97578 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts @@ -75,4 +75,4 @@ export class DialogHandlerContribution extends Disposable implements IWorkbenchC } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, 'DialogHandlerContribution', LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, LifecyclePhase.Starting); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 8651d5bfbe2..919b490fd88 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -122,10 +122,10 @@ Registry.as(EditorExtensions.EditorFactory).registerEdit //#region Workbench Contributions -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, 'EditorAutoSave', LifecyclePhase.Ready); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, 'EditorStatus', LifecyclePhase.Ready); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledTextEditorWorkingCopyEditorHandler, 'UntitledTextEditorWorkingCopyEditorHandler', LifecyclePhase.Ready); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DynamicEditorConfigurations, 'DynamicEditorConfigurations', LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledTextEditorWorkingCopyEditorHandler, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DynamicEditorConfigurations, LifecyclePhase.Ready); registerEditorContribution(FloatingClickMenu.ID, FloatingClickMenu); diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 4ebd6498e72..9ebe6ca8ed7 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -18,7 +18,7 @@ const registry = Registry.as(ConfigurationExtensions.Con (function registerConfiguration(): void { // Migration support - Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ConfigurationMigrationWorkbenchContribution, 'ConfigurationMigrationWorkbenchContribution', LifecyclePhase.Eventually); + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ConfigurationMigrationWorkbenchContribution, LifecyclePhase.Eventually); // Workbench registry.registerConfiguration({ diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index afa24265570..592f64c9f89 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { runWhenIdle, IdleDeadline } from 'vs/base/common/async'; import { mark } from 'vs/base/common/performance'; import { ILogService } from 'vs/platform/log/common/log'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; /** * A workbench contribution that will be loaded when the workbench starts and disposed when the workbench shuts down. @@ -23,21 +24,15 @@ export namespace Extensions { type IWorkbenchContributionSignature = new (...services: Service) => IWorkbenchContribution; -interface IWorkbenchContributionRegistration { - readonly id: string; - readonly ctor: IConstructorSignature; -} - export interface IWorkbenchContributionsRegistry { /** * Registers a workbench contribution to the platform that will be loaded when the workbench starts and disposed when * the workbench shuts down. * - * @param id the identifier of the contribution. * @param phase the lifecycle phase when to instantiate the contribution. */ - registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, id: string, phase: LifecyclePhase): void; + registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void; /** * Starts the registry by providing the required services. @@ -50,15 +45,15 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry private instantiationService: IInstantiationService | undefined; private lifecycleService: ILifecycleService | undefined; private logService: ILogService | undefined; + private environmentService: IEnvironmentService | undefined; - private readonly toBeInstantiated = new Map(); + private readonly toBeInstantiated = new Map[]>(); - registerWorkbenchContribution(ctor: IConstructorSignature, id: string, phase: LifecyclePhase = LifecyclePhase.Starting): void { - const contribution = { id, ctor }; + registerWorkbenchContribution(ctor: IConstructorSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void { // Instantiate directly if we are already matching the provided phase - if (this.instantiationService && this.lifecycleService && this.logService && this.lifecycleService.phase >= phase) { - this.safeCreateInstance(this.instantiationService, this.logService, contribution, phase); + if (this.instantiationService && this.lifecycleService && this.logService && this.environmentService && this.lifecycleService.phase >= phase) { + this.safeCreateInstance(this.instantiationService, this.logService, this.environmentService, ctor, phase); } // Otherwise keep contributions by lifecycle phase @@ -69,7 +64,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry this.toBeInstantiated.set(phase, toBeInstantiated); } - toBeInstantiated.push(contribution); + toBeInstantiated.push(ctor as IConstructorSignature); } } @@ -77,26 +72,27 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry const instantiationService = this.instantiationService = accessor.get(IInstantiationService); const lifecycleService = this.lifecycleService = accessor.get(ILifecycleService); const logService = this.logService = accessor.get(ILogService); + const environmentService = this.environmentService = accessor.get(IEnvironmentService); for (const phase of [LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually]) { - this.instantiateByPhase(instantiationService, lifecycleService, logService, phase); + this.instantiateByPhase(instantiationService, lifecycleService, logService, environmentService, phase); } } - private instantiateByPhase(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, logService: ILogService, phase: LifecyclePhase): void { + private instantiateByPhase(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, logService: ILogService, environmentService: IEnvironmentService, phase: LifecyclePhase): void { // Instantiate contributions directly when phase is already reached if (lifecycleService.phase >= phase) { - this.doInstantiateByPhase(instantiationService, logService, phase); + this.doInstantiateByPhase(instantiationService, logService, environmentService, phase); } // Otherwise wait for phase to be reached else { - lifecycleService.when(phase).then(() => this.doInstantiateByPhase(instantiationService, logService, phase)); + lifecycleService.when(phase).then(() => this.doInstantiateByPhase(instantiationService, logService, environmentService, phase)); } } - private doInstantiateByPhase(instantiationService: IInstantiationService, logService: ILogService, phase: LifecyclePhase): void { + private doInstantiateByPhase(instantiationService: IInstantiationService, logService: ILogService, environmentService: IEnvironmentService, phase: LifecyclePhase): void { const toBeInstantiated = this.toBeInstantiated.get(phase); if (toBeInstantiated) { this.toBeInstantiated.delete(phase); @@ -108,7 +104,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry mark(`code/willCreateWorkbenchContributions/${phase}`); for (const ctor of toBeInstantiated) { - this.safeCreateInstance(instantiationService, logService, ctor, phase); // catch error so that other contributions are still considered + this.safeCreateInstance(instantiationService, logService, environmentService, ctor, phase); // catch error so that other contributions are still considered } mark(`code/didCreateWorkbenchContributions/${phase}`); @@ -123,7 +119,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry const instantiateSome = (idle: IdleDeadline) => { while (i < toBeInstantiated.length) { const ctor = toBeInstantiated[i++]; - this.safeCreateInstance(instantiationService, logService, ctor, phase); // catch error so that other contributions are still considered + this.safeCreateInstance(instantiationService, logService, environmentService, ctor, phase); // catch error so that other contributions are still considered if (idle.timeRemaining() < 1) { // time is up -> reschedule runWhenIdle(instantiateSome, forcedTimeout); @@ -136,19 +132,19 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry } } - private safeCreateInstance(instantiationService: IInstantiationService, logService: ILogService, contribution: IWorkbenchContributionRegistration, phase: LifecyclePhase): void { + private safeCreateInstance(instantiationService: IInstantiationService, logService: ILogService, environmentService: IEnvironmentService, ctor: IConstructorSignature, phase: LifecyclePhase): void { const now: number | undefined = phase < LifecyclePhase.Restored ? Date.now() : undefined; try { - instantiationService.createInstance(contribution.ctor); + instantiationService.createInstance(ctor); } catch (error) { - logService.error(`Unable to instantiate workbench contribution ${contribution.id}.`, error); + logService.error(`Unable to instantiate workbench contribution ${ctor.name}.`, error); } - if (typeof now === 'number') { + if (typeof now === 'number' && !environmentService.isBuilt /* only log out of sources where we have good ctor names */) { const time = Date.now() - now; - if (time > 5) { - logService.warn(`Workbench contribution ${contribution.id} blocked restore phase by ${time}ms.`); + if (time > 20) { + logService.warn(`Workbench contribution ${ctor.name} blocked restore phase by ${time}ms.`); } } } diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 061845f3af8..8626ff1630e 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -17,8 +17,8 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle registerSingleton(IAudioCueService, AudioCueService, false); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineFeatureContribution, 'AudioCueLineFeatureContribution', LifecyclePhase.Restored); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineDebuggerContribution, 'AudioCueLineDebuggerContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineFeatureContribution, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineDebuggerContribution, LifecyclePhase.Restored); const audioCueFeatureBase: IConfigurationPropertySchema = { 'type': 'string', diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts index af4f63a1d65..c1051e9d4cf 100644 --- a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -51,5 +51,5 @@ class BracketPairColorizer2TelemetryContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BracketPairColorizer2TelemetryContribution, 'BracketPairColorizer2TelemetryContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BracketPairColorizer2TelemetryContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts index 19164716538..4d51be59e2f 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts @@ -323,9 +323,7 @@ registerAction2(class ToggleGrouping extends Action2 { }); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( - BulkEditPreviewContribution, - 'BulkEditPreviewContribution', - LifecyclePhase.Ready + BulkEditPreviewContribution, LifecyclePhase.Ready ); const refactorPreviewViewIcon = registerIcon('refactor-preview-view-icon', Codicon.lightbulb, localize('refactorPreviewViewIcon', 'View icon of the refactor preview view.')); diff --git a/src/vs/workbench/contrib/codeActions/browser/codeActions.contribution.ts b/src/vs/workbench/contrib/codeActions/browser/codeActions.contribution.ts index f3d4de633ba..afcf9915643 100644 --- a/src/vs/workbench/contrib/codeActions/browser/codeActions.contribution.ts +++ b/src/vs/workbench/contrib/codeActions/browser/codeActions.contribution.ts @@ -30,4 +30,4 @@ class WorkbenchConfigurationContribution { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WorkbenchConfigurationContribution, 'WorkbenchConfigurationContribution', LifecyclePhase.Eventually); + .registerWorkbenchContribution(WorkbenchConfigurationContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index 3cbf02252d0..5f44dc67e26 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -432,4 +432,4 @@ class DocumentSymbolsOutlineCreator implements IOutlineCreator(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DocumentSymbolsOutlineCreator, 'DocumentSymbolsOutlineCreator', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DocumentSymbolsOutlineCreator, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts index 2049f12a728..4b966ec9bd1 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts @@ -402,4 +402,4 @@ export class SaveParticipantsContribution extends Disposable implements IWorkben } const workbenchContributionsRegistry = Registry.as(WorkbenchContributionsExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(SaveParticipantsContribution, 'SaveParticipantsContribution', LifecyclePhase.Restored); +workbenchContributionsRegistry.registerWorkbenchContribution(SaveParticipantsContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts index 58424f5f37c..fea60d0515a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts @@ -64,7 +64,7 @@ class MultiCursorModifierContextKeyController implements IWorkbenchContribution } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MultiCursorModifierContextKeyController, 'MultiCursorModifierContextKeyController', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MultiCursorModifierContextKeyController, LifecyclePhase.Restored); registerAction2(ToggleMultiCursorModifierAction); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 947a3d1cfb4..56e5219cb2b 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -269,7 +269,7 @@ class EditorWordWrapContextKeyTracker implements IWorkbenchContribution { } const workbenchRegistry = Registry.as(Extensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(EditorWordWrapContextKeyTracker, 'EditorWordWrapContextKeyTracker', LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(EditorWordWrapContextKeyTracker, LifecyclePhase.Ready); registerEditorContribution(ToggleWordWrapController.ID, ToggleWordWrapController); diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts index 4a2368a13a1..4d53ac15383 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts @@ -23,4 +23,4 @@ class DisplayChangeRemeasureFonts extends Disposable implements IWorkbenchContri } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DisplayChangeRemeasureFonts, 'DisplayChangeRemeasureFonts', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DisplayChangeRemeasureFonts, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts index 2801c0cb4c0..b0c66b9acb9 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts @@ -135,7 +135,7 @@ class PasteSelectionClipboardAction extends EditorAction { } registerEditorContribution(SelectionClipboardContributionID, SelectionClipboard); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SelectionClipboardPastePreventer, 'SelectionClipboardPastePreventer', LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SelectionClipboardPastePreventer, LifecyclePhase.Ready); if (platform.isLinux) { registerEditorAction(PasteSelectionClipboardAction); } diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts index 78219ebf9ef..f0e5225baa5 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts @@ -24,4 +24,4 @@ class SleepResumeRepaintMinimap extends Disposable implements IWorkbenchContribu } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SleepResumeRepaintMinimap, 'SleepResumeRepaintMinimap', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SleepResumeRepaintMinimap, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts b/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts index 9a0c2be015a..127283add02 100644 --- a/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts +++ b/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts @@ -23,4 +23,4 @@ export class ExtensionPoints implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, 'ExtensionPoints', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/contextmenu/browser/contextmenu.contribution.ts b/src/vs/workbench/contrib/contextmenu/browser/contextmenu.contribution.ts index 79cf442038e..ee27b0aefa9 100644 --- a/src/vs/workbench/contrib/contextmenu/browser/contextmenu.contribution.ts +++ b/src/vs/workbench/contrib/contextmenu/browser/contextmenu.contribution.ts @@ -25,4 +25,4 @@ class ContextMenuContribution implements IWorkbenchContribution { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(ContextMenuContribution, 'ContextMenuContribution', LifecyclePhase.Eventually); + .registerWorkbenchContribution(ContextMenuContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts index a79139a3b19..f8673805e33 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts @@ -34,4 +34,4 @@ Registry.as(EditorExtensions.EditorFactory) CustomEditorInputSerializer); Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(ComplexCustomWorkingCopyEditorHandler, 'ComplexCustomWorkingCopyEditorHandler', LifecyclePhase.Starting); + .registerWorkbenchContribution(ComplexCustomWorkingCopyEditorHandler, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 54a69d7be0b..d065ee2c811 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -64,16 +64,16 @@ registerColors(); registerSingleton(IDebugService, DebugService, true); // Register Debug Workbench Contributions -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugStatusContribution, 'DebugStatusContribution', LifecyclePhase.Eventually); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugProgressContribution, 'DebugProgressContribution', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugStatusContribution, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugProgressContribution, LifecyclePhase.Eventually); if (isWeb) { - Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugTitleContribution, 'DebugTitleContribution', LifecyclePhase.Eventually); + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugTitleContribution, LifecyclePhase.Eventually); } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, 'DebugToolBar', LifecyclePhase.Restored); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, 'DebugContentProvider', LifecyclePhase.Eventually); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, 'StatusBarColorProvider', LifecyclePhase.Eventually); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DisassemblyViewContribution, 'DisassemblyViewContribution', LifecyclePhase.Eventually); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugLifecycle, 'DebugLifecycle', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DisassemblyViewContribution, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugLifecycle, LifecyclePhase.Eventually); // Register Quick Access Registry.as(QuickAccessExtensions.Quickaccess).registerQuickAccessProvider({ diff --git a/src/vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution.ts b/src/vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution.ts index 2a91d82f0d8..3abb2f55315 100644 --- a/src/vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution.ts +++ b/src/vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution.ts @@ -100,4 +100,4 @@ interface State { }[]; } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DeprecatedExtensionMigratorContribution, 'DeprecatedExtensionMigratorContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DeprecatedExtensionMigratorContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index fb5487270ba..15bc2773b6a 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -800,7 +800,7 @@ const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(EditSessionsContribution, 'EditSessionsContribution', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(EditSessionsContribution, LifecyclePhase.Restored); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ ...workbenchConfigurationNodeBase, diff --git a/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts b/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts index 2dc9b0f9303..825e120e8e9 100644 --- a/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts +++ b/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts @@ -15,7 +15,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio registerSingleton(IExperimentService, ExperimentService, true); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExperimentalPrompts, 'ExperimentalPrompts', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExperimentalPrompts, LifecyclePhase.Eventually); const registry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index ebac501e17b..e356f6f316b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -1588,18 +1588,18 @@ class ExtensionStorageCleaner implements IWorkbenchContribution { } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, 'ExtensionsContributions', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(StatusUpdater, 'StatusUpdater', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, 'MaliciousExtensionChecker', LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, 'KeymapExtensions', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, 'ExtensionsViewletViewsContribution', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, 'ExtensionActivationProgress', LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, 'ExtensionDependencyChecker', LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrustTransitionParticipant, 'ExtensionEnablementWorkspaceTrustTransitionParticipant', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, 'ExtensionsCompletionItemsProvider', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(UnsupportedExtensionsMigrationContrib, 'UnsupportedExtensionsMigrationContrib', LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrustTransitionParticipant, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(UnsupportedExtensionsMigrationContrib, LifecyclePhase.Eventually); if (isWeb) { - workbenchRegistry.registerWorkbenchContribution(ExtensionStorageCleaner, 'ExtensionStorageCleaner', LifecyclePhase.Eventually); + workbenchRegistry.registerWorkbenchContribution(ExtensionStorageCleaner, LifecyclePhase.Eventually); } diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts index 4af6ab2713f..4a10f305828 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts @@ -67,9 +67,9 @@ class ExtensionsContributions implements IWorkbenchContribution { } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, 'ExtensionsContributions', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, 'ExtensionsAutoProfiler', LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(RemoteExtensionsInitializerContribution, 'RemoteExtensionsInitializerContribution', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(RemoteExtensionsInitializerContribution, LifecyclePhase.Restored); // Register Commands CommandsRegistry.registerCommand(DebugExtensionHostAction.ID, (accessor: ServicesAccessor) => { diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index fdb07a0941f..b1cdf5d227a 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -136,4 +136,4 @@ export class ExternalTerminalContribution extends Disposable implements IWorkben } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExternalTerminalContribution, 'ExternalTerminalContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExternalTerminalContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts index e0759e2b781..e910ea0b127 100644 --- a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts @@ -135,4 +135,4 @@ export class ExternalTerminalContribution implements IWorkbenchContribution { // Register workbench contributions const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ExternalTerminalContribution, 'ExternalTerminalContribution', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExternalTerminalContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts b/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts index 238e4095817..94485ad4969 100644 --- a/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts @@ -8,4 +8,4 @@ import { FeedbackStatusbarConribution } from 'vs/workbench/contrib/feedback/brow import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FeedbackStatusbarConribution, 'FeedbackStatusbarConribution', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FeedbackStatusbarConribution, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 062fb218400..b6ab06c8e97 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -83,25 +83,25 @@ Registry.as(EditorExtensions.EditorFactory).registerFile // Register Editor Input Serializer & Handler Registry.as(EditorExtensions.EditorFactory).registerEditorSerializer(FILE_EDITOR_INPUT_ID, FileEditorInputSerializer); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileEditorWorkingCopyEditorHandler, 'FileEditorWorkingCopyEditorHandler', LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileEditorWorkingCopyEditorHandler, LifecyclePhase.Ready); // Register Explorer views -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExplorerViewletViewsContribution, 'ExplorerViewletViewsContribution', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExplorerViewletViewsContribution, LifecyclePhase.Starting); // Register Text File Editor Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextFileEditorTracker, 'TextFileEditorTracker', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextFileEditorTracker, LifecyclePhase.Starting); // Register Text File Save Error Handler -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextFileSaveErrorHandler, 'TextFileSaveErrorHandler', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextFileSaveErrorHandler, LifecyclePhase.Starting); // Register uri display for file uris -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriLabelContribution, 'FileUriLabelContribution', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriLabelContribution, LifecyclePhase.Starting); // Register Workspace Watcher -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, 'WorkspaceWatcher', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored); // Register Dirty Files Indicator -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesIndicator, 'DirtyFilesIndicator', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesIndicator, LifecyclePhase.Starting); // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index e76a5bfc3b2..71c8d537e30 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -241,7 +241,6 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( DefaultFormatter, - 'DefaultFormatter', LifecyclePhase.Restored ); diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 0e31c344e68..89839abf905 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -268,8 +268,8 @@ class InteractiveInputContentProvider implements ITextModelContentProvider { const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(InteractiveDocumentContribution, 'InteractiveDocumentContribution', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(InteractiveInputContentProvider, 'InteractiveInputContentProvider', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(InteractiveDocumentContribution, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(InteractiveInputContentProvider, LifecyclePhase.Ready); export class InteractiveEditorSerializer implements IEditorSerializer { public static readonly ID = InteractiveEditorInput.ID; diff --git a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts index c3822e6c68c..61a4bd29e40 100644 --- a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts @@ -100,7 +100,7 @@ class RegisterIssueContribution implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterIssueContribution, 'RegisterIssueContribution', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterIssueContribution, LifecyclePhase.Starting); CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { return nls.localize('statusUnsupported', "The --status argument is not yet supported in browsers."); diff --git a/src/vs/workbench/contrib/languageDetection/browser/languageDetection.contribution.ts b/src/vs/workbench/contrib/languageDetection/browser/languageDetection.contribution.ts index d5605600b90..363f76cb570 100644 --- a/src/vs/workbench/contrib/languageDetection/browser/languageDetection.contribution.ts +++ b/src/vs/workbench/contrib/languageDetection/browser/languageDetection.contribution.ts @@ -115,7 +115,7 @@ class LanguageDetectionStatusContribution implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LanguageDetectionStatusContribution, 'LanguageDetectionStatusContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LanguageDetectionStatusContribution, LifecyclePhase.Restored); registerAction2(class extends Action2 { diff --git a/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts b/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts index f1661dcd48e..63b120d3b3c 100644 --- a/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts +++ b/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts @@ -391,7 +391,7 @@ class EditorStatusContribution implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatusContribution, 'EditorStatusContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatusContribution, LifecyclePhase.Restored); registerAction2(class extends Action2 { diff --git a/src/vs/workbench/contrib/list/browser/list.contribution.ts b/src/vs/workbench/contrib/list/browser/list.contribution.ts index a8593efd37b..a2347a33886 100644 --- a/src/vs/workbench/contrib/list/browser/list.contribution.ts +++ b/src/vs/workbench/contrib/list/browser/list.contribution.ts @@ -20,4 +20,4 @@ export class ListContext implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ListContext, 'ListContext', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ListContext, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/localHistory/browser/localHistory.contribution.ts b/src/vs/workbench/contrib/localHistory/browser/localHistory.contribution.ts index 44e11d4afa6..dda52a6f3a5 100644 --- a/src/vs/workbench/contrib/localHistory/browser/localHistory.contribution.ts +++ b/src/vs/workbench/contrib/localHistory/browser/localHistory.contribution.ts @@ -10,4 +10,4 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { LocalHistoryTimeline } from 'vs/workbench/contrib/localHistory/browser/localHistoryTimeline'; // Register Local History Timeline -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LocalHistoryTimeline, 'LocalHistoryTimeline', LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LocalHistoryTimeline, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts index 3adcf5734b8..e23d92dddcc 100644 --- a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts +++ b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts @@ -220,7 +220,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(LocalizationWorkbenchContribution, 'LocalizationWorkbenchContribution', LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(LocalizationWorkbenchContribution, LifecyclePhase.Eventually); ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'localizations', diff --git a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts index 91600e0b61d..d78954e856e 100644 --- a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts @@ -31,4 +31,4 @@ class WebLogOutputChannels extends Disposable implements IWorkbenchContribution } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WebLogOutputChannels, 'WebLogOutputChannels', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WebLogOutputChannels, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index d4e9518e352..636c211ffcd 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -80,4 +80,4 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, 'LogOutputChannels', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts index 5032ac87a6b..022c66402f2 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts @@ -42,7 +42,7 @@ class NativeLogOutputChannels extends Disposable implements IWorkbenchContributi } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeLogOutputChannels, 'NativeLogOutputChannels', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeLogOutputChannels, LifecyclePhase.Restored); const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLogsFolderAction), 'Developer: Open Logs Folder', CATEGORIES.Developer.value); diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 58105365186..3512616b8b8 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -514,7 +514,7 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont } } -workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, 'MarkersStatusBarContributions', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); class ActivityUpdater extends Disposable implements IWorkbenchContribution { @@ -537,4 +537,4 @@ class ActivityUpdater extends Disposable implements IWorkbenchContribution { } } -workbenchRegistry.registerWorkbenchContribution(ActivityUpdater, 'ActivityUpdater', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ActivityUpdater, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts b/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts index 88b5c1a57fd..8ca2e6bce00 100644 --- a/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts @@ -107,4 +107,4 @@ Registry.as(ConfigurationExtensions.Configuration).regis // register file decorations Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(MarkersFileDecorations, 'MarkersFileDecorations', LifecyclePhase.Restored); + .registerWorkbenchContribution(MarkersFileDecorations, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index b168f302520..ed17e054277 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -81,11 +81,11 @@ registerAction2(MergeEditorLoadContentsFromFolder); Registry .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(MergeEditorOpenHandlerContribution, 'MergeEditorOpenHandlerContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(MergeEditorOpenHandlerContribution, LifecyclePhase.Restored); Registry .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(MergeEditorResolverContribution, 'MergeEditorResolverContribution', LifecyclePhase.Starting); + .registerWorkbenchContribution(MergeEditorResolverContribution, LifecyclePhase.Starting); /* class MergeEditorWorkbenchContribution extends Disposable implements IWorkbenchContribution { constructor(@IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService) { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts b/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts index dab66bf78fe..908b48c6295 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts @@ -129,7 +129,7 @@ class NotebookBreakpoints extends Disposable implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookBreakpoints, 'NotebookBreakpoints', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookBreakpoints, LifecyclePhase.Restored); class NotebookCellPausing extends Disposable implements IWorkbenchContribution { private readonly _pausedCells = new Set(); @@ -196,4 +196,4 @@ class NotebookCellPausing extends Disposable implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookCellPausing, 'NotebookCellPausing', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookCellPausing, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/statusBarProviders.ts b/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/statusBarProviders.ts index a7f9f6bb958..ee2b1fdfa22 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/statusBarProviders.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/statusBarProviders.ts @@ -155,4 +155,4 @@ class BuiltinCellStatusBarProviders extends Disposable { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BuiltinCellStatusBarProviders, 'BuiltinCellStatusBarProviders', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BuiltinCellStatusBarProviders, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts index 71403cf4fde..712c2369044 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts @@ -400,7 +400,7 @@ export class NotebookClipboardContribution extends Disposable { } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookClipboardContribution, 'NotebookClipboardContribution', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookClipboardContribution, LifecyclePhase.Ready); const COPY_CELL_COMMAND_ID = 'notebook.cell.copy'; const CUT_CELL_COMMAND_ID = 'notebook.cell.cut'; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts index ad13e9be7a0..d3d04163713 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts @@ -517,7 +517,7 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(KernelStatus, 'KernelStatus', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(KernelStatus, LifecyclePhase.Restored); export class ActiveCellStatus extends Disposable implements IWorkbenchContribution { @@ -593,4 +593,4 @@ export class ActiveCellStatus extends Disposable implements IWorkbenchContributi } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ActiveCellStatus, 'ActiveCellStatus', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ActiveCellStatus, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts index 9bcf8daff2e..2165fa94cc2 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts @@ -75,7 +75,7 @@ export class NotebookGettingStarted extends Disposable implements IWorkbenchCont } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookGettingStarted, 'NotebookGettingStarted', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookGettingStarted, LifecyclePhase.Restored); registerAction2(class NotebookClearNotebookLayoutAction extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts b/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts index f7c3f252abd..13315c8ab5d 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts @@ -46,4 +46,4 @@ class MarkerListProvider implements IMarkerListProvider { Registry .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(MarkerListProvider, 'MarkerListProvider', LifecyclePhase.Ready); + .registerWorkbenchContribution(MarkerListProvider, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index 7c189a4b3dc..1103b138b84 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -648,7 +648,7 @@ class NotebookOutlineCreator implements IOutlineCreator(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookOutlineCreator, 'NotebookOutlineCreator', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookOutlineCreator, LifecyclePhase.Eventually); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts index 5848a745b90..42089a40651 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts @@ -125,5 +125,5 @@ export class NotebookProfileContribution extends Disposable { } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookProfileContribution, 'NotebookProfileContribution', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookProfileContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts index ee32a2865c5..22678c6af01 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts @@ -65,4 +65,4 @@ class NotebookUndoRedoContribution extends Disposable { } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookUndoRedoContribution, 'NotebookUndoRedoContribution', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookUndoRedoContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 489c3a3670d..67c3e64ecbe 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -688,14 +688,14 @@ class NotebookLanguageSelectorScoreRefine { } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, 'NotebookContribution', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, 'CellContentProvider', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(CellInfoContentProvider, 'CellInfoContentProvider', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasContribution, 'RegisterSchemasContribution', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManager, 'NotebookEditorManager', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSelectorScoreRefine, 'NotebookLanguageSelectorScoreRefine', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, 'SimpleNotebookWorkingCopyEditorHandler', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(ComplexNotebookWorkingCopyEditorHandler, 'ComplexNotebookWorkingCopyEditorHandler', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(CellInfoContentProvider, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasContribution, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManager, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSelectorScoreRefine, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(ComplexNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); registerSingleton(INotebookService, NotebookService, false); registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, false); diff --git a/src/vs/workbench/contrib/offline/browser/offline.contribution.ts b/src/vs/workbench/contrib/offline/browser/offline.contribution.ts index 470eaf250e3..75b1671e327 100644 --- a/src/vs/workbench/contrib/offline/browser/offline.contribution.ts +++ b/src/vs/workbench/contrib/offline/browser/offline.contribution.ts @@ -94,4 +94,4 @@ export class OfflineStatusBarController implements IWorkbenchContribution { } Registry.as(Extensions.Workbench) - .registerWorkbenchContribution(OfflineStatusBarController, 'OfflineStatusBarController', LifecyclePhase.Restored); + .registerWorkbenchContribution(OfflineStatusBarController, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index c067ceadfd7..090aff78b69 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -102,7 +102,7 @@ class OutputContribution implements IWorkbenchContribution { } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(OutputContribution, 'OutputContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(OutputContribution, LifecyclePhase.Restored); registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/performance/browser/performance.contribution.ts b/src/vs/workbench/contrib/performance/browser/performance.contribution.ts index ac2fe448888..de72a95db03 100644 --- a/src/vs/workbench/contrib/performance/browser/performance.contribution.ts +++ b/src/vs/workbench/contrib/performance/browser/performance.contribution.ts @@ -20,7 +20,6 @@ import { EventProfiling } from 'vs/base/common/event'; Registry.as(Extensions.Workbench).registerWorkbenchContribution( PerfviewContrib, - 'PerfviewContrib', LifecyclePhase.Ready ); diff --git a/src/vs/workbench/contrib/performance/browser/performance.web.contribution.ts b/src/vs/workbench/contrib/performance/browser/performance.web.contribution.ts index 25e76c1f35a..566cf8af723 100644 --- a/src/vs/workbench/contrib/performance/browser/performance.web.contribution.ts +++ b/src/vs/workbench/contrib/performance/browser/performance.web.contribution.ts @@ -30,6 +30,5 @@ class ResourcePerformanceMarks { Registry.as(Extensions.Workbench).registerWorkbenchContribution( ResourcePerformanceMarks, - 'ResourcePerformanceMarks', LifecyclePhase.Eventually ); diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts b/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts index 35adfeaff21..978c8c32b04 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts @@ -13,7 +13,6 @@ import { RendererProfiling } from 'vs/workbench/contrib/performance/electron-san Registry.as(Extensions.Workbench).registerWorkbenchContribution( RendererProfiling, - 'RendererProfiling', LifecyclePhase.Eventually ); @@ -21,7 +20,6 @@ Registry.as(Extensions.Workbench).registerWorkb Registry.as(Extensions.Workbench).registerWorkbenchContribution( StartupProfiler, - 'StartupProfiler', LifecyclePhase.Restored ); @@ -29,6 +27,5 @@ Registry.as(Extensions.Workbench).registerWorkb Registry.as(Extensions.Workbench).registerWorkbenchContribution( StartupTimings, - 'StartupTimings', LifecyclePhase.Eventually ); diff --git a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts index efc514e74a4..f5dff19e6d8 100644 --- a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts +++ b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts @@ -81,7 +81,7 @@ export class KeyboardLayoutPickerContribution extends Disposable implements IWor } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(KeyboardLayoutPickerContribution, 'KeyboardLayoutPickerContribution', LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(KeyboardLayoutPickerContribution, LifecyclePhase.Starting); interface LayoutQuickPickItem extends IQuickPickItem { layout: IKeyboardLayoutInfo; diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index bda672f49dd..e1aab482fb5 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -1243,8 +1243,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(PreferencesActionsContribution, 'PreferencesActionsContribution', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(PreferencesContribution, 'PreferencesContribution', LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(PreferencesActionsContribution, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(PreferencesContribution, LifecyclePhase.Starting); registerEditorContribution(SettingsEditorContribution.ID, SettingsEditorContribution); diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index a2c8e69b223..fa262bfda14 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -232,5 +232,5 @@ export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWor } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(SettingsChangeRelauncher, 'SettingsChangeRelauncher', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(WorkspaceChangeExtHostRelauncher, 'WorkspaceChangeExtHostRelauncher', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(SettingsChangeRelauncher, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(WorkspaceChangeExtHostRelauncher, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/remote/browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/browser/remote.contribution.ts index 4bb56230f2a..63e7f2df0b4 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.contribution.ts @@ -13,11 +13,11 @@ import { RemoteStatusIndicator } from 'vs/workbench/contrib/remote/browser/remot import { AutomaticPortForwarding, ForwardedPortsView, PortRestore } from 'vs/workbench/contrib/remote/browser/remoteExplorer'; const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(ShowCandidateContribution, 'ShowCandidateContribution', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(TunnelFactoryContribution, 'TunnelFactoryContribution', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, 'RemoteAgentConnectionStatusListener', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteStatusIndicator, 'RemoteStatusIndicator', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(ForwardedPortsView, 'ForwardedPortsView', LifecyclePhase.Restored); -workbenchContributionsRegistry.registerWorkbenchContribution(PortRestore, 'PortRestore', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(AutomaticPortForwarding, 'AutomaticPortForwarding', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteMarkers, 'RemoteMarkers', LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(ShowCandidateContribution, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(TunnelFactoryContribution, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteStatusIndicator, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(ForwardedPortsView, LifecyclePhase.Restored); +workbenchContributionsRegistry.registerWorkbenchContribution(PortRestore, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(AutomaticPortForwarding, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteMarkers, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index c1de0fcfdae..1bf27f3153c 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -267,11 +267,11 @@ class InitialRemoteConnectionHealthContribution implements IWorkbenchContributio } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(LabelContribution, 'LabelContribution', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, 'RemoteChannelsContribution', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteInvalidWorkspaceDetector, 'RemoteInvalidWorkspaceDetector', LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteLogOutputChannels, 'RemoteLogOutputChannels', LifecyclePhase.Restored); -workbenchContributionsRegistry.registerWorkbenchContribution(InitialRemoteConnectionHealthContribution, 'InitialRemoteConnectionHealthContribution', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(LabelContribution, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteInvalidWorkspaceDetector, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteLogOutputChannels, LifecyclePhase.Restored); +workbenchContributionsRegistry.registerWorkbenchContribution(InitialRemoteConnectionHealthContribution, LifecyclePhase.Ready); const enableDiagnostics = true; diff --git a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts index 74be20ebf6c..f884e73d9da 100644 --- a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts @@ -170,12 +170,12 @@ class WSLContextKeyInitializer extends Disposable implements IWorkbenchContribut } const workbenchContributionsRegistry = Registry.as(WorkbenchContributionsExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, 'RemoteAgentDiagnosticListener', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteExtensionHostEnvironmentUpdater, 'RemoteExtensionHostEnvironmentUpdater', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, 'RemoteTelemetryEnablementUpdater', LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, 'RemoteEmptyWorkbenchPresentation', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteExtensionHostEnvironmentUpdater, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, LifecyclePhase.Ready); if (isWindows) { - workbenchContributionsRegistry.registerWorkbenchContribution(WSLContextKeyInitializer, 'WSLContextKeyInitializer', LifecyclePhase.Ready); + workbenchContributionsRegistry.registerWorkbenchContribution(WSLContextKeyInitializer, LifecyclePhase.Ready); } Registry.as(ConfigurationExtensions.Configuration) diff --git a/src/vs/workbench/contrib/sash/browser/sash.contribution.ts b/src/vs/workbench/contrib/sash/browser/sash.contribution.ts index ffcbfcce3fa..ca2bbe1d72b 100644 --- a/src/vs/workbench/contrib/sash/browser/sash.contribution.ts +++ b/src/vs/workbench/contrib/sash/browser/sash.contribution.ts @@ -16,7 +16,7 @@ import { isIOS } from 'vs/base/common/platform'; // Sash size contribution Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(SashSettingsController, 'SashSettingsController', LifecyclePhase.Restored); + .registerWorkbenchContribution(SashSettingsController, LifecyclePhase.Restored); // Sash size configuration contribution Registry.as(ConfigurationExtensions.Configuration) diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 0ff79b1dc49..69dfa264dad 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -39,7 +39,7 @@ ModesRegistry.registerLanguage({ }); Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(DirtyDiffWorkbenchController, 'DirtyDiffWorkbenchController', LifecyclePhase.Restored); + .registerWorkbenchContribution(DirtyDiffWorkbenchController, LifecyclePhase.Restored); const sourceControlViewIcon = registerIcon('source-control-view-icon', Codicon.sourceControl, localize('sourceControlViewIcon', 'View icon of the Source Control view.')); @@ -108,10 +108,10 @@ viewsRegistry.registerViews([{ }], viewContainer); Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(SCMActiveResourceContextKeyController, 'SCMActiveResourceContextKeyController', LifecyclePhase.Restored); + .registerWorkbenchContribution(SCMActiveResourceContextKeyController, LifecyclePhase.Restored); Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(SCMStatusController, 'SCMStatusController', LifecyclePhase.Restored); + .registerWorkbenchContribution(SCMStatusController, LifecyclePhase.Restored); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'scm', diff --git a/src/vs/workbench/contrib/search/browser/replaceContributions.ts b/src/vs/workbench/contrib/search/browser/replaceContributions.ts index 5312753d6d2..3c32a737f8b 100644 --- a/src/vs/workbench/contrib/search/browser/replaceContributions.ts +++ b/src/vs/workbench/contrib/search/browser/replaceContributions.ts @@ -11,5 +11,5 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle export function registerContributions(): void { registerSingleton(IReplaceService, ReplaceService, true); - Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ReplacePreviewContentProvider, 'ReplacePreviewContentProvider', LifecyclePhase.Starting); + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ReplacePreviewContentProvider, LifecyclePhase.Starting); } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 6231409e20b..4d0dd55a919 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -746,7 +746,7 @@ class RegisterSearchViewContribution implements IWorkbenchContribution { .registerConfigurationMigrations([{ key: 'search.location', migrateFn: (value: any) => ({ value: undefined }) }]); } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterSearchViewContribution, 'RegisterSearchViewContribution', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterSearchViewContribution, LifecyclePhase.Starting); // Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts index 6e72f838ba0..a8a22c38b18 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts @@ -100,7 +100,7 @@ class SearchEditorContribution implements IWorkbenchContribution { } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(SearchEditorContribution, 'SearchEditorContribution', LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(SearchEditorContribution, LifecyclePhase.Starting); //#endregion //#region Input Serializer @@ -592,5 +592,5 @@ class SearchEditorWorkingCopyEditorHandler extends Disposable implements IWorkbe } } -workbenchContributionsRegistry.registerWorkbenchContribution(SearchEditorWorkingCopyEditorHandler, 'SearchEditorWorkingCopyEditorHandler', LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(SearchEditorWorkingCopyEditorHandler, LifecyclePhase.Ready); //#endregion diff --git a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts index 24d7e406307..4da8e2b191d 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts @@ -36,7 +36,7 @@ registerAction2(ApplyFileSnippetAction); // workbench contribs Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(SnippetCodeActions, 'SnippetCodeActions', LifecyclePhase.Restored); + .registerWorkbenchContribution(SnippetCodeActions, LifecyclePhase.Restored); // config Registry diff --git a/src/vs/workbench/contrib/splash/browser/splash.contribution.ts b/src/vs/workbench/contrib/splash/browser/splash.contribution.ts index e427bc2e0e2..a037c8fa2a2 100644 --- a/src/vs/workbench/contrib/splash/browser/splash.contribution.ts +++ b/src/vs/workbench/contrib/splash/browser/splash.contribution.ts @@ -22,6 +22,5 @@ registerSingleton(ISplashStorageService, class SplashStorageService implements I Registry.as(Extensions.Workbench).registerWorkbenchContribution( PartsSplash, - 'PartsSplash', LifecyclePhase.Starting ); diff --git a/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts b/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts index 904e65ce6cb..64bfeb23c2e 100644 --- a/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts @@ -25,6 +25,5 @@ registerSingleton(ISplashStorageService, SplashStorageService, true); Registry.as(Extensions.Workbench).registerWorkbenchContribution( PartsSplash, - 'PartsSplash', LifecyclePhase.Starting ); diff --git a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts index aa6e5e53f50..3320a020843 100644 --- a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts @@ -160,5 +160,5 @@ class CESContribution extends Disposable implements IWorkbenchContribution { if (language === 'en') { const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); - workbenchRegistry.registerWorkbenchContribution(CESContribution, 'CESContribution', LifecyclePhase.Restored); + workbenchRegistry.registerWorkbenchContribution(CESContribution, LifecyclePhase.Restored); } diff --git a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts index c05d75f92e7..ae6e3b498bc 100644 --- a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts @@ -160,5 +160,5 @@ class LanguageSurveysContribution implements IWorkbenchContribution { if (language === 'en') { const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); - workbenchRegistry.registerWorkbenchContribution(LanguageSurveysContribution, 'LanguageSurveysContribution', LifecyclePhase.Restored); + workbenchRegistry.registerWorkbenchContribution(LanguageSurveysContribution, LifecyclePhase.Restored); } diff --git a/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts b/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts index df89651c60d..bb1e79f25e4 100644 --- a/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/nps.contribution.ts @@ -94,5 +94,5 @@ class NPSContribution implements IWorkbenchContribution { if (language === 'en') { const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); - workbenchRegistry.registerWorkbenchContribution(NPSContribution, 'NPSContribution', LifecyclePhase.Restored); + workbenchRegistry.registerWorkbenchContribution(NPSContribution, LifecyclePhase.Restored); } diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts b/src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts index 61ce8213cd8..887b429b74c 100644 --- a/src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts +++ b/src/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts @@ -9,4 +9,4 @@ import { WorkspaceTags } from 'vs/workbench/contrib/tags/electron-sandbox/worksp import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; // Register Workspace Tags Contribution -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTags, 'WorkspaceTags', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTags, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 25f1e3c891d..a8b5100b47b 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -41,7 +41,7 @@ import { TerminalMenuBarGroup } from 'vs/workbench/contrib/terminal/browser/term import { isString } from 'vs/base/common/types'; const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(RunAutomaticTasks, 'RunAutomaticTasks', LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(RunAutomaticTasks, LifecyclePhase.Eventually); registerAction2(ManageAutomaticTaskRunning); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { @@ -161,7 +161,7 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench } } -workbenchRegistry.registerWorkbenchContribution(TaskStatusBarContributions, 'TaskStatusBarContributions', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(TaskStatusBarContributions, LifecyclePhase.Restored); MenuRegistry.appendMenuItem(MenuId.MenubarTerminalMenu, { group: TerminalMenuBarGroup.Run, diff --git a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts index 21cd8e46f4e..ad17e2c08ac 100644 --- a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts +++ b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts @@ -234,4 +234,4 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TelemetryContribution, 'TelemetryContribution', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TelemetryContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 8af479229ed..1d59a6cface 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -77,8 +77,8 @@ CommandsRegistry.registerCommand({ id: quickAccessNavigatePreviousInTerminalPick // Register workbench contributions const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(TerminalMainContribution, 'TerminalMainContribution', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(RemoteTerminalBackendContribution, 'RemoteTerminalBackendContribution', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(TerminalMainContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(RemoteTerminalBackendContribution, LifecyclePhase.Restored); // Register configurations registerTerminalPlatformConfiguration(); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts index 2e768f25878..1752c735948 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts @@ -21,5 +21,5 @@ registerSingleton(ITerminalProfileResolverService, ElectronTerminalProfileResolv // Register workbench contributions const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(LocalTerminalBackendContribution, 'LocalTerminalBackendContribution', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, 'TerminalNativeContribution', LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(LocalTerminalBackendContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 087f7555cff..f6580294960 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -102,9 +102,9 @@ registerAction2(GoToNextMessageAction); registerAction2(CloseTestPeek); registerAction2(ToggleTestingPeekHistory); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, 'TestingContentProvider', LifecyclePhase.Restored); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingPeekOpener, 'TestingPeekOpener', LifecyclePhase.Eventually); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingProgressTrigger, 'TestingProgressTrigger', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingPeekOpener, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingProgressTrigger, LifecyclePhase.Eventually); registerEditorContribution(Testing.OutputPeekContributionId, TestingOutputPeekController); registerEditorContribution(Testing.DecorationsContributionId, TestingDecorations); diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index f77d43ba166..78296bf7b6e 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -20,9 +20,9 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels'; const workbench = Registry.as(WorkbenchExtensions.Workbench); -workbench.registerWorkbenchContribution(ProductContribution, 'ProductContribution', LifecyclePhase.Restored); -workbench.registerWorkbenchContribution(UpdateContribution, 'UpdateContribution', LifecyclePhase.Restored); -workbench.registerWorkbenchContribution(SwitchProductQualityContribution, 'SwitchProductQualityContribution', LifecyclePhase.Restored); +workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored); +workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); +workbench.registerWorkbenchContribution(SwitchProductQualityContribution, LifecyclePhase.Restored); const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); diff --git a/src/vs/workbench/contrib/url/browser/url.contribution.ts b/src/vs/workbench/contrib/url/browser/url.contribution.ts index 8f0486abd0b..5ee80ca2ac1 100644 --- a/src/vs/workbench/contrib/url/browser/url.contribution.ts +++ b/src/vs/workbench/contrib/url/browser/url.contribution.ts @@ -64,17 +64,14 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( OpenerValidatorContributions, - 'OpenerValidatorContributions', LifecyclePhase.Restored ); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( TrustedDomainsFileSystemProvider, - 'TrustedDomainsFileSystemProvider', LifecyclePhase.Ready ); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( ExternalUriResolverContribution, - 'ExternalUriResolverContribution', LifecyclePhase.Ready ); diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts index 665ae46d09c..b069dea82cd 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts @@ -10,4 +10,4 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import './userDataProfileActions'; const workbenchRegistry = Registry.as(Extensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(UserDataProfilesWorkbenchContribution, 'UserDataProfilesWorkbenchContribution', LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(UserDataProfilesWorkbenchContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index e470b811bc0..64c68ee02e6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -69,6 +69,6 @@ class UserDataSyncReportIssueContribution extends Disposable implements IWorkben } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(UserDataSyncWorkbenchContribution, 'UserDataSyncWorkbenchContribution', LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(UserDataSyncTrigger, 'UserDataSyncTrigger', LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(UserDataSyncReportIssueContribution, 'UserDataSyncReportIssueContribution', LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncWorkbenchContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncTrigger, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncReportIssueContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts index 2cd27d2465b..6840848e322 100644 --- a/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts @@ -29,7 +29,7 @@ class UserDataSyncServicesContribution implements IWorkbenchContribution { } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(UserDataSyncServicesContribution, 'UserDataSyncServicesContribution', LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncServicesContribution, LifecyclePhase.Starting); registerAction2(class OpenSyncBackupsFolder extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 592b032dfee..d20cf69cc08 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -210,7 +210,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WatermarkContribution, 'WatermarkContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(WatermarkContribution, LifecyclePhase.Restored); Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts index 0e6e8e11e66..9b9f5741211 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts @@ -82,7 +82,7 @@ class WebviewPanelContribution extends Disposable implements IWorkbenchContribut } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(WebviewPanelContribution, 'WebviewPanelContribution', LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(WebviewPanelContribution, LifecyclePhase.Starting); Registry.as(EditorExtensions.EditorFactory).registerEditorSerializer( WebviewEditorInputSerializer.ID, diff --git a/src/vs/workbench/contrib/welcomeBanner/browser/welcomeBanner.contribution.ts b/src/vs/workbench/contrib/welcomeBanner/browser/welcomeBanner.contribution.ts index 2aa549c7556..543ff8df1be 100644 --- a/src/vs/workbench/contrib/welcomeBanner/browser/welcomeBanner.contribution.ts +++ b/src/vs/workbench/contrib/welcomeBanner/browser/welcomeBanner.contribution.ts @@ -50,4 +50,4 @@ class WelcomeBannerContribution { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WelcomeBannerContribution, 'WelcomeBannerContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(WelcomeBannerContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts index 2c18fde1e75..7bdc86fa5bc 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts @@ -285,7 +285,7 @@ class WorkspacePlatformContribution { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WorkspacePlatformContribution, 'WorkspacePlatformContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(WorkspacePlatformContribution, LifecyclePhase.Restored); const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -336,4 +336,4 @@ configurationRegistry.registerConfiguration({ Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(StartupPageContribution, 'StartupPageContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(StartupPageContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts index a6d0e9e5e03..55ef4113b60 100644 --- a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts +++ b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts @@ -206,7 +206,7 @@ class NewFileTemplatesManager extends Disposable { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(NewFileTemplatesManager, 'NewFileTemplatesManager', LifecyclePhase.Restored); + .registerWorkbenchContribution(NewFileTemplatesManager, LifecyclePhase.Restored); MenuRegistry.appendMenuItem(MenuId.NewFile, { group: 'file', diff --git a/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.ts b/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.ts index 86e4ddca529..e68958ca71b 100644 --- a/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.ts +++ b/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.ts @@ -22,4 +22,4 @@ class WorkbenchConfigurationContribution { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WorkbenchConfigurationContribution, 'WorkbenchConfigurationContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(WorkbenchConfigurationContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts index 45ba2b555d0..0c1668932d8 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts @@ -35,7 +35,7 @@ Registry.as(Extensions.WorkbenchActions) Registry.as(EditorExtensions.EditorFactory).registerEditorSerializer(EditorWalkThroughInputSerializer.ID, EditorWalkThroughInputSerializer); Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WalkThroughSnippetContentProvider, 'WalkThroughSnippetContentProvider', LifecyclePhase.Starting); + .registerWorkbenchContribution(WalkThroughSnippetContentProvider, LifecyclePhase.Starting); KeybindingsRegistry.registerCommandAndKeybindingRule(WalkThroughArrowUp); diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 67ae288b9a6..1575fbf2118 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -72,7 +72,7 @@ export class WorkspaceTrustContextKeys extends Disposable implements IWorkbenchC } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustContextKeys, 'WorkspaceTrustContextKeys', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustContextKeys, LifecyclePhase.Restored); /* @@ -578,8 +578,8 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon //#endregion } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustRequestHandler, 'WorkspaceTrustRequestHandler', LifecyclePhase.Ready); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustUXHandler, 'WorkspaceTrustUXHandler', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustRequestHandler, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustUXHandler, LifecyclePhase.Restored); /** @@ -857,4 +857,4 @@ class WorkspaceTrustTelemetryContribution extends Disposable implements IWorkben } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WorkspaceTrustTelemetryContribution, 'WorkspaceTrustTelemetryContribution', LifecyclePhase.Restored); + .registerWorkbenchContribution(WorkspaceTrustTelemetryContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts b/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts index c274839d5bd..26d1f82e6b7 100644 --- a/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts +++ b/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts @@ -94,7 +94,7 @@ export class WorkspacesFinderContribution extends Disposable implements IWorkben } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspacesFinderContribution, 'WorkspacesFinderContribution', LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspacesFinderContribution, LifecyclePhase.Eventually); // Render "Open Workspace" button in *.code-workspace files diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts index 07792869840..60eb43ec230 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts +++ b/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts @@ -99,4 +99,4 @@ export class DialogHandlerContribution extends Disposable implements IWorkbenchC } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, 'DialogHandlerContribution', LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, LifecyclePhase.Starting); diff --git a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts index c02ebba5884..a7d574ca562 100644 --- a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts @@ -87,5 +87,5 @@ class LinuxAccessibilityContribution implements IWorkbenchContribution { } if (isLinux) { - Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LinuxAccessibilityContribution, 'LinuxAccessibilityContribution', LifecyclePhase.Ready); + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LinuxAccessibilityContribution, LifecyclePhase.Ready); } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index ed219b35242..ea97c694c87 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -1301,6 +1301,6 @@ class UpdateExperimentalSettingsDefaults extends Disposable implements IWorkbenc } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, 'RegisterConfigurationSchemasContribution', LifecyclePhase.Restored); -workbenchContributionsRegistry.registerWorkbenchContribution(ResetConfigurationDefaultsOverridesCache, 'ResetConfigurationDefaultsOverridesCache', LifecyclePhase.Eventually); -workbenchContributionsRegistry.registerWorkbenchContribution(UpdateExperimentalSettingsDefaults, 'UpdateExperimentalSettingsDefaults', LifecyclePhase.Restored); +workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored); +workbenchContributionsRegistry.registerWorkbenchContribution(ResetConfigurationDefaultsOverridesCache, LifecyclePhase.Eventually); +workbenchContributionsRegistry.registerWorkbenchContribution(UpdateExperimentalSettingsDefaults, LifecyclePhase.Restored); diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index 2a099ed043a..ad8c116d0b3 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -211,7 +211,6 @@ class ExtensionBisectUi { Registry.as(Extensions.Workbench).registerWorkbenchContribution( ExtensionBisectUi, - 'ExtensionBisectUi', LifecyclePhase.Restored ); diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index e147dac6cc2..13924b49ef0 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -416,7 +416,7 @@ class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandle } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ExtensionUrlBootstrapHandler, 'ExtensionUrlBootstrapHandler', LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(ExtensionUrlBootstrapHandler, LifecyclePhase.Ready); class ManageAuthorizedExtensionURIsAction extends Action2 { diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index bf0c0c1f5b2..e969fc50dce 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -103,7 +103,7 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution { }); } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, 'ResourceLabelFormattersHandler', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, LifecyclePhase.Restored); const FORMATTER_CACHE_SIZE = 50; diff --git a/src/vs/workbench/services/remote/browser/remoteAgentService.ts b/src/vs/workbench/services/remote/browser/remoteAgentService.ts index 69a816ad6b9..dc897db8241 100644 --- a/src/vs/workbench/services/remote/browser/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/browser/remoteAgentService.ts @@ -69,4 +69,4 @@ class RemoteConnectionFailureNotificationContribution implements IWorkbenchContr } const workbenchRegistry = Registry.as(Extensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, 'RemoteConnectionFailureNotificationContribution', LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts b/src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts index 38556bbcb9a..997cfc7cda5 100644 --- a/src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/electron-sandbox/remoteAgentService.ts @@ -90,4 +90,4 @@ class RemoteConnectionFailureNotificationContribution implements IWorkbenchContr } const workbenchRegistry = Registry.as(Extensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, 'RemoteConnectionFailureNotificationContribution', LifecyclePhase.Ready); +workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/services/userData/browser/userDataInit.ts b/src/vs/workbench/services/userData/browser/userDataInit.ts index 67ab3ee9976..e7cfccfe177 100644 --- a/src/vs/workbench/services/userData/browser/userDataInit.ts +++ b/src/vs/workbench/services/userData/browser/userDataInit.ts @@ -445,5 +445,5 @@ class InitializeOtherResourcesContribution implements IWorkbenchContribution { if (isWeb) { const workbenchRegistry = Registry.as(Extensions.Workbench); - workbenchRegistry.registerWorkbenchContribution(InitializeOtherResourcesContribution, 'InitializeOtherResourcesContribution', LifecyclePhase.Restored); + workbenchRegistry.registerWorkbenchContribution(InitializeOtherResourcesContribution, LifecyclePhase.Restored); } diff --git a/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts b/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts index 9b6ac4489eb..14f99f72911 100644 --- a/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts +++ b/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts @@ -32,4 +32,4 @@ export class BrowserWorkingCopyBackupService extends WorkingCopyBackupService { registerSingleton(IWorkingCopyBackupService, BrowserWorkingCopyBackupService, InstantiationType.Eager); // Register Backup Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BrowserWorkingCopyBackupTracker, 'BrowserWorkingCopyBackupTracker', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BrowserWorkingCopyBackupTracker, LifecyclePhase.Starting); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts index d758a61f093..1e299593f87 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyHistoryService.ts @@ -787,4 +787,4 @@ export abstract class WorkingCopyHistoryService extends Disposable implements IW } // Register History Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkingCopyHistoryTracker, 'WorkingCopyHistoryTracker', LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkingCopyHistoryTracker, LifecyclePhase.Restored); diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts index f2c28188a53..1aa006ca6e6 100644 --- a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts +++ b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts @@ -42,4 +42,4 @@ export class NativeWorkingCopyBackupService extends WorkingCopyBackupService { registerSingleton(IWorkingCopyBackupService, NativeWorkingCopyBackupService, InstantiationType.Eager); // Register Backup Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeWorkingCopyBackupTracker, 'NativeWorkingCopyBackupTracker', LifecyclePhase.Starting); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeWorkingCopyBackupTracker, LifecyclePhase.Starting); From b29b217e36ce43101f67334c291386fd593d8493 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 10:50:48 +0200 Subject: [PATCH 199/599] Fixes #162027 --- extensions/git/package.json | 10 ------- .../mergeEditor/browser/commands/commands.ts | 26 +---------------- .../browser/mergeEditor.contribution.ts | 23 +-------------- .../browser/model/mergeEditorModel.ts | 28 ------------------- 4 files changed, 2 insertions(+), 85 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index db43d24b5f2..a8764170aa6 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1590,16 +1590,6 @@ "when": "config.git.enabled && !git.missing && !isInDiffEditor && !isMergeEditor && resource in git.mergeChanges" } ], - "mergeEditor/result/title": [ - { - "command": "git.runGitMerge", - "when": "isMergeEditor" - }, - { - "command": "git.runGitMergeDiff3", - "when": "isMergeEditor" - } - ], "scm/change/title": [ { "command": "git.stageChange", diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 33cb8fd014f..73882208428 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -603,31 +603,7 @@ export class ResetToBaseAndAutoMergeCommand extends MergeEditorAction { } override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { - viewModel.model.resetResultToBaseAndAutoMerge(); - } -} - -export class ResetDirtyConflictsToBaseCommand extends MergeEditorAction { - constructor() { - super({ - id: 'mergeEditor.resetDirtyConflictsToBase', - category: mergeEditorCategory, - title: { - value: localize( - 'mergeEditor.resetDirtyConflictsToBase', - 'Reset Dirty Conflicts In Result To Base' - ), - original: 'Reset Dirty Conflicts In Result To Base', - }, - shortTitle: localize('mergeEditor.resetDirtyConflictsToBase.short', 'Reset Dirty Conflicts To Base'), - f1: true, - precondition: ctxIsMergeEditor, - menu: { id: MenuId.MergeInputResultToolbar } - }); - } - - override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { - viewModel.model.resetDirtyConflictsToBase(); + viewModel.model.reset(); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index ed17e054277..6a5a7cd3bdc 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -11,7 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; -import { AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, ResetDirtyConflictsToBaseCommand, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideAtTopBase, ShowHideBase, ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; +import { AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideAtTopBase, ShowHideBase, ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; import { MergeEditorCopyContentsToJSON, MergeEditorLoadContentsFromFolder, MergeEditorSaveContentsToFolder } from 'vs/workbench/contrib/mergeEditor/browser/commands/devCommands'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor, MergeEditorOpenHandlerContribution, MergeEditorResolverContribution } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -70,7 +70,6 @@ registerAction2(AcceptAllInput1); registerAction2(AcceptAllInput2); registerAction2(ResetToBaseAndAutoMergeCommand); -registerAction2(ResetDirtyConflictsToBaseCommand); registerAction2(AcceptMerge); @@ -86,23 +85,3 @@ Registry Registry .as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(MergeEditorResolverContribution, LifecyclePhase.Starting); -/* -class MergeEditorWorkbenchContribution extends Disposable implements IWorkbenchContribution { - constructor(@IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService) { - super(); - - this._register( - _workingCopyEditorService.registerHandler({ - createEditor(workingCopy) { - throw new BugIndicatingError('not supported'); - }, - handles(workingCopy) { - return workingCopy.typeId === ''; - }, - isOpen(workingCopy, editor) { - return workingCopy.resource.toString() === that._model?.resultTextModel.uri.toString(); - }, - })); - } -} -*/ diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 365d11269b8..0ba8f83e655 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -437,34 +437,6 @@ export class MergeEditorModel extends EditorModel { }); } - public acceptNonConflictingDiffs(): void { - transaction((tx) => { - /** @description Merge None Conflicting Diffs */ - this.resultTextModel.pushStackElement(); - for (const m of this.modifiedBaseRanges.get()) { - if (m.isConflicting) { - continue; - } - this.setState( - m, - m.input1Diffs.length > 0 - ? ModifiedBaseRangeState.default.withInput1(true) - : ModifiedBaseRangeState.default.withInput2(true), - true, - tx, - false - ); - } - this.resultTextModel.pushStackElement(); - }); - } - - public async resetResultToBaseAndAutoMerge() { - await waitForState(this.inputDiffComputingState, state => state === MergeEditorModelState.upToDate); - this.resultTextModel.setValue(this.base.getValue()); - this.acceptNonConflictingDiffs(); - } - public isHandled(baseRange: ModifiedBaseRange): IObservable { return this.modifiedBaseRangeResultStates.get().get(baseRange)!.handled; } From 61f44f9b2c6f50794cbf06811055e6cd782da1eb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 29 Sep 2022 11:27:17 +0200 Subject: [PATCH 200/599] give menuIds to setActions, adopt for composite panes (#162317) fixes https://github.com/microsoft/vscode/issues/162003#issuecomment-1261214285 --- src/vs/platform/actions/browser/toolbar.ts | 9 ++++++--- src/vs/platform/actions/common/actions.ts | 2 +- src/vs/platform/actions/common/menuService.ts | 16 +++++++++------- src/vs/workbench/browser/composite.ts | 10 ++++++++++ src/vs/workbench/browser/panecomposite.ts | 13 ++++++++++++- src/vs/workbench/browser/parts/compositePart.ts | 3 ++- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index 63bc9d27504..2117bb57c00 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -96,7 +96,7 @@ export class WorkbenchToolBar extends ToolBar { } } - override setActions(_primary: readonly IAction[], _secondary: readonly IAction[] = []): void { + override setActions(_primary: readonly IAction[], _secondary: readonly IAction[] = [], menuIds?: readonly MenuId[]): void { this._sessionDisposables.clear(); const primary = _primary.slice(); @@ -170,12 +170,15 @@ export class WorkbenchToolBar extends ToolBar { actions = [hideAction, new Separator(), ...toggleActions]; // add "Reset Menu" action - if (someAreHidden && this._options?.resetMenu) { + if (this._options?.resetMenu && !menuIds) { + menuIds = [this._options.resetMenu]; + } + if (someAreHidden && menuIds) { actions.push(new Separator()); actions.push(toAction({ id: 'resetThisMenu', label: localize('resetThisMenu', "Reset Menu"), - run: () => this._menuService.resetHiddenStates(this._options!.resetMenu) + run: () => this._menuService.resetHiddenStates(menuIds) })); } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 3c3353f52d6..ea836c330a6 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -238,7 +238,7 @@ export interface IMenuService { /** * Reset the menu's hidden states. */ - resetHiddenStates(menuId: MenuId | undefined): void; + resetHiddenStates(menuIds: readonly MenuId[] | undefined): void; } export type ICommandsMap = Map; diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index d3671f623f8..355fa5f43cf 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -32,8 +32,8 @@ export class MenuService implements IMenuService { return new MenuImpl(id, this._hiddenStates, { emitEventsForSubmenuChanges: false, eventDebounceDelay: 50, ...options }, this._commandService, contextKeyService); } - resetHiddenStates(id?: MenuId): void { - this._hiddenStates.reset(id); + resetHiddenStates(ids?: MenuId[]): void { + this._hiddenStates.reset(ids); } } @@ -108,17 +108,19 @@ class PersistedMenuHideState { this._persist(); } - reset(menu?: MenuId): void { - if (menu === undefined) { + reset(menus?: MenuId[]): void { + if (menus === undefined) { // reset all this._data = Object.create(null); this._persist(); } else { // reset only for a specific menu - if (this._data[menu.id]) { - delete this._data[menu.id]; - this._persist(); + for (const { id } of menus) { + if (this._data[id]) { + delete this._data[id]; + } } + this._persist(); } } diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index a619fe25a1f..ca2f9cdf638 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -15,6 +15,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { Disposable } from 'vs/base/common/lifecycle'; import { assertIsDefined } from 'vs/base/common/types'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { MenuId } from 'vs/platform/actions/common/actions'; /** * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite @@ -161,6 +162,15 @@ export abstract class Composite extends Component implements IComposite { super.updateStyles(); } + + /** + * + * @returns the action runner for this composite + */ + getMenuIds(): readonly MenuId[] { + return []; + } + /** * Returns an array of actions to show in the action bar of the composite. */ diff --git a/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts index 21230d84325..246e899675a 100644 --- a/src/vs/workbench/browser/panecomposite.ts +++ b/src/vs/workbench/browser/panecomposite.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { Dimension } from 'vs/base/browser/dom'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAction, Separator } from 'vs/base/common/actions'; -import { SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuId, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -73,6 +73,17 @@ export abstract class PaneComposite extends Composite implements IPaneComposite return this.viewPaneContainer?.menuActions?.getContextMenuActions() ?? []; } + override getMenuIds(): MenuId[] { + const result: MenuId[] = []; + if (this.viewPaneContainer?.menuActions) { + result.push(this.viewPaneContainer.menuActions.menuId); + if (this.viewPaneContainer.isViewMergedWithContainer()) { + result.push(this.viewPaneContainer.panes[0].menuActions.menuId); + } + } + return result; + } + override getActions(): readonly IAction[] { const result = []; if (this.viewPaneContainer?.menuActions) { diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index af7db9400e1..18a4d42ea90 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -329,6 +329,7 @@ export abstract class CompositePart extends Part { private collectCompositeActions(composite?: Composite): () => void { // From Composite + const menuIds = composite?.getMenuIds(); const primaryActions: IAction[] = composite?.getActions().slice(0) || []; const secondaryActions: IAction[] = composite?.getSecondaryActions().slice(0) || []; @@ -337,7 +338,7 @@ export abstract class CompositePart extends Part { toolBar.context = this.actionsContextProvider(); // Return fn to set into toolbar - return () => toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions)); + return () => toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions), menuIds); } protected getActiveComposite(): IComposite | undefined { From c4359c2dab4e7e5fce31dd8248a4d1d0744d50a0 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 12:18:18 +0200 Subject: [PATCH 201/599] Addresses #162112 (#162321) --- extensions/git/package.nls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 683e7142348..57e36d3422e 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -104,7 +104,7 @@ "command.api.getRepositoryState": "Get Repository State", "command.api.getRemoteSources": "Get Remote Sources", "command.git.acceptMerge": "Accept Merge", - "command.git.openMergeEditor": "Open in Merge Editor", + "command.git.openMergeEditor": "Resolve in Merge Editor", "command.git.runGitMerge": "Compute Conflicts With Git", "command.git.runGitMergeDiff3": "Compute Conflicts With Git (Diff3)", "config.enabled": "Whether git is enabled.", From 320f33868193bab477df8f389c5ef0957f781d39 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 29 Sep 2022 12:19:36 +0200 Subject: [PATCH 202/599] [html] Sytax Highlighting is way off with new line after event handler (#162319) --- .../server/src/modes/embeddedSupport.ts | 4 ++-- .../html-language-features/server/src/test/embedded.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/html-language-features/server/src/modes/embeddedSupport.ts b/extensions/html-language-features/server/src/modes/embeddedSupport.ts index 9cc401fdf38..c3398f8f80f 100644 --- a/extensions/html-language-features/server/src/modes/embeddedSupport.ts +++ b/extensions/html-language-features/server/src/modes/embeddedSupport.ts @@ -196,9 +196,9 @@ function getSuffix(c: EmbeddedRegion) { } function substituteWithWhitespace(result: string, start: number, end: number, oldContent: string, before: string, after: string) { - let accumulatedWS = 0; result += before; - for (let i = start + before.length; i < end; i++) { + let accumulatedWS = -before.length; // start with a negative value to account for the before string + for (let i = start; i < end; i++) { const ch = oldContent[i]; if (ch === '\n' || ch === '\r') { // only write new lines, skip the whitespace diff --git a/extensions/html-language-features/server/src/test/embedded.test.ts b/extensions/html-language-features/server/src/test/embedded.test.ts index 1e63a72ec89..722578cb07c 100644 --- a/extensions/html-language-features/server/src/test/embedded.test.ts +++ b/extensions/html-language-features/server/src/test/embedded.test.ts @@ -122,7 +122,7 @@ suite('HTML Embedded Support', () => { assertEmbeddedLanguageContent('
', 'javascript', ' foo(); bar(); '); assertEmbeddedLanguageContent('
', 'javascript', ' return; '); - + assertEmbeddedLanguageContent('
', 'javascript', ' return;\n foo(); '); }); }); From c00b594c7e0e8fd0772a66513dd4f6cf68e85af4 Mon Sep 17 00:00:00 2001 From: Najmieh <98463228+najmiehsa@users.noreply.github.com> Date: Thu, 29 Sep 2022 14:20:48 +0330 Subject: [PATCH 203/599] Edit for the slight ambiguity in wording when adding untrusted files to trusted workspace (#161168) fix the wording for the untrusted files to trusted workspace --- .../contrib/workspace/browser/workspace.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 1575fbf2118..4dad7461871 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -271,7 +271,7 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon localize('addWorkspaceFolderMessage', "Do you trust the authors of the files in this folder?"), [localize('yes', 'Yes'), localize('no', 'No')], { - detail: localize('addWorkspaceFolderDetail', "You are adding files to a trusted workspace that are not currently trusted. Do you trust the authors of these new files?"), + detail: localize('addWorkspaceFolderDetail', "You are adding files that are not currently trusted to a trusted workspace. Do you trust the authors of these new files?"), cancelId: 1, custom: { icon: Codicon.shield } } From 095f6b5e49ea50301db609c248431ee1a7f707de Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 29 Sep 2022 03:54:59 -0700 Subject: [PATCH 204/599] Revert "Allow opt-in multi-line quick fixes (#162189)" This reverts commit 0c22a33a9d670a84309447b36abdbd8c04ee6219. --- .../commandDetectionCapability.ts | 52 ++++++++----------- .../contrib/terminal/browser/terminal.ts | 25 ++++++++- .../browser/terminalQuickFixBuiltinActions.ts | 2 +- .../contrib/terminal/common/terminal.ts | 23 ++------ .../test/browser/quickFixAddon.test.ts | 3 +- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 5257fd8352e..5b6a8ca79ac 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -490,7 +490,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { commandStartLineContent: this._currentCommand.commandStartLineContent, hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), - getOutputMatch: (outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), + getOutputMatch: (outputMatcher?: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), markProperties: options?.markProperties }; this._commands.push(newCommand); @@ -647,35 +647,43 @@ function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMa return output === '' ? undefined : output; } -export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }): RegExpMatchArray | undefined { +export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number } | undefined): RegExpMatchArray | undefined { if (!executedMarker || !endMarker) { return undefined; } const startLine = executedMarker.line; const endLine = endMarker.line; - const matcher = outputMatcher.lineMatcher; - const linesToCheck = typeof matcher === 'string' ? 1 : countNewLines(matcher); - const lines: string[] = []; - if (outputMatcher.anchor === 'bottom') { + if (startLine === endLine) { + return undefined; + } + + let line: string | undefined; + if (outputMatcher?.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { - lines.unshift(getXtermLineContent(buffer, i, i, cols)); - if (lines.length > linesToCheck) { - lines.pop(); + let wrappedLineStart = i; + const wrappedLineEnd = i; + while (wrappedLineStart >= startLine && buffer.getLine(wrappedLineStart)?.isWrapped) { + wrappedLineStart--; } - const match = lines.join('\n').match(matcher); + i = wrappedLineStart; + line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); + const match = line.match(outputMatcher.lineMatcher); if (match) { return match; } } } else { - for (let i = startLine + (outputMatcher.offset || 0); i < endLine; i++) { - lines.push(getXtermLineContent(buffer, i, i, cols)); - if (lines.length === linesToCheck) { - lines.shift(); + for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) { + const wrappedLineStart = i; + let wrappedLineEnd = i; + while (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) { + wrappedLineEnd++; } + i = wrappedLineEnd; + line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); if (outputMatcher) { - const match = lines.join('\n').match(matcher); + const match = line.match(outputMatcher.lineMatcher); if (match) { return match; } @@ -701,17 +709,3 @@ function getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number } return content; } - -function countNewLines(regex: RegExp): number { - if (!regex.multiline) { - return 1; - } - const source = regex.source; - let count = 1; - let i = source.indexOf('\\n'); - while (i !== -1) { - count++; - i = source.indexOf('\\n', i + 1); - } - return count; -} diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index a7f3c931277..9bb8e35938c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -20,7 +20,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import { ITerminalQuickFix } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalOutputMatcher, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IMarker } from 'xterm'; @@ -933,6 +933,29 @@ export interface ITerminalQuickFixAction extends IAction { addNewLine?: boolean; } +/** + * A matcher that runs on a sub-section of a terminal command's output + */ +export interface ITerminalOutputMatcher { + /** + * A string or regex to match against the unwrapped line. + */ + lineMatcher: string | RegExp; + /** + * Which side of the output to anchor the {@link offset} and {@link length} against. + */ + anchor: 'top' | 'bottom'; + /** + * How far from either the top or the bottom of the butter to start matching against. + */ + offset: number; + /** + * The number of rows to match against, this should be as small as possible for performance + * reasons. + */ + length: number; +} + export interface IXtermTerminal { /** * An object that tracks when commands are run and enables navigating and selecting between diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index f3d6241a16e..889776fb25a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -12,7 +12,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.+/; -export const GitSimilarOutputRegex = /most similar command is\s*\n\s*([^\s]{3,})/m; +export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; // The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*", diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 319de723435..c165c6cc43e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -96,28 +96,11 @@ export interface IShellLaunchConfigResolveOptions { allowAutomationShell?: boolean; } -/** - * A matcher that runs on a sub-section of a terminal command's output - */ export interface ITerminalOutputMatcher { - /** - * A string or regex to match against the unwrapped line. If this is a regex with the multiline - * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1. - */ lineMatcher: string | RegExp; - /** - * Which side of the output to anchor the {@link offset} and {@link length} against. - */ - anchor: 'top' | 'bottom'; - /** - * How far from either the top or the bottom of the butter to start matching against. - */ - offset: number; - /** - * The number of rows to match against, this should be as small as possible for performance - * reasons. - */ - length: number; + anchor?: 'top' | 'bottom'; + offset?: number; + length?: number; } export interface ITerminalBackend { diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 415a9d0663a..6de36f45a01 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -14,10 +14,9 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; -import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalQuickFixAction, ITerminalInstance, ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal } from 'xterm'; suite('QuickFixAddon', () => { From ad7695c7931ea582c24c8d95933931faf6e71ff2 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 29 Sep 2022 12:58:10 +0200 Subject: [PATCH 205/599] Adopt new Notices format (#162324) --- ThirdPartyNotices.txt | 792 +++++++++++++++++++++++------------------- 1 file changed, 430 insertions(+), 362 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 02721af49cc..9326900f1b4 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -1,86 +1,14 @@ -microsoft-vscode +NOTICES -THIRD-PARTY SOFTWARE NOTICES AND INFORMATION -Do Not Translate or Localize - -This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. - -1. atom/language-clojure version 0.22.8 (https://github.com/atom/language-clojure) -2. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) -3. atom/language-css version 0.45.1 (https://github.com/atom/language-css) -4. atom/language-java version 0.32.1 (https://github.com/atom/language-java) -5. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) -6. atom/language-shellscript version 0.28.2 (https://github.com/atom/language-shellscript) -7. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) -8. better-go-syntax version 1.0.0 (https://github.com/jeff-hykin/better-go-syntax/ ) -9. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) -10. daaain/Handlebars version 1.8.0 (https://github.com/daaain/Handlebars) -11. dart-lang/dart-syntax-highlight (https://github.com/dart-lang/dart-syntax-highlight) -12. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) -13. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) -14. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) -15. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) -16. dompurify version 2.3.1 (https://github.com/cure53/DOMPurify) -17. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) -18. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) -19. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) -20. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) -21. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -22. Ikuyadeu/vscode-R version 2.3.8 (https://github.com/Ikuyadeu/vscode-R) -23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -25. James-Yu/LaTeX-Workshop version 8.19.1 (https://github.com/James-Yu/LaTeX-Workshop) -26. jeff-hykin/better-c-syntax version 1.13.2 (https://github.com/jeff-hykin/better-c-syntax) -27. jeff-hykin/better-cpp-syntax version 1.15.18 (https://github.com/jeff-hykin/better-cpp-syntax) -28. jeff-hykin/better-objc-syntax version 0.2.0 (https://github.com/jeff-hykin/better-objc-syntax) -29. jeff-hykin/better-objcpp-syntax version 0.1.0 (https://github.com/jeff-hykin/better-objcpp-syntax) -30. jlelong/vscode-latex-basics version 1.3.0 (https://github.com/jlelong/vscode-latex-basics) -31. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) -32. JuliaEditorSupport/atom-language-julia version 0.22.1 (https://github.com/JuliaEditorSupport/atom-language-julia) -33. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) -34. language-docker (https://github.com/moby/moby) -35. language-less version 0.34.2 (https://github.com/atom/language-less) -36. language-php version 0.48.1 (https://github.com/atom/language-php) -37. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -38. marked version 4.1.0 (https://github.com/markedjs/marked) -39. mdn-data version 1.1.12 (https://github.com/mdn/data) -40. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) -41. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) -42. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar) -43. microsoft/vscode-mssql version 1.16.0 (https://github.com/microsoft/vscode-mssql) -44. mmims/language-batchfile version 0.7.6 (https://github.com/mmims/language-batchfile) -45. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar) -46. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) -47. rust-syntax version 0.5.0 (https://github.com/dustypomerleau/rust-syntax) -48. semver version 5.5.0 (https://github.com/npm/node-semver) -49. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -50. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -51. sumneko/lua.tmbundle version 1.0.0 (https://github.com/sumneko/lua.tmbundle) -52. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -53. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -54. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -55. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -56. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -57. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -58. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -59. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -60. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -61. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -62. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) -63. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -64. trond-snekvik/vscode-rst version 1.5.1 (https://github.com/trond-snekvik/vscode-rst) -65. TypeScript-TmLanguage version 0.1.8 (https://github.com/microsoft/TypeScript-TmLanguage) -66. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage) -67. Unicode version 12.0.0 (https://home.unicode.org/) -68. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons) -69. vscode-logfile-highlighter version 2.15.0 (https://github.com/emilast/vscode-logfile-highlighter) -70. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) -71. vscode-win32-app-container-tokens (https://github.com/microsoft/vscode-win32-app-container-tokens) -72. Web Background Synchronization (https://github.com/WICG/background-sync) +This repository incorporates material as listed below or described in the code. -%% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE -========================================= + +--------------------------------------------------------- + +atom/language-clojure 0.22.8 - MIT +https://github.com/atom/language-clojure + Copyright (c) 2014 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining @@ -128,11 +56,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-clojure NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-coffee-script 0.49.3 - MIT +https://github.com/atom/language-coffee-script -%% atom/language-coffee-script NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -183,11 +113,13 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-coffee-script NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-css 0.45.1 - GitHub License +https://github.com/atom/language-css -%% atom/language-css NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2014 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining @@ -219,11 +151,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-css NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-java 0.32.1 - MIT +https://github.com/atom/language-java -%% atom/language-java NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -256,11 +190,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-java NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-sass 0.61.4 - MIT +https://github.com/atom/language-sass -%% atom/language-sass NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -309,11 +245,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-sass NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-shellscript 0.28.2 - MIT +https://github.com/atom/language-shellscript -%% atom/language-shellscript NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -346,11 +284,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-shellscript NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +atom/language-xml 0.35.2 - MIT +https://github.com/atom/language-xml -%% atom/language-xml NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -383,11 +323,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF atom/language-xml NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +better-go-syntax 1.0.0 - MIT +https://github.com/jeff-hykin/better-go-syntax/ -%% better-go-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -409,11 +351,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF better-go-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Colorsublime-Themes 0.1.0 +https://github.com/Colorsublime/Colorsublime-Themes -%% Colorsublime-Themes NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2015 Colorsublime.com Permission is hereby granted, free of charge, to any person obtaining a copy @@ -433,11 +377,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Colorsublime-Themes NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +daaain/Handlebars 1.8.0 - MIT +https://github.com/daaain/Handlebars -%% daaain/Handlebars NOTICES AND INFORMATION BEGIN HERE -========================================= -- Credits Adapted from the great sublime-text-handlebars package by Nicholas Westlake. @@ -455,11 +401,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF daaain/Handlebars NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dart-lang/dart-syntax-highlight 0.0.0 - BSD +https://github.com/dart-lang/dart-syntax-highlight -%% dart-lang/dart-syntax-highlight NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright 2020, the Dart project authors. Redistribution and use in source and binary forms, with or without @@ -487,11 +435,13 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -========================================= -END OF dart-lang/dart-syntax-highlight NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +davidrios/pug-tmbundle 0.0.0 - MIT +https://github.com/davidrios/pug-tmbundle -%% davidrios/pug-tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2016 David Rios @@ -512,11 +462,13 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF davidrios/pug-tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +definitelytyped - MIT +https://github.com/DefinitelyTyped/DefinitelyTyped -%% definitelytyped NOTICES AND INFORMATION BEGIN HERE -========================================= This project is licensed under the MIT license. Copyrights are respective of each contributor listed at the beginning of each definition file. @@ -525,11 +477,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF definitelytyped NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +demyte/language-cshtml 0.3.0 - MIT +https://github.com/demyte/language-cshtml -%% demyte/language-cshtml NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 James Summerton @@ -552,11 +506,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF demyte/language-cshtml NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Document Object Model 4.0.0 - W3C License +https://www.w3.org/DOM/ -%% Document Object Model NOTICES AND INFORMATION BEGIN HERE -========================================= W3C License This work is being provided by the copyright holders under the following license. By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. @@ -573,11 +529,13 @@ FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT W COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. -========================================= -END OF Document Object Model NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dompurify 2.3.1 - Apache 2.0 +https://github.com/cure53/DOMPurify -%% dompurify NOTICES AND INFORMATION BEGIN HERE -========================================= DOMPurify Copyright 2015 Mario Heiderich @@ -955,11 +913,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -========================================= -END OF dompurify NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +dotnet/csharp-tmLanguage 0.1.0 - MIT +https://github.com/dotnet/csharp-tmLanguage -%% dotnet/csharp-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2016 .NET Foundation @@ -981,11 +941,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF dotnet/csharp-tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +expand-abbreviation 0.5.8 - MIT +https://github.com/emmetio/expand-abbreviation -%% expand-abbreviation NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2017 Emmet.io @@ -1007,11 +969,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF expand-abbreviation NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +fadeevab/make.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/fadeevab/make.tmbundle -%% fadeevab/make.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-make.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -1025,11 +989,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF fadeevab/make.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +freebroccolo/atom-language-swift 0.0.0 - MIT +https://github.com/freebroccolo/atom-language-swift -%% freebroccolo/atom-language-swift NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 Darin Morrison @@ -1050,11 +1016,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF freebroccolo/atom-language-swift NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +HTML 5.1 W3C Working Draft 08 October 2015 - W3C Document License +http://www.w3.org/TR/2015/WD-html51-20151008/ -%% HTML 5.1 W3C Working Draft NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes material copied from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.) @@ -1068,11 +1036,13 @@ DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. -========================================= -END OF HTML 5.1 W3C Working Draft NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Ikuyadeu/vscode-R 2.3.8 - MIT +https://github.com/Ikuyadeu/vscode-R -%% Ikuyadeu/vscode-R NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2022 REditorSupport @@ -1094,11 +1064,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Ikuyadeu/vscode-R NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Ionic documentation 1.2.4 - Apache2 +https://github.com/ionic-team/ionic-site -%% Ionic documentation NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright Drifty Co. http://drifty.com/. Apache License @@ -1156,11 +1128,13 @@ If the Work includes a "NOTICE" text file as part of its distribution, then any 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS -========================================= -END OF Ionic documentation NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +ionide/ionide-fsgrammar 0.0.0 - MIT +https://github.com/ionide/ionide-fsgrammar -%% ionide/ionide-fsgrammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 Krzysztof Cieslak @@ -1182,11 +1156,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF ionide/ionide-fsgrammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +James-Yu/LaTeX-Workshop 8.19.1 - MIT +https://github.com/James-Yu/LaTeX-Workshop -%% James-Yu/LaTeX-Workshop NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2016 James Yu @@ -1208,11 +1184,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF James-Yu/LaTeX-Workshop NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-c-syntax 1.13.2 - MIT +https://github.com/jeff-hykin/better-c-syntax -%% jeff-hykin/better-c-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -1234,11 +1212,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF jeff-hykin/better-c-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-cpp-syntax 1.15.18 - MIT +https://github.com/jeff-hykin/better-cpp-syntax -%% jeff-hykin/better-cpp-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -1260,11 +1240,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF jeff-hykin/better-cpp-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-objc-syntax 0.2.0 - MIT +https://github.com/jeff-hykin/better-objc-syntax -%% jeff-hykin/better-objc-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -1286,11 +1268,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF jeff-hykin/better-objc-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jeff-hykin/better-objcpp-syntax 0.1.0 - MIT +https://github.com/jeff-hykin/better-objcpp-syntax -%% jeff-hykin/better-objcpp-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2019 Jeff Hykin @@ -1312,11 +1296,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF jeff-hykin/better-objcpp-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +jlelong/vscode-latex-basics 1.3.0 - MIT +https://github.com/jlelong/vscode-latex-basics -%% jlelong/vscode-latex-basics NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) vscode-latex-basics authors If not otherwise specified (see below), files in this repository fall under the MIT License @@ -1335,11 +1321,13 @@ included in VSCode and falls under the license described in markdown-latex-combi The file syntaxes/cpp-grammar-bailout.tmLanguage.json is generated from https://github.com/jeff-hykin/better-cpp-syntax and falls under the license described in cpp-bailout-license.txt. -========================================= -END OF jlelong/vscode-latex-basics NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +js-beautify 1.6.8 - MIT +https://github.com/beautify-web/js-beautify -%% js-beautify NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. @@ -1349,11 +1337,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF js-beautify NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +JuliaEditorSupport/atom-language-julia 0.22.1 - MIT +https://github.com/JuliaEditorSupport/atom-language-julia -%% JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION BEGIN HERE -========================================= The atom-language-julia package is licensed under the MIT "Expat" License: > Copyright (c) 2015 @@ -1376,11 +1366,13 @@ The atom-language-julia package is licensed under the MIT "Expat" License: > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Jxck/assert 1.0.0 - MIT +https://github.com/Jxck/assert -%% Jxck/assert NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2011 Jxck @@ -1404,11 +1396,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Jxck/assert NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-docker 0.0.0 - Apache2 +https://github.com/moby/moby -%% language-docker NOTICES AND INFORMATION BEGIN HERE -========================================= Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ @@ -1599,11 +1593,13 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -========================================= -END OF language-docker NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-less 0.34.2 - MIT +https://github.com/atom/language-less -%% language-less NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -1651,11 +1647,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF language-less NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +language-php 0.48.1 - MIT +https://github.com/atom/language-php -%% language-php NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2014 GitHub Inc. @@ -1688,11 +1686,13 @@ Permission to copy, use, modify, sell and distribute this software is granted. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. -========================================= -END OF language-php NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +MagicStack/MagicPython 1.1.1 - MIT +https://github.com/MagicStack/MagicPython -%% MagicStack/MagicPython NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License Copyright (c) 2015-present MagicStack Inc. http://magic.io @@ -1714,11 +1714,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF MagicStack/MagicPython NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +marked 4.1.0 - MIT +https://github.com/markedjs/marked -%% marked NOTICES AND INFORMATION BEGIN HERE -========================================= information ## Contribution License Agreement @@ -1763,11 +1765,13 @@ Redistribution and use in source and binary forms, with or without modification, * Neither the name "Markdown" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. -========================================= -END OF marked NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +mdn-data 1.1.12 - MPL +https://github.com/mdn/data -%% mdn-data NOTICES AND INFORMATION BEGIN HERE -========================================= Mozilla Public License Version 2.0 Copyright (c) 2018 Mozilla Corporation @@ -2144,11 +2148,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -========================================= -END OF mdn-data NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/TypeScript-TmLanguage 0.0.1 - MIT +https://github.com/microsoft/TypeScript-TmLanguage -%% microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2171,11 +2177,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-JSON.tmLanguage 0.0.0 - MIT +https://github.com/microsoft/vscode-JSON.tmLanguage -%% microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= vscode-JSON.tmLanguage Copyright (c) Microsoft Corporation @@ -2195,11 +2203,13 @@ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-markdown-tm-grammar 1.0.0 - MIT +https://github.com/microsoft/vscode-markdown-tm-grammar -%% microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) Microsoft 2018 @@ -2221,11 +2231,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +microsoft/vscode-mssql 1.16.0 - MIT +https://github.com/microsoft/vscode-mssql -%% microsoft/vscode-mssql NOTICES AND INFORMATION BEGIN HERE -========================================= ------------------------------------------ START OF LICENSE ----------------------------------------- vscode-mssql Copyright (c) Microsoft Corporation @@ -2236,11 +2248,13 @@ Copyright (c) 2016 Microsoft The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------- END OF LICENSE ----------------------------------------- -========================================= -END OF microsoft/vscode-mssql NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +mmims/language-batchfile 0.7.6 - MIT +https://github.com/mmims/language-batchfile -%% mmims/language-batchfile NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2021 Michael Mims @@ -2262,11 +2276,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF mmims/language-batchfile NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +NVIDIA/cuda-cpp-grammar 0.0.0 - MIT +https://github.com/NVIDIA/cuda-cpp-grammar -%% NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright 2021 NVIDIA Corporation @@ -2276,11 +2292,13 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +PowerShell/EditorSyntax 1.0.0 - MIT +https://github.com/PowerShell/EditorSyntax -%% PowerShell/EditorSyntax NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2304,11 +2322,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF PowerShell/EditorSyntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +rust-syntax 0.5.0 - MIT +https://github.com/dustypomerleau/rust-syntax -%% rust-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2020 Dustin Pomerleau @@ -2330,11 +2350,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF rust-syntax NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +semver 5.5.0 - The ISC License +https://github.com/npm/node-semver -%% semver NOTICES AND INFORMATION BEGIN HERE -========================================= The ISC License Copyright (c) Isaac Z. Schlueter and Contributors @@ -2350,11 +2372,13 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -========================================= -END OF semver NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +seti-ui 0.1.0 +https://github.com/jesseweed/seti-ui -%% seti-ui NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2014 Jesse Weed Permission is hereby granted, free of charge, to any person obtaining @@ -2375,11 +2399,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF seti-ui NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +shaders-tmLanguage 0.1.0 - MIT +https://github.com/tgjones/shaders-tmLanguage -%% shaders-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) 2017 Tim Jones @@ -2401,11 +2427,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF shaders-tmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +sumneko/lua.tmbundle 1.0.0 - TextMate Bundle License +https://github.com/sumneko/lua.tmbundle -%% sumneko/lua.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) sumneko-lua.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2419,11 +2447,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF sumneko/lua.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/asp.vb.net.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/asp.vb.net.tmbundle -%% textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-asp.vb.net.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2437,11 +2467,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/c.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/c.tmbundle -%% textmate/c.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-c.tmbundle authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2455,11 +2487,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/c.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/diff.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/diff.tmbundle -%% textmate/diff.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-diff.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2473,11 +2507,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/diff.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/git.tmbundle 0.0.0 - MIT +https://github.com/textmate/git.tmbundle -%% textmate/git.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2008 Tim Harper @@ -2500,11 +2536,13 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/git.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/groovy.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/groovy.tmbundle -%% textmate/groovy.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-groovy.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2518,11 +2556,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/groovy.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/html.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/html.tmbundle -%% textmate/html.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-html.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2536,11 +2576,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/html.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/ini.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/ini.tmbundle -%% textmate/ini.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-ini.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2554,11 +2596,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ini.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/javascript.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/javascript.tmbundle -%% textmate/javascript.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-javascript.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2572,11 +2616,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/javascript.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/markdown.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/markdown.tmbundle -%% textmate/markdown.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) markdown.tmbundle authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2590,11 +2636,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/markdown.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/perl.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/perl.tmbundle -%% textmate/perl.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-perl.tmbundle project authors If not otherwise specified (see below), files in this repository fall under the following license: @@ -2608,11 +2656,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/perl.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/ruby.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/ruby.tmbundle -%% textmate/ruby.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) textmate-ruby.tmbundle project authors If not otherwise specified (see below), files in this folder fall under the following license: @@ -2626,11 +2676,13 @@ An exception is made for files in readable text which contain their own license or files where an accompanying file exists (in the same directory) with a "-license" suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example "tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ruby.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +textmate/yaml.tmbundle 0.0.0 - TextMate Bundle License +https://github.com/textmate/yaml.tmbundle -%% textmate/yaml.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) 2015 FichteFoll Permission is hereby granted, free of charge, to any person obtaining a copy @@ -2649,11 +2701,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/yaml.tmbundle NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +trond-snekvik/vscode-rst 1.5.1 - MIT +https://github.com/trond-snekvik/vscode-rst -%% trond-snekvik/vscode-rst NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright 2021 Trond Snekvik @@ -2663,11 +2717,14 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF trond-snekvik/vscode-rst NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +TypeScript-TmLanguage 0.1.8 - MIT +TypeScript-TmLanguage 1.0.0 - MIT +https://github.com/microsoft/TypeScript-TmLanguage -%% TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= Copyright (c) Microsoft Corporation All rights reserved. @@ -2690,11 +2747,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF TypeScript-TmLanguage NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Unicode 12.0.0 - UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +https://home.unicode.org/ -%% Unicode NOTICES AND INFORMATION BEGIN HERE -========================================= Unicode Data Files include all data files under the directories https://www.unicode.org/Public/, https://www.unicode.org/reports/, https://cldr.unicode.org, https://github.com/unicode-org/icu, and @@ -2750,11 +2809,13 @@ Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. -========================================= -END OF Unicode NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-codicons 0.0.14 - MIT and Creative Commons Attribution 4.0 +https://github.com/microsoft/vscode-codicons -%% vscode-codicons NOTICES AND INFORMATION BEGIN HERE -========================================= Attribution 4.0 International ======================================================================= @@ -3150,11 +3211,13 @@ the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. -========================================= -END OF vscode-codicons NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-logfile-highlighter 2.15.0 - MIT +https://github.com/emilast/vscode-logfile-highlighter -%% vscode-logfile-highlighter NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 emilast @@ -3176,11 +3239,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF vscode-logfile-highlighter NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-swift 0.0.1 - MIT +https://github.com/owensd/vscode-swift -%% vscode-swift NOTICES AND INFORMATION BEGIN HERE -========================================= The MIT License (MIT) Copyright (c) 2015 David Owens II @@ -3201,11 +3266,13 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF vscode-swift NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +vscode-win32-app-container-tokens +https://github.com/microsoft/vscode-win32-app-container-tokens -%% vscode-win32-app-container-tokens NOTICES AND INFORMATION BEGIN HERE -========================================= MIT License Copyright (c) Microsoft Corporation. @@ -3227,11 +3294,13 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE -========================================= -END OF vscode-win32-app-container-tokens NOTICES AND INFORMATION +--------------------------------------------------------- + +--------------------------------------------------------- + +Web Background Synchronization - Apache2 +https://github.com/WICG/background-sync -%% Web Background Synchronization NOTICES AND INFORMATION BEGIN HERE -========================================= Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -3433,5 +3502,4 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -========================================= -END OF Web Background Synchronization NOTICES AND INFORMATION \ No newline at end of file +--------------------------------------------------------- \ No newline at end of file From 79bacef484ab2cd56835af9fca6961c0dd8a0ce9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 28 Sep 2022 07:06:35 -0700 Subject: [PATCH 206/599] Allow opt-in multi-line quick fixes Fixes #161997 --- .../commandDetectionCapability.ts | 38 +++++++++++++++---- .../contrib/terminal/browser/terminal.ts | 25 +----------- .../browser/terminalQuickFixBuiltinActions.ts | 2 +- .../contrib/terminal/common/terminal.ts | 23 +++++++++-- .../test/browser/quickFixAddon.test.ts | 3 +- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 5b6a8ca79ac..222fa193d38 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -490,7 +490,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { commandStartLineContent: this._currentCommand.commandStartLineContent, hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), - getOutputMatch: (outputMatcher?: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), + getOutputMatch: (outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), markProperties: options?.markProperties }; this._commands.push(newCommand); @@ -647,7 +647,7 @@ function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMa return output === '' ? undefined : output; } -export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number } | undefined): RegExpMatchArray | undefined { +export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }): RegExpMatchArray | undefined { if (!executedMarker || !endMarker) { return undefined; } @@ -658,7 +658,9 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en return undefined; } - let line: string | undefined; + const matcher = outputMatcher.lineMatcher; + const linesToCheck = typeof matcher === 'string' ? 1 : countNewLines(matcher); + const lines: string[] = []; if (outputMatcher?.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { let wrappedLineStart = i; @@ -667,23 +669,29 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en wrappedLineStart--; } i = wrappedLineStart; - line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); - const match = line.match(outputMatcher.lineMatcher); + lines.unshift(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols)); + if (lines.length > linesToCheck) { + lines.pop(); + } + const match = lines.join('\n').match(matcher); if (match) { return match; } } } else { - for (let i = startLine + (outputMatcher?.offset || 0); i < endLine; i++) { + for (let i = startLine + (outputMatcher.offset || 0); i < endLine; i++) { const wrappedLineStart = i; let wrappedLineEnd = i; while (wrappedLineEnd + 1 < endLine && buffer.getLine(wrappedLineEnd + 1)?.isWrapped) { wrappedLineEnd++; } i = wrappedLineEnd; - line = getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols); + lines.push(getXtermLineContent(buffer, wrappedLineStart, wrappedLineEnd, cols)); + if (lines.length === linesToCheck) { + lines.shift(); + } if (outputMatcher) { - const match = line.match(outputMatcher.lineMatcher); + const match = lines.join('\n').match(matcher); if (match) { return match; } @@ -709,3 +717,17 @@ function getXtermLineContent(buffer: IBuffer, lineStart: number, lineEnd: number } return content; } + +function countNewLines(regex: RegExp): number { + if (!regex.multiline) { + return 1; + } + const source = regex.source; + let count = 1; + let i = source.indexOf('\\n'); + while (i !== -1) { + count++; + i = source.indexOf('\\n', i + 1); + } + return count; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 9bb8e35938c..a7f3c931277 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -20,7 +20,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import { ITerminalQuickFix } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalOutputMatcher, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IMarker } from 'xterm'; @@ -933,29 +933,6 @@ export interface ITerminalQuickFixAction extends IAction { addNewLine?: boolean; } -/** - * A matcher that runs on a sub-section of a terminal command's output - */ -export interface ITerminalOutputMatcher { - /** - * A string or regex to match against the unwrapped line. - */ - lineMatcher: string | RegExp; - /** - * Which side of the output to anchor the {@link offset} and {@link length} against. - */ - anchor: 'top' | 'bottom'; - /** - * How far from either the top or the bottom of the butter to start matching against. - */ - offset: number; - /** - * The number of rows to match against, this should be as small as possible for performance - * reasons. - */ - length: number; -} - export interface IXtermTerminal { /** * An object that tracks when commands are run and enables navigating and selecting between diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 889776fb25a..f3d6241a16e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -12,7 +12,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const AnyCommandLineRegex = /.+/; -export const GitSimilarOutputRegex = /most similar command is\s*([^\s]{3,})/; +export const GitSimilarOutputRegex = /most similar command is\s*\n\s*([^\s]{3,})/m; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; // The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*", diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index c165c6cc43e..319de723435 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -96,11 +96,28 @@ export interface IShellLaunchConfigResolveOptions { allowAutomationShell?: boolean; } +/** + * A matcher that runs on a sub-section of a terminal command's output + */ export interface ITerminalOutputMatcher { + /** + * A string or regex to match against the unwrapped line. If this is a regex with the multiline + * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1. + */ lineMatcher: string | RegExp; - anchor?: 'top' | 'bottom'; - offset?: number; - length?: number; + /** + * Which side of the output to anchor the {@link offset} and {@link length} against. + */ + anchor: 'top' | 'bottom'; + /** + * How far from either the top or the bottom of the butter to start matching against. + */ + offset: number; + /** + * The number of rows to match against, this should be as small as possible for performance + * reasons. + */ + length: number; } export interface ITerminalBackend { diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 6de36f45a01..415a9d0663a 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -14,9 +14,10 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; -import { ITerminalQuickFixAction, ITerminalInstance, ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; +import { ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal } from 'xterm'; suite('QuickFixAddon', () => { From 187f099e913f2783d9b5a311bb5666f132e4c93b Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 29 Sep 2022 13:08:02 +0200 Subject: [PATCH 207/599] update distro (#162326) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4ad73f96dd9..e741661bd4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.72.0", - "distro": "a75e0e9bdfca0851f24bfad4a244226c87a0c2c4", + "distro": "d4b1b117d224d627ec65bb0fd0b02fdee65303aa", "author": { "name": "Microsoft Corporation" }, From dbc971b48aeb5d728063af5b3616ca5e88ed8d45 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 29 Sep 2022 04:16:41 -0700 Subject: [PATCH 208/599] Remove unneeded if, clean up types --- .../common/capabilities/capabilities.ts | 27 ++++++++++++++++++- .../commandDetectionCapability.ts | 14 ++++------ .../contrib/terminal/browser/terminal.ts | 4 +-- .../contrib/terminal/common/terminal.ts | 26 +----------------- .../browser/links/terminalLinkOpeners.test.ts | 3 +-- .../test/browser/quickFixAddon.test.ts | 3 +-- 6 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 03f863348fc..d68a14d21b8 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -221,10 +221,35 @@ export interface ITerminalCommand { commandStartLineContent?: string; markProperties?: IMarkProperties; getOutput(): string | undefined; - getOutputMatch(outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }): RegExpMatchArray | undefined; + getOutputMatch(outputMatcher: ITerminalOutputMatcher): RegExpMatchArray | undefined; hasOutput(): boolean; } + +/** + * A matcher that runs on a sub-section of a terminal command's output + */ +export interface ITerminalOutputMatcher { + /** + * A string or regex to match against the unwrapped line. If this is a regex with the multiline + * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1. + */ + lineMatcher: string | RegExp; + /** + * Which side of the output to anchor the {@link offset} and {@link length} against. + */ + anchor: 'top' | 'bottom'; + /** + * How far from either the top or the bottom of the butter to start matching against. + */ + offset: number; + /** + * The number of rows to match against, this should be as small as possible for performance + * reasons. + */ + length: number; +} + /** * A clone of the IMarker from xterm which cannot be imported from common */ diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 222fa193d38..814d275ebfa 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -7,7 +7,7 @@ import { timeout } from 'vs/base/common/async'; import { debounce } from 'vs/base/common/decorators'; import { Emitter } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; -import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand, IHandleCommandOptions, ICommandInvalidationRequest, CommandInvalidationReason, ISerializedCommand, ISerializedCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand, IHandleCommandOptions, ICommandInvalidationRequest, CommandInvalidationReason, ISerializedCommand, ISerializedCommandDetectionCapability, ITerminalOutputMatcher } from 'vs/platform/terminal/common/capabilities/capabilities'; // Importing types is safe in any layer // eslint-disable-next-line local/code-import-patterns @@ -490,7 +490,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { commandStartLineContent: this._currentCommand.commandStartLineContent, hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), - getOutputMatch: (outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), + getOutputMatch: (outputMatcher: ITerminalOutputMatcher) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), markProperties: options?.markProperties }; this._commands.push(newCommand); @@ -615,7 +615,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { exitCode: e.exitCode, hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker.line < endMarker.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), - getOutputMatch: (outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), + getOutputMatch: (outputMatcher: ITerminalOutputMatcher) => getOutputMatchForCommand(executedMarker, endMarker, buffer, this._terminal.cols, outputMatcher), markProperties: e.markProperties }; this._commands.push(newCommand); @@ -647,21 +647,17 @@ function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMa return output === '' ? undefined : output; } -export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: { lineMatcher: string | RegExp; anchor?: 'top' | 'bottom'; offset?: number; length?: number }): RegExpMatchArray | undefined { +export function getOutputMatchForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer, cols: number, outputMatcher: ITerminalOutputMatcher): RegExpMatchArray | undefined { if (!executedMarker || !endMarker) { return undefined; } const startLine = executedMarker.line; const endLine = endMarker.line; - if (startLine === endLine) { - return undefined; - } - const matcher = outputMatcher.lineMatcher; const linesToCheck = typeof matcher === 'string' ? 1 : countNewLines(matcher); const lines: string[] = []; - if (outputMatcher?.anchor === 'bottom') { + if (outputMatcher.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { let wrappedLineStart = i; const wrappedLineEnd = i; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index a7f3c931277..94377a2a85b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -12,7 +12,7 @@ import { OperatingSystem } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IKeyMods } from 'vs/platform/quickinput/common/quickInput'; -import { IMarkProperties, ITerminalCapabilityStore, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { IMarkProperties, ITerminalCapabilityStore, ITerminalCommand, ITerminalOutputMatcher } from 'vs/platform/terminal/common/capabilities/capabilities'; import { IExtensionTerminalProfile, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; @@ -20,7 +20,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import { ITerminalQuickFix } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalOutputMatcher, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { INavigationMode, IRegisterContributedProfileArgs, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalFont, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IMarker } from 'xterm'; diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 319de723435..7d3d05d5e16 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -13,7 +13,7 @@ import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/e import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IMarkProperties, ISerializedCommandDetectionCapability, ITerminalCapabilityStore, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { IMarkProperties, ISerializedCommandDetectionCapability, ITerminalCapabilityStore, ITerminalOutputMatcher, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IProcessDetails } from 'vs/platform/terminal/common/terminalProcess'; @@ -96,30 +96,6 @@ export interface IShellLaunchConfigResolveOptions { allowAutomationShell?: boolean; } -/** - * A matcher that runs on a sub-section of a terminal command's output - */ -export interface ITerminalOutputMatcher { - /** - * A string or regex to match against the unwrapped line. If this is a regex with the multiline - * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1. - */ - lineMatcher: string | RegExp; - /** - * Which side of the output to anchor the {@link offset} and {@link length} against. - */ - anchor: 'top' | 'bottom'; - /** - * How far from either the top or the bottom of the butter to start matching against. - */ - offset: number; - /** - * The number of rows to match against, this should be as small as possible for performance - * reasons. - */ - length: number; -} - export interface ITerminalBackend { readonly remoteAuthority: string | undefined; diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts index 4aaa1f4fedf..528ca7290a2 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts @@ -17,7 +17,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalBuiltinLinkType } from 'vs/workbench/contrib/terminal/browser/links/links'; import { TerminalLocalFileLinkOpener, TerminalLocalFolderInWorkspaceLinkOpener, TerminalSearchLinkOpener } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners'; -import { TerminalCapability, ITerminalCommand, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { TerminalCapability, ITerminalCommand, IXtermMarker, ITerminalOutputMatcher } from 'vs/platform/terminal/common/capabilities/capabilities'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -25,7 +25,6 @@ import { TestContextService } from 'vs/workbench/test/common/workbenchTestServic import { Terminal } from 'xterm'; import { IFileQuery, ISearchComplete, ISearchService } from 'vs/workbench/services/search/common/search'; import { SearchService } from 'vs/workbench/services/search/common/searchService'; -import { ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/common/terminal'; export interface ITerminalLinkActivationResult { source: 'editor' | 'search'; diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 415a9d0663a..f786a336129 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -11,13 +11,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { ITerminalCommand, ITerminalOutputMatcher, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; -import { ITerminalOutputMatcher } from 'vs/workbench/contrib/terminal/common/terminal'; import { Terminal } from 'xterm'; suite('QuickFixAddon', () => { From a2fe848791fb61cb1fb41baa8f0bf2a7f60266d0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 29 Sep 2022 14:50:07 +0200 Subject: [PATCH 209/599] set `git.mergeChanges` context key for all repos, not just one (#162339) fixes https://github.com/microsoft/vscode/issues/162224 --- extensions/git/src/model.ts | 17 ++++++++++++++++- extensions/git/src/repository.ts | 3 --- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index c10a9d6a193..14ee4d66e74 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -450,7 +450,21 @@ export class Model implements IRemoteSourcePublisherRegistry, IPostCommitCommand .forEach(p => this.eventuallyScanPossibleGitRepository(p)); }; - const statusListener = repository.onDidRunGitStatus(checkForSubmodules); + const updateMergeChanges = () => { + // set mergeChanges context + const mergeChanges: Uri[] = []; + for (const { repository } of this.openRepositories.values()) { + for (const state of repository.mergeGroup.resourceStates) { + mergeChanges.push(state.resourceUri); + } + } + commands.executeCommand('setContext', 'git.mergeChanges', mergeChanges); + }; + + const statusListener = repository.onDidRunGitStatus(() => { + checkForSubmodules(); + updateMergeChanges(); + }); checkForSubmodules(); const dispose = () => { @@ -466,6 +480,7 @@ export class Model implements IRemoteSourcePublisherRegistry, IPostCommitCommand const openRepository = { repository, dispose }; this.openRepositories.push(openRepository); + updateMergeChanges(); this._onDidOpenRepository.fire(repository); } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index d622fd23c87..83120afcdc5 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -2103,9 +2103,6 @@ export class Repository implements Disposable { // set count badge this.setCountBadge(); - // set mergeChanges context - commands.executeCommand('setContext', 'git.mergeChanges', merge.map(item => item.resourceUri)); - this._onDidChangeStatus.fire(); this._sourceControl.commitTemplate = await this.getInputTemplate(); From cdb2e2c343c65e7ab2b37d2bfd7eba5b0fca3c71 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 15:06:32 +0200 Subject: [PATCH 210/599] Addresses #161587 --- .../contrib/mergeEditor/browser/mergeEditorInputModel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index 5882c9818aa..a7db1a6481e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -18,7 +18,7 @@ import { localize } from 'vs/nls'; import { ConfirmResult, IDialogOptions, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IRevertOptions } from 'vs/workbench/common/editor'; +import { IRevertOptions, SaveSourceRegistry } from 'vs/workbench/common/editor'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { conflictMarkers } from 'vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController'; @@ -269,6 +269,8 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa ) { } + private static readonly FILE_SAVED_SOURCE = SaveSourceRegistry.registerSource('merge-editor.source', localize('merge-editor.source', "Before Resolving Conflicts In Merge Editor")); + public async createInputModel(args: MergeEditorArgs): Promise { const store = new DisposableStore(); @@ -302,7 +304,7 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa throw new BugIndicatingError(); } // So that "Don't save" does revert the file - await resultTextFileModel.save(); + await resultTextFileModel.save({ source: WorkspaceMergeEditorModeFactory.FILE_SAVED_SOURCE }); const lines = resultTextFileModel.textEditorModel!.getLinesContent(); const hasConflictMarkers = lines.some(l => l.startsWith(conflictMarkers.start)); From b4b96c847fa600733752c7cafec81169b8d67695 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 29 Sep 2022 15:23:51 +0200 Subject: [PATCH 211/599] prevent hiding of actions of the global panel part menu (#162335) https://github.com/microsoft/vscode/issues/162006 --- src/vs/workbench/browser/parts/panel/panelPart.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index d3dfaf39c5f..6b8e20f84f4 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -45,7 +45,7 @@ import { IPartOptions } from 'vs/workbench/browser/part'; import { StringSHA1 } from 'vs/base/common/hash'; import { URI } from 'vs/base/common/uri'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; -import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; interface ICachedPanel { id: string; @@ -110,7 +110,7 @@ export abstract class BasePanelPart extends CompositePart impleme private compositeBar: CompositeBar; private readonly compositeActions = new Map(); - private globalToolBar: WorkbenchToolBar | undefined; + private globalToolBar: ToolBar | undefined; private globalActions: CompositeMenuActions; private readonly panelDisposables: Map = new Map(); @@ -549,13 +549,12 @@ export abstract class BasePanelPart extends CompositePart impleme const globalTitleActionsContainer = element.appendChild($('.global-actions')); // Global Actions Toolbar - this.globalToolBar = this._register(this.instantiationService.createInstance(WorkbenchToolBar, globalTitleActionsContainer, { + this.globalToolBar = this._register(new ToolBar(globalTitleActionsContainer, this.contextMenuService, { actionViewItemProvider: action => this.actionViewItemProvider(action), orientation: ActionsOrientation.HORIZONTAL, getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), - toggleMenuTitle: localize('moreActions', "More Actions..."), - resetMenu: this.globalActions.menuId + toggleMenuTitle: localize('moreActions', "More Actions...") })); this.updateGlobalToolbarActions(); From 13683b13cadf202481c4d44e01fb2a4c5f601b44 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Thu, 29 Sep 2022 13:24:53 +0000 Subject: [PATCH 212/599] Improve wording in protocol url open dialog (#162273) --- src/vs/workbench/browser/window.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index 52dcef61e86..4e4de25cf52 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -210,11 +210,16 @@ export class BrowserWindow extends Disposable { [ localize('openExternalDialogButtonRetry', "Try again"), localize('openExternalDialogButtonInstall', "Install {0}", this.productService.nameLong), - localize('openExternalDialogButtonContinue', "Continue here") + localize('openExternalDialogButtonCancel', "Cancel") ], { cancelId: 2, - detail: localize('openExternalDialogDetail', "We tried opening {0} on your computer.", this.productService.nameLong) + detail: localize( + 'openExternalDialogDetail.v2', + "We launched {0} on your computer.\n\nIf {1} did not launch, try again or install it below.", + this.productService.nameLong, + this.productService.nameLong, + ) }, ); From 2df70ee36682d9eaa3124990d13f0af93d0294b7 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 15:41:09 +0200 Subject: [PATCH 213/599] Fixes #162042 by removing CodeLens icons from merge editor actions (#162345) --- .../mergeEditor/browser/view/conflictActions.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index 57aed4fda5e..a5341171ff2 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -104,7 +104,7 @@ export class ConflictActionsFactory extends Disposable { if (!state.conflicting && !state.isInputIncluded(inputNumber)) { result.push( !state.isInputIncluded(inputNumber) - ? command(localize('accept', "$(pass) Accept {0}", inputData.title), async () => { + ? command(localize('accept', "Accept {0}", inputData.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -114,7 +114,7 @@ export class ConflictActionsFactory extends Disposable { ); }); }) - : command(localize('remove', "$(error) Remove {0}", inputData.title), async () => { + : command(localize('remove', "Remove {0}", inputData.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -129,7 +129,7 @@ export class ConflictActionsFactory extends Disposable { if (modifiedBaseRange.canBeCombined && state.isEmpty) { result.push( state.input1 && state.input2 - ? command(localize('removeBoth', "$(error) Remove Both"), async () => { + ? command(localize('removeBoth', "Remove Both"), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -139,7 +139,7 @@ export class ConflictActionsFactory extends Disposable { ); }); }) - : command(localize('acceptBoth', "$(pass) Accept Both"), async () => { + : command(localize('acceptBoth', "Accept Both"), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -204,7 +204,7 @@ export class ConflictActionsFactory extends Disposable { const stateToggles: IContentWidgetAction[] = []; if (state.input1) { - result.push(command(localize('remove', "$(error) Remove {0}", model.input1.title), async () => { + result.push(command(localize('remove', "Remove {0}", model.input1.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -217,7 +217,7 @@ export class ConflictActionsFactory extends Disposable { ); } if (state.input2) { - result.push(command(localize('remove', "$(error) Remove {0}", model.input2.title), async () => { + result.push(command(localize('remove', "Remove {0}", model.input2.title), async () => { transaction((tx) => { model.setState( modifiedBaseRange, @@ -238,7 +238,7 @@ export class ConflictActionsFactory extends Disposable { if (state.conflicting) { result.push( - command(localize('resetToBase', "$(error) Reset to base"), async () => { + command(localize('resetToBase', "Reset to base"), async () => { transaction((tx) => { model.setState( modifiedBaseRange, From 12637cf568a7bfc4e3357aca5194a7cdcb1b2350 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 16:44:29 +0200 Subject: [PATCH 214/599] Addresses #162191 by not hiding conflict markers in the result editor (#162355) --- .../mergeEditor/browser/view/editors/resultCodeEditorView.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index eb56c55a996..327707bed0b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -16,7 +16,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { MergeMarkersController } from 'vs/workbench/contrib/mergeEditor/browser/mergeMarkers/mergeMarkersController'; import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange'; import { applyObservableDecorations, join } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors'; @@ -41,8 +40,6 @@ export class ResultCodeEditorView extends CodeEditorView { this._register(toDisposable(() => isMergeResultEditor.reset())); }); - this._register(new MergeMarkersController(this.editor, this.viewModel)); - this.htmlElements.gutterDiv.style.width = '5px'; this._register( From 43d851d1b0fcd99c2944432ce91ecb47c21c8b11 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 28 Sep 2022 12:22:15 +0200 Subject: [PATCH 215/599] Fixes #162028 by improving merge editor tooltips --- .../browser/view/conflictActions.ts | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index a5341171ff2..ca0a12ec2d5 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -113,7 +113,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }) + }, localize('acceptTooltip', "Accept {0} in the result document.", inputData.title)) : command(localize('remove', "Remove {0}", inputData.title), async () => { transaction((tx) => { model.setState( @@ -123,7 +123,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }), + }, localize('removeTooltip', "Remove {0} from the result document.", inputData.title)), ); if (modifiedBaseRange.canBeCombined && state.isEmpty) { @@ -138,7 +138,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }) + }, localize('removeBothTooltip', "Remove both changes from the result document.")) : command(localize('acceptBoth', "Accept Both"), async () => { transaction((tx) => { model.setState( @@ -150,7 +150,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }, localize('acceptBothTooltip', "Both changes can be combined automatically")), + }, localize('acceptBothTooltip', "Accept an automatic combination of both sides in the result document.")), ); } } @@ -161,10 +161,11 @@ export class ConflictActionsFactory extends Disposable { createResultWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange): IContentWidget { - function command(title: string, action: () => Promise): IContentWidgetAction { + function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { return { text: title, - action + action, + tooltip }; } @@ -178,12 +179,15 @@ export class ConflictActionsFactory extends Disposable { if (state.conflicting) { result.push({ text: localize('manualResolution', "Manual Resolution"), - tooltip: localize('manualResolutionTooltip', "This conflict has been resolved manually"), + tooltip: localize('manualResolutionTooltip', "This conflict has been resolved manually."), }); } else if (state.isEmpty) { result.push({ text: localize('noChangesAccepted', 'No Changes Accepted'), - tooltip: localize('noChangesAcceptedTooltip', "The current resolution of this conflict equals the common ancestor of both the right and left changes."), + tooltip: localize( + 'noChangesAcceptedTooltip', + 'The current resolution of this conflict equals the common ancestor of both the right and left changes.' + ), }); } else { @@ -213,7 +217,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }), + }, localize('removeTooltip', "Remove {0} from the result document.", model.input1.title)), ); } if (state.input2) { @@ -226,7 +230,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }), + }, localize('removeTooltip', "Remove {0} from the result document.", model.input2.title)), ); } if (state.input2First) { @@ -247,7 +251,7 @@ export class ConflictActionsFactory extends Disposable { tx ); }); - }) + }, localize('resetToBaseTooltip', "Reset this conflict to the common ancestor of both the right and left changes.")), ); } return result; From f8ba3353d1131b7bcfaa6306ea1c74bdb150edce Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 29 Sep 2022 17:01:56 +0200 Subject: [PATCH 216/599] #161791 better fix - use current profile (#162357) --- .../extensionManagement/common/webExtensionManagementService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index 8cc76238682..a0e3bcd903e 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -65,7 +65,7 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe } private filterEvent({ profileLocation, applicationScoped }: { profileLocation?: URI; applicationScoped?: boolean }): boolean { - profileLocation = profileLocation ?? this.userDataProfilesService.defaultProfile.extensionsResource; + profileLocation = profileLocation ?? this.userDataProfileService.currentProfile.extensionsResource; return applicationScoped || this.uriIdentityService.extUri.isEqual(this.userDataProfileService.currentProfile.extensionsResource, profileLocation); } From f1d4fced59311fe26b512cb1bf39fff79dac8783 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 17:03:48 +0200 Subject: [PATCH 217/599] Fixes #162195 (#162353) --- .../contrib/mergeEditor/browser/view/conflictActions.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index a5341171ff2..32ba15bd4eb 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -86,6 +86,10 @@ export class ConflictActionsFactory extends Disposable { } const items = derived('items', reader => { + if (!viewModel.model.hasBaseRange(modifiedBaseRange)) { + return []; + } + const state = viewModel.model.getState(modifiedBaseRange).read(reader); const handled = viewModel.model.isHandled(modifiedBaseRange).read(reader); const model = viewModel.model; From 112a03b39b21224a00a44727de3a87455a5f9957 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 29 Sep 2022 17:04:43 +0200 Subject: [PATCH 218/599] Don't allow negative numbers in view badges (#162359) --- src/vs/workbench/api/common/extHostTreeViews.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 3ade5261221..9a76fc9daa7 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -124,7 +124,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { set badge(badge: vscode.ViewBadge | undefined) { if (ExtHostViewBadge.isViewBadge(badge)) { treeView.badge = { - value: Math.floor(badge.value), + value: Math.floor(Math.abs(badge.value)), tooltip: badge.tooltip }; } From 5c168e7c3907a95135a8d95436832094dc380358 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 29 Sep 2022 17:13:37 +0200 Subject: [PATCH 219/599] use max border radius to show like a pill (#162360) --- .../browser/parts/activitybar/media/activityaction.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 395d1193e74..795c7e16267 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -184,7 +184,7 @@ justify-content: center; align-items: center; font-size: 14px; - border-radius: 8px; + border-radius: 10px; } /* Right aligned */ From 2b712ceeefc3e46e29dc0f8bb2ab54ccc44652bf Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Thu, 29 Sep 2022 17:14:07 +0200 Subject: [PATCH 220/599] Adding context menu on the sticky line --- .../browser/link/clickLinkGesture.ts | 2 ++ .../browser/stickyScrollActions.ts | 1 + .../browser/stickyScrollController.ts | 25 +++++++++++++++++++ .../browser/stickyScrollWidget.ts | 2 +- src/vs/platform/actions/common/actions.ts | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts b/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts index c11b578b773..78b3bdbfed5 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts @@ -25,9 +25,11 @@ export class ClickLinkMouseEvent { public readonly hasTriggerModifier: boolean; public readonly hasSideBySideModifier: boolean; public readonly isNoneOrSingleMouseDown: boolean; + public readonly hasRightClick: boolean; constructor(source: IEditorMouseEvent, opts: ClickLinkOptions) { this.target = source.target; + this.hasRightClick = source.event.rightButton; this.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier); this.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier); this.isNoneOrSingleMouseDown = (source.event.detail <= 1); diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts index a1c6cac5baf..087aa6bc43e 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts @@ -25,6 +25,7 @@ export class ToggleStickyScroll extends Action2 { menu: [ { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 6 }, + { id: MenuId.StickyScroll } ] }); } diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts index 47fbfec59b9..cecddbb5034 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts @@ -12,6 +12,12 @@ import { StickyScrollWidget, StickyScrollWidgetState } from './stickyScrollWidge import { StickyLineCandidateProvider, StickyRange } from './stickyScrollProvider'; import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import * as dom from 'vs/base/browser/dom'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IAction } from 'vs/base/common/actions'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class StickyScrollController extends Disposable implements IEditorContribution { @@ -26,6 +32,9 @@ export class StickyScrollController extends Disposable implements IEditorContrib _editor: ICodeEditor, @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, @IInstantiationService _instaService: IInstantiationService, + @IContextMenuService private readonly _contextMenuService: IContextMenuService, + @IMenuService private readonly _menuService: IMenuService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, ) { super(); this._editor = _editor; @@ -41,6 +50,9 @@ export class StickyScrollController extends Disposable implements IEditorContrib } })); this.readConfiguration(); + this._register(dom.addDisposableListener(this._stickyScrollWidget.getDomNode(), dom.EventType.CONTEXT_MENU, async (event: MouseEvent) => { + this.onContextMenu(event); + })); } public get stickyScrollCandidateProvider() { @@ -51,6 +63,19 @@ export class StickyScrollController extends Disposable implements IEditorContrib return this._widgetState; } + private onContextMenu(event: MouseEvent) { + const menu = this._menuService.createMenu(MenuId.StickyScroll, this._contextKeyService); + const actions: IAction[] = []; + createAndFillInContextMenuActions(menu, undefined, actions); + this._contextMenuService.showContextMenu({ + getActions: () => actions, + getAnchor: () => event, + onHide: () => { + menu.dispose(); + } + }); + } + private readConfiguration() { const options = this._editor.getOption(EditorOption.stickyScroll); if (options.enabled === false) { diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts index bc15f45478d..777154b9891 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts @@ -152,7 +152,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { this._editor.revealPosition({ lineNumber: this._hoverOnLine, column: 1 }); } this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, { uri: this._editor.getModel()!.uri, range: this._stickyRangeProjectedOnEditor } as Location); - } else { + } else if (!e.hasRightClick) { // Normal click this._editor.revealPosition({ lineNumber: this._hoverOnLine, column: 1 }); } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index ea836c330a6..3cf5d70339f 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -103,6 +103,7 @@ export class MenuId { static readonly SearchContext = new MenuId('SearchContext'); static readonly StatusBarWindowIndicatorMenu = new MenuId('StatusBarWindowIndicatorMenu'); static readonly StatusBarRemoteIndicatorMenu = new MenuId('StatusBarRemoteIndicatorMenu'); + static readonly StickyScroll = new MenuId('StickyScrollMenu'); static readonly TestItem = new MenuId('TestItem'); static readonly TestItemGutter = new MenuId('TestItemGutter'); static readonly TestPeekElement = new MenuId('TestPeekElement'); From 46afa5b1080944f9e06557930367d8b5475e6453 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 29 Sep 2022 17:19:06 +0200 Subject: [PATCH 221/599] Fixes #162043 by renaming "Accept Merge" to "Complete Merge" (#162361) --- extensions/git/package.nls.json | 2 +- extensions/git/src/commands.ts | 4 ++-- .../contrib/mergeEditor/browser/commands/commands.ts | 6 +++--- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 57e36d3422e..cba41774355 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -103,7 +103,7 @@ "command.api.getRepositories": "Get Repositories", "command.api.getRepositoryState": "Get Repository State", "command.api.getRemoteSources": "Get Remote Sources", - "command.git.acceptMerge": "Accept Merge", + "command.git.acceptMerge": "Complete Merge", "command.git.openMergeEditor": "Resolve in Merge Editor", "command.git.runGitMerge": "Compute Conflicts With Git", "command.git.runGitMergeDiff3": "Compute Conflicts With Git (Diff3)", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 6591bf1bef3..5a6850f1efd 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1162,7 +1162,7 @@ export class CommandCenter { const repository = this.model.getRepository(uri); if (!repository) { - console.log(`FAILED to accept merge because uri ${uri.toString()} doesn't belong to any repository`); + console.log(`FAILED to complete merge because uri ${uri.toString()} doesn't belong to any repository`); return; } @@ -1183,7 +1183,7 @@ export class CommandCenter { // make sure to save the merged document const doc = workspace.textDocuments.find(doc => doc.uri.toString() === uri.toString()); if (!doc) { - console.log(`FAILED to accept merge because uri ${uri.toString()} doesn't match a document`); + console.log(`FAILED to complete merge because uri ${uri.toString()} doesn't match a document`); return; } if (doc.isDirty) { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 73882208428..016ff819756 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -616,9 +616,9 @@ export class AcceptMerge extends MergeEditorAction2 { title: { value: localize( 'mergeEditor.acceptMerge', - 'Accept Merge' + 'Complete Merge' ), - original: 'Accept Merge', + original: 'Complete Merge', }, f1: false, precondition: ctxIsMergeEditor @@ -633,7 +633,7 @@ export class AcceptMerge extends MergeEditorAction2 { const confirmResult = await dialogService.confirm({ type: 'info', message: localize('mergeEditor.acceptMerge.unhandledConflicts', "There are still unhandled conflicts. Are you sure you want to accept the merge?"), - primaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.accept', "Accept merge with unhandled conflicts"), + primaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.accept', "Complete merge with unhandled conflicts"), secondaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.cancel', "Cancel"), }); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 58295101d2f..f1fbbfc5079 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -1152,7 +1152,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: 'workbench.userDataSync.actions.acceptMerges', - title: localize('accept merges title', "Accept Merge"), + title: localize('complete merges title', "Complete Merge"), menu: [{ id: MenuId.EditorContent, when: ContextKeyExpr.and(ctxIsMergeResultEditor, ContextKeyExpr.regex(ctxMergeBaseUri.key, new RegExp(`^${USER_DATA_SYNC_SCHEME}:`))), From 82ac904296d00dca70138f8c260e183bcd5e309e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 29 Sep 2022 17:45:27 +0200 Subject: [PATCH 222/599] add run code web launches (#162364) --- .vscode/launch.json | 27 +++++++++++++++++++++++++++ .vscode/tasks.json | 22 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index ab98af7d3d2..d0c0ed97f49 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -322,6 +322,33 @@ "order": 3 } }, + { + "type": "chrome", + "request": "launch", + "outFiles": [], + "perScriptSourcemaps": "yes", + "name": "VS Code Web (Chrome)", + "url": "http://localhost:8080", + "preLaunchTask": "Run code web", + "presentation": { + "group": "0_vscode", + "order": 3 + } + }, + { + "type": "msedge", + "request": "launch", + "outFiles": [], + "perScriptSourcemaps": "yes", + "name": "VS Code Web (Edge)", + "url": "http://localhost:8080", + "pauseForSourceMap": false, + "preLaunchTask": "Run code web", + "presentation": { + "group": "0_vscode", + "order": 3 + } + }, { "type": "node", "request": "launch", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 885f825cc2e..59b1893c293 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -203,6 +203,28 @@ "reveal": "never" } }, + { + "type": "shell", + "command": "./scripts/code-web.sh", + "windows": { + "command": ".\\scripts\\code-web.bat" + }, + "args": ["--port", "8080", "--browser", "none"], + "label": "Run code web", + "isBackground": true, + "problemMatcher": { + "pattern": { + "regexp": "" + }, + "background": { + "beginsPattern": ".*node .*", + "endsPattern": "Listening on .*" + } + }, + "presentation": { + "reveal": "never" + } + }, { "type": "npm", "script": "eslint", From 9a25983e9df8cafa9543072f8bcee0fa5df86bd7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 29 Sep 2022 17:54:03 +0200 Subject: [PATCH 223/599] for now disable toolbar animation (#162368) https://github.com/microsoft/vscode/issues/162292 --- src/vs/platform/actions/browser/toolbar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index 2117bb57c00..3886e3e5556 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -194,7 +194,7 @@ export class WorkbenchToolBar extends ToolBar { } } - this.getElement().classList.toggle('config', true); + // this.getElement().classList.toggle('config', true); this._contextMenuService.showContextMenu({ getAnchor: () => e, From 203b26d182c608f796152762bb3656b797751a16 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 29 Sep 2022 18:31:10 +0200 Subject: [PATCH 224/599] Fixes #161731 (#162372) --- src/vs/base/browser/globalPointerMoveMonitor.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/globalPointerMoveMonitor.ts b/src/vs/base/browser/globalPointerMoveMonitor.ts index d5c432114d7..0348db2528f 100644 --- a/src/vs/base/browser/globalPointerMoveMonitor.ts +++ b/src/vs/base/browser/globalPointerMoveMonitor.ts @@ -64,7 +64,17 @@ export class GlobalPointerMoveMonitor implements IDisposable { try { initialElement.setPointerCapture(pointerId); this._hooks.add(toDisposable(() => { - initialElement.releasePointerCapture(pointerId); + try { + initialElement.releasePointerCapture(pointerId); + } catch (err) { + // See https://github.com/microsoft/vscode/issues/161731 + // + // `releasePointerCapture` sometimes fails when being invoked with the exception: + // DOMException: Failed to execute 'releasePointerCapture' on 'Element': + // No active pointer with the given id is found. + // + // There's no need to do anything in case of failure + } })); } catch (err) { // See https://github.com/microsoft/vscode/issues/144584 From b891aa212a3644cc345d061c63a67ba51080cace Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Thu, 29 Sep 2022 16:51:36 +0000 Subject: [PATCH 225/599] Don't show account badge if user already actioned Edit Sessions via Continue On once (#162373) Fix https://github.com/microsoft/vscode/issues/162301 --- .../browser/editSessions.contribution.ts | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 15bc2773b6a..af450bcd68e 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -144,22 +144,33 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo }; this.telemetryService.publicLog2('editSessions.continue.resume'); + const shouldAutoResumeOnReload = this.configurationService.getValue('workbench.editSessions.autoResume') === 'onReload'; + if (this.environmentService.editSessionId !== undefined) { this.logService.info(`Resuming edit session, reason: found editSessionId ${this.environmentService.editSessionId} in environment service...`); await this.resumeEditSession(this.environmentService.editSessionId).finally(() => this.environmentService.editSessionId = undefined); - } else if ( - this.configurationService.getValue('workbench.editSessions.autoResume') === 'onReload' && - this.editSessionsStorageService.isSignedIn - ) { + } else if (shouldAutoResumeOnReload && this.editSessionsStorageService.isSignedIn) { this.logService.info('Resuming edit session, reason: edit sessions enabled...'); // Attempt to resume edit session based on edit workspace identifier // Note: at this point if the user is not signed into edit sessions, // we don't want them to be prompted to sign in and should just return early await this.resumeEditSession(undefined, true); - } else { + } else if (shouldAutoResumeOnReload) { // The application has previously launched via a protocol URL Continue On flow const hasApplicationLaunchedFromContinueOnFlow = this.storageService.getBoolean(EditSessionsContribution.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, StorageScope.APPLICATION, false); + const handlePendingEditSessions = () => { + // display a badge in the accounts menu but do not prompt the user to sign in again + this.updateAccountsMenuBadge(); + // attempt a resume if we are in a pending state and the user just signed in + const disposable = this.editSessionsStorageService.onDidSignIn(async () => { + disposable.dispose(); + this.resumeEditSession(undefined, true); + this.storageService.remove(EditSessionsContribution.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, StorageScope.APPLICATION); + this.environmentService.continueOn = undefined; + }); + }; + if ((this.environmentService.continueOn !== undefined) && !this.editSessionsStorageService.isSignedIn && // and user has not yet been prompted to sign in on this machine @@ -170,17 +181,14 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo if (this.editSessionsStorageService.isSignedIn) { await this.resumeEditSession(undefined, true); } else { - this.updateAccountsMenuBadge(); + handlePendingEditSessions(); } // store the fact that we prompted the user } else if (!this.editSessionsStorageService.isSignedIn && // and user has been prompted to sign in on this machine hasApplicationLaunchedFromContinueOnFlow === true ) { - // display a badge in the accounts menu but do not prompt the user to sign in again - this.updateAccountsMenuBadge(); - // attempt a resume if we are in a pending state and the user just signed in - this._register(this.editSessionsStorageService.onDidSignIn(async () => this.resumeEditSession(undefined, true))); + handlePendingEditSessions(); } } From 7d3027e43cfa93effd21be49419461638f11df19 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 29 Sep 2022 18:58:01 +0200 Subject: [PATCH 226/599] Fixes #161723 (#162374) --- src/vs/base/parts/ipc/node/ipc.net.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index bff8e41d8e5..810ba41d106 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -32,6 +32,9 @@ export class NodeSocket implements ISocket { public readonly debugLabel: string; public readonly socket: Socket; private readonly _errorListener: (err: any) => void; + private readonly _closeListener: (hadError: boolean) => void; + private readonly _endListener: () => void; + private _canWrite = true; public traceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void { SocketDiagnostics.traceSocketEvent(this.socket, this.debugLabel, type, data); @@ -57,10 +60,24 @@ export class NodeSocket implements ISocket { } }; this.socket.on('error', this._errorListener); + + this._closeListener = (hadError: boolean) => { + this.traceSocketEvent(SocketDiagnosticsEventType.Close, { hadError }); + this._canWrite = false; + }; + this.socket.on('close', this._closeListener); + + this._endListener = () => { + this.traceSocketEvent(SocketDiagnosticsEventType.NodeEndReceived); + this._canWrite = false; + }; + this.socket.on('end', this._endListener); } public dispose(): void { this.socket.off('error', this._errorListener); + this.socket.off('close', this._closeListener); + this.socket.off('end', this._endListener); this.socket.destroy(); } @@ -77,7 +94,6 @@ export class NodeSocket implements ISocket { public onClose(listener: (e: SocketCloseEvent) => void): IDisposable { const adapter = (hadError: boolean) => { - this.traceSocketEvent(SocketDiagnosticsEventType.Close, { hadError }); listener({ type: SocketCloseEventType.NodeSocketCloseEvent, hadError: hadError, @@ -92,7 +108,6 @@ export class NodeSocket implements ISocket { public onEnd(listener: () => void): IDisposable { const adapter = () => { - this.traceSocketEvent(SocketDiagnosticsEventType.NodeEndReceived); listener(); }; this.socket.on('end', adapter); @@ -103,7 +118,7 @@ export class NodeSocket implements ISocket { public write(buffer: VSBuffer): void { // return early if socket has been destroyed in the meantime - if (this.socket.destroyed) { + if (this.socket.destroyed || !this._canWrite) { return; } From 261fc9995535a1fc92eeda91fd4a7fb6911c66a5 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 29 Sep 2022 10:14:16 -0700 Subject: [PATCH 227/599] Fixes #162243 (#162376) --- src/vs/base/parts/quickinput/browser/quickInput.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index 41e7da28efa..ec55bbc810b 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -1166,11 +1166,14 @@ class InputBox extends QuickInput implements IInputBox { if (!this.visible) { return; } + + this.ui.container.classList.remove('hidden-input'); const visibilities: Visibilities = { title: !!this.title || !!this.step || !!this.buttons.length, description: !!this.description || !!this.step, inputBox: true, message: true }; + this.ui.setVisibilities(visibilities); super.update(); if (this.ui.inputBox.value !== this.value) { @@ -1186,7 +1189,6 @@ class InputBox extends QuickInput implements IInputBox { if (this.ui.inputBox.password !== this.password) { this.ui.inputBox.password = this.password; } - } } From d05038818904543686eff672d5afe3b2b04d6f4a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 29 Sep 2022 11:03:34 -0700 Subject: [PATCH 228/599] Remove unused disposable in template (#162271) --- src/vs/base/browser/ui/selectBox/selectBoxCustom.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index cc09126b530..cfdaca03d75 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -15,7 +15,7 @@ import { ISelectBoxDelegate, ISelectBoxOptions, ISelectBoxStyles, ISelectData, I import * as arrays from 'vs/base/common/arrays'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import 'vs/css!./selectBoxCustom'; @@ -31,7 +31,6 @@ interface ISelectListTemplateData { text: HTMLElement; detail: HTMLElement; decoratorRight: HTMLElement; - disposables: IDisposable[]; } class SelectListRenderer implements IListRenderer { @@ -40,7 +39,6 @@ class SelectListRenderer implements IListRenderer Date: Thu, 29 Sep 2022 11:33:45 -0700 Subject: [PATCH 229/599] fixes #160272 (#162358) * fixes #160272 * I guess this is how we do it --- src/vs/base/browser/ui/sash/sash.ts | 34 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 4bc8ff1b8ee..5cbf7e6f192 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -5,7 +5,7 @@ import { $, append, createStyleSheet, EventHelper, EventLike } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; -import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; +import { EventType, Gesture } from 'vs/base/browser/touch'; import { Delayer } from 'vs/base/common/async'; import { memoize } from 'vs/base/common/decorators'; import { Emitter, Event } from 'vs/base/common/event'; @@ -155,6 +155,7 @@ interface PointerEvent extends EventLike { readonly pageY: number; readonly altKey: boolean; readonly target: EventTarget | null; + readonly initialTarget?: EventTarget | undefined; } interface IPointerEventFactory { @@ -419,17 +420,22 @@ export class Sash extends Disposable { this._register(Gesture.addTarget(this.el)); - const onTouchStart = Event.map(this._register(new DomEmitter(this.el, EventType.Start)).event, e => ({ ...e, target: e.initialTarget ?? null })); + const onTouchStart = this._register(new DomEmitter(this.el, EventType.Start)).event; this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this.el)), this)); const onTap = this._register(new DomEmitter(this.el, EventType.Tap)).event; - const onDoubleTap = Event.map( - Event.filter( - Event.debounce(onTap, (res, event) => ({ event, count: (res?.count ?? 0) + 1 }), 250), - ({ count }) => count === 2 - ), - ({ event }) => ({ ...event, target: event.initialTarget ?? null }) - ); - this._register(onDoubleTap(this.onPointerDoublePress, this)); + + let doubleTapTimeout: any = undefined; + this._register(onTap(event => { + if (doubleTapTimeout) { + clearTimeout(doubleTapTimeout); + doubleTapTimeout = undefined; + this.onPointerDoublePress(event); + return; + } + + clearTimeout(doubleTapTimeout); + doubleTapTimeout = setTimeout(() => doubleTapTimeout = undefined, 250); + }, this)); if (typeof options.size === 'number') { this.size = options.size; @@ -645,12 +651,14 @@ export class Sash extends Disposable { } private getOrthogonalSash(e: PointerEvent): Sash | undefined { - if (!e.target || !(e.target instanceof HTMLElement)) { + const target = e.initialTarget ?? e.target; + + if (!target || !(target instanceof HTMLElement)) { return undefined; } - if (e.target.classList.contains('orthogonal-drag-handle')) { - return e.target.classList.contains('start') ? this.orthogonalStartSash : this.orthogonalEndSash; + if (target.classList.contains('orthogonal-drag-handle')) { + return target.classList.contains('start') ? this.orthogonalStartSash : this.orthogonalEndSash; } return undefined; From 9e099a8d79f806a5ef2909082bec4d3b047afc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 29 Sep 2022 12:26:05 -0700 Subject: [PATCH 230/599] List find + breadcrumb fixes (#162394) * fix list style overrides fixes #158824 * make sure breadcrumbs doesn't disappear when using tree find fixes #158767 --- src/vs/base/browser/ui/inputbox/inputBox.ts | 8 ++++---- src/vs/base/browser/ui/tree/abstractTree.ts | 7 ++++++- src/vs/platform/list/browser/listService.ts | 2 +- .../workbench/browser/parts/editor/breadcrumbsPicker.ts | 2 ++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index ae89cb33f38..a9f2b326c28 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -58,7 +58,7 @@ export interface IInputValidator { } export interface IMessage { - readonly content: string; + readonly content?: string; readonly formatContent?: boolean; // defaults to false readonly type?: MessageType; } @@ -396,7 +396,7 @@ export class InputBox extends Widget { const styles = this.stylesForType(this.message.type); this.element.style.border = styles.border ? `1px solid ${styles.border}` : ''; - if (this.hasFocus() || force) { + if (this.message.content && (this.hasFocus() || force)) { this._showMessage(); } } @@ -477,8 +477,8 @@ export class InputBox extends Widget { }; const spanElement = (this.message.formatContent - ? renderFormattedText(this.message.content, renderOptions) - : renderText(this.message.content, renderOptions)); + ? renderFormattedText(this.message.content!, renderOptions) + : renderText(this.message.content!, renderOptions)); spanElement.classList.add(this.classForType(this.message.type)); const styles = this.stylesForType(this.message.type); diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 3f8ae2b6737..aa74182dc21 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -996,7 +996,11 @@ class FindController implements IDisposable { const noMatches = this.filter.totalCount > 0 && this.filter.matchCount === 0; if (this.pattern && noMatches) { - this.widget?.showMessage({ type: MessageType.WARNING, content: localize('not found', "No elements found.") }); + if (this.tree.options.showNotFoundMessage ?? true) { + this.widget?.showMessage({ type: MessageType.WARNING, content: localize('not found', "No elements found.") }); + } else { + this.widget?.showMessage({ type: MessageType.WARNING }); + } } else { this.widget?.clearMessage(); } @@ -1062,6 +1066,7 @@ export interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions { readonly typeNavigationEnabled?: boolean; readonly typeNavigationMode?: TypeNavigationMode; readonly defaultFindMode?: TreeFindMode; + readonly showNotFoundMessage?: boolean; readonly smoothScrolling?: boolean; readonly horizontalScrolling?: boolean; readonly mouseWheelScrollSensitivity?: number; diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 197fb970f66..5fb143fc948 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -1291,7 +1291,7 @@ class WorkbenchTreeInternals { updateStyleOverrides(overrideStyles?: IColorMapping): void { dispose(this.styler); - this.styler = overrideStyles ? attachListStyler(this.tree, this.themeService, overrideStyles) : Disposable.None; + this.styler = attachListStyler(this.tree, this.themeService, overrideStyles); } dispose(): void { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index e6535720005..28894f417fe 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -381,6 +381,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { identityProvider: new FileIdentityProvider(), keyboardNavigationLabelProvider: new FileNavigationLabelProvider(), accessibilityProvider: this._instantiationService.createInstance(FileAccessibilityProvider), + showNotFoundMessage: false, overrideStyles: { listBackground: breadcrumbsPickerBackground }, @@ -474,6 +475,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { collapseByDefault: true, expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, + showNotFoundMessage: false } ); } From 3f1bf5fa8deacc08f6195f4b5dda7b323f20362b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 29 Sep 2022 12:36:07 -0700 Subject: [PATCH 231/599] list find: remember last input (#162398) fixes #156248 --- src/vs/base/browser/ui/tree/abstractTree.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index aa74182dc21..b77d5e9e5dd 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -695,6 +695,14 @@ class FindWidget extends Disposable { this.findInput.inputBox.setPlaceHolder(mode === TreeFindMode.Filter ? localize('type to filter', "Type to filter") : localize('type to search', "Type to search")); } + get value(): string { + return this.findInput.inputBox.value; + } + + set value(value: string) { + this.findInput.inputBox.value = value; + } + private readonly modeToggle: ModeToggle; private readonly findInput: FindInput; private readonly actionbar: ActionBar; @@ -876,6 +884,7 @@ class FindController implements IDisposable { private _pattern = ''; get pattern(): string { return this._pattern; } + private previousPattern = ''; private _mode: TreeFindMode; get mode(): TreeFindMode { return this._mode; } @@ -940,6 +949,9 @@ class FindController implements IDisposable { this.widget.layout(this.width); this.widget.focus(); + this.widget.value = this.previousPattern; + this.widget.select(); + this._onDidChangeOpenState.fire(true); } @@ -953,6 +965,7 @@ class FindController implements IDisposable { this.enabledDisposables.dispose(); this.enabledDisposables = new DisposableStore(); + this.previousPattern = this.pattern; this.onDidChangeValue(''); this.tree.domFocus(); From 95b4a71a2ce00b7910b2a11b78f422ca4e13922c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 29 Sep 2022 13:04:46 -0700 Subject: [PATCH 232/599] make sure tree renderers share indent guides collection (#162400) fixes #161607 --- src/vs/base/browser/ui/tree/abstractTree.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index b77d5e9e5dd..9b7a75ba596 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -337,7 +337,6 @@ class TreeRenderer implements IListRenderer private hideTwistiesOfChildlessElements: boolean = false; private shouldRenderIndentGuides: boolean = false; - private renderedIndentGuides = new SetMap, HTMLDivElement>(); private activeIndentNodes = new Set>(); private indentGuidesDisposable: IDisposable = Disposable.None; @@ -348,6 +347,7 @@ class TreeRenderer implements IListRenderer private modelProvider: () => ITreeModel, onDidChangeCollapseState: Event>, private activeNodes: Collection>, + private renderedIndentGuides: SetMap, HTMLDivElement>, options: ITreeRendererOptions = {} ) { this.templateId = renderer.templateId; @@ -1448,7 +1448,8 @@ export abstract class AbstractTree implements IDisposable const onDidChangeCollapseStateRelay = new Relay>(); const onDidChangeActiveNodes = new Relay[]>(); const activeNodes = this.disposables.add(new EventCollection(onDidChangeActiveNodes.event)); - this.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options)); + const renderedIndentGuides = new SetMap, HTMLDivElement>(); + this.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, renderedIndentGuides, _options)); for (const r of this.renderers) { this.disposables.add(r); } From 6e040c2f4ae6606315bf88572e5e16ffb1cc0ead Mon Sep 17 00:00:00 2001 From: Ian Huff Date: Thu, 29 Sep 2022 13:05:24 -0700 Subject: [PATCH 233/599] Allow for a controller to be both selected and suggested as suggested items get specific UI precedence. (#162365) Allow for a controller to be both selected and suggested as only suggested items are grouped in the top of the kernel picker Co-authored-by: Ian Huff --- .../notebook/browser/services/notebookKernelServiceImpl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts index dd2ab69fa3c..2ce63b5332e 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts @@ -246,7 +246,7 @@ export class NotebookKernelService extends Disposable implements INotebookKernel // bound kernel const selectedId = this._notebookBindings.get(NotebookTextModelLikeId.str(notebook)); const selected = selectedId ? this._kernels.get(selectedId)?.kernel : undefined; - const suggestions = kernels.filter(item => item.instanceAffinity > 1 && item.kernel !== selected).map(item => item.kernel); + const suggestions = kernels.filter(item => item.instanceAffinity > 1).map(item => item.kernel); const hidden = kernels.filter(item => item.instanceAffinity < 0).map(item => item.kernel); return { all, selected, suggestions, hidden }; } From feb3d2d205dd292eedd80ccc8a5382046d9cda3a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 29 Sep 2022 13:15:01 -0700 Subject: [PATCH 234/599] Fix null ref in attachments check (#162396) Fixes #162391 Also reduces use of `any` --- .../ipynb/src/notebookAttachmentCleaner.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/extensions/ipynb/src/notebookAttachmentCleaner.ts b/extensions/ipynb/src/notebookAttachmentCleaner.ts index 265c284d984..a72761754df 100644 --- a/extensions/ipynb/src/notebookAttachmentCleaner.ts +++ b/extensions/ipynb/src/notebookAttachmentCleaner.ts @@ -153,16 +153,16 @@ export class AttachmentCleaner implements vscode.CodeActionProvider { this.saveAllAttachmentsToCache(cell.metadata, notebookUri, cellFragment); } - if (this.checkMetadataAttachmentsExistence(cell.metadata)) { + if (this.checkMetadataHasAttachmentsField(cell.metadata)) { // the cell metadata contains attachments, check if any are used in the markdown source - for (const currFilename of Object.keys(cell.metadata.attachments)) { + for (const [currFilename, attachment] of Object.entries(cell.metadata.attachments)) { // means markdown reference is present in the metadata, rendering will work properly // therefore, we don't need to check it in the next loop either if (markdownAttachmentsRefedInCell.has(currFilename)) { // attachment reference is present in the markdown source, no need to cache it markdownAttachmentsRefedInCell.get(currFilename)!.valid = true; - markdownAttachmentsInUse[currFilename] = cell.metadata.attachments[currFilename]; + markdownAttachmentsInUse[currFilename] = attachment as IAttachmentData; } else { // attachment reference is not present in the markdown source, cache it this.saveAttachmentToCache(notebookUri, cellFragment, currFilename, cell.metadata); @@ -227,7 +227,7 @@ export class AttachmentCleaner implements vscode.CodeActionProvider { const diagnostics: IAttachmentDiagnostic[] = []; const markdownAttachments = this.getAttachmentNames(document); - if (this.checkMetadataAttachmentsExistence(activeCell.metadata)) { + if (this.checkMetadataHasAttachmentsField(activeCell.metadata)) { for (const [currFilename, attachment] of markdownAttachments) { if (!activeCell.metadata.attachments[currFilename]) { // no attachment reference in the metadata @@ -295,8 +295,8 @@ export class AttachmentCleaner implements vscode.CodeActionProvider { * @param metadata metadata of cell * @returns boolean representing the presence of any attachments */ - private checkMetadataAttachmentsExistence(metadata: { [key: string]: any }): boolean { - return !!(metadata.attachments); + private checkMetadataHasAttachmentsField(metadata: { [key: string]: unknown }): metadata is { readonly attachments: Record } { + return !!metadata.attachments && typeof metadata.attachments === 'object'; } /** @@ -305,14 +305,16 @@ export class AttachmentCleaner implements vscode.CodeActionProvider { * @param notebookUri uri for the notebook being edited * @param cellFragment fragment of cell being edited */ - private saveAllAttachmentsToCache(metadata: { [key: string]: any }, notebookUri: string, cellFragment: string): void { + private saveAllAttachmentsToCache(metadata: { [key: string]: unknown }, notebookUri: string, cellFragment: string): void { const documentCache = this._attachmentCache.get(notebookUri) ?? new Map(); this._attachmentCache.set(notebookUri, documentCache); const cellCache = documentCache.get(cellFragment) ?? new Map(); documentCache.set(cellFragment, cellCache); - for (const currFilename of Object.keys(metadata.attachments)) { - cellCache.set(currFilename, metadata.attachments[currFilename]); + if (metadata.attachments && typeof metadata.attachments === 'object') { + for (const [currFilename, attachment] of Object.entries(metadata.attachments)) { + cellCache.set(currFilename, attachment); + } } } From c4c4814a826b0041135140a62cf2850c02109bf6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 29 Sep 2022 22:16:36 +0200 Subject: [PATCH 235/599] Fix #157623 (#162399) --- .../browser/extensionsWorkbenchService.ts | 13 +++++++------ .../browser/extensionEnablementService.ts | 18 +++++++++--------- .../browser/extensionEnablementService.test.ts | 10 ++++++++++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 10fd6d93e31..542534bada3 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -1587,14 +1587,15 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension for (const extension of toCheck) { checked.push(extension); } - const extensionsToDisable = installed.filter(i => { + const extensionsToEanbleOrDisable = installed.filter(i => { if (checked.indexOf(i) !== -1) { return false; } - if (i.enablementState === enablementState) { + const enable = enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace; + const isExtensionEnabled = i.enablementState === EnablementState.EnabledGlobally || i.enablementState === EnablementState.EnabledWorkspace; + if (enable === isExtensionEnabled) { return false; } - const enable = enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace; return (enable || !i.isBuiltin) // Include all Extensions for enablement and only non builtin extensions for disablement && (options.dependencies || options.pack) && extensions.some(extension => @@ -1602,10 +1603,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension || (options.pack && extension.extensionPack.some(id => areSameExtensions({ id }, i.identifier))) ); }); - if (extensionsToDisable.length) { - extensionsToDisable.push(...this.getExtensionsRecursively(extensionsToDisable, installed, enablementState, options, checked)); + if (extensionsToEanbleOrDisable.length) { + extensionsToEanbleOrDisable.push(...this.getExtensionsRecursively(extensionsToEanbleOrDisable, installed, enablementState, options, checked)); } - return extensionsToDisable; + return extensionsToEanbleOrDisable; } return []; } diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 3c350eae2d8..260a53c4b1f 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -236,7 +236,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench checked.push(extension); } - const extensionsToDisable: IExtension[] = []; + const extensionsToEnable: IExtension[] = []; for (const extension of allExtensions) { // Extension is already checked if (checked.some(e => areSameExtensions(e.identifier, extension.identifier))) { @@ -244,8 +244,8 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } const enablementStateOfExtension = this.getEnablementState(extension); - // Extension enablement state is same as the end enablement state - if (enablementStateOfExtension === enablementState) { + // Extension is enabled + if (this.isEnabledEnablementState(enablementStateOfExtension)) { continue; } @@ -254,11 +254,11 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench (options.dependencies && e.manifest.extensionDependencies?.some(id => areSameExtensions({ id }, extension.identifier))) || (options.pack && e.manifest.extensionPack?.some(id => areSameExtensions({ id }, extension.identifier))))) { - const index = extensionsToDisable.findIndex(e => areSameExtensions(e.identifier, extension.identifier)); + const index = extensionsToEnable.findIndex(e => areSameExtensions(e.identifier, extension.identifier)); // Extension is not aded to the disablement list so add it if (index === -1) { - extensionsToDisable.push(extension); + extensionsToEnable.push(extension); } // Extension is there already in the disablement list. @@ -266,17 +266,17 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench try { // Replace only if the enablement state can be changed this.throwErrorIfEnablementStateCannotBeChanged(extension, enablementStateOfExtension, true); - extensionsToDisable.splice(index, 1, extension); + extensionsToEnable.splice(index, 1, extension); } catch (error) { /*Do not add*/ } } } } - if (extensionsToDisable.length) { - extensionsToDisable.push(...this.getExtensionsToEnableRecursively(extensionsToDisable, allExtensions, enablementState, options, checked)); + if (extensionsToEnable.length) { + extensionsToEnable.push(...this.getExtensionsToEnableRecursively(extensionsToEnable, allExtensions, enablementState, options, checked)); } - return extensionsToDisable; + return extensionsToEnable; } private _setUserEnablementState(extension: IExtension, newState: EnablementState): Promise { 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 8e8c6678cfc..32b5b71b281 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -402,6 +402,16 @@ suite('ExtensionEnablementService Test', () => { assert.strictEqual(testObject.getEnablementState(dep), EnablementState.EnabledGlobally); }); + test('test enable an extension in workspace with a dependency extension that has auth providers', async () => { + installed.push(...[aLocalExtension2('pub.a', { extensionDependencies: ['pub.b'] }), aLocalExtension('pub.b', { authentication: [{ id: 'a', label: 'a' }] })]); + const target = installed[0]; + await (testObject).waitUntilInitialized(); + await testObject.setEnablement([target], EnablementState.DisabledWorkspace); + await testObject.setEnablement([target], EnablementState.EnabledWorkspace); + assert.ok(testObject.isEnabled(target)); + assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledWorkspace); + }); + 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]; From bcb6c9b7e0e795bdf65ea440025d204060e4bfc8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 30 Sep 2022 00:34:04 +0200 Subject: [PATCH 236/599] Fix #159263 (#162402) --- .../browser/extensionEnablementService.ts | 5 +++++ .../browser/extensionEnablementService.test.ts | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 260a53c4b1f..ee5d1794a65 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -249,6 +249,11 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench continue; } + // Skip if dependency extension is disabled by extension kind + if (enablementStateOfExtension === EnablementState.DisabledByExtensionKind) { + continue; + } + // Check if the extension is a dependency or in extension pack if (extensions.some(e => (options.dependencies && e.manifest.extensionDependencies?.some(id => areSameExtensions({ id }, 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 32b5b71b281..3bbb6fe1ebe 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -412,6 +412,22 @@ suite('ExtensionEnablementService Test', () => { assert.strictEqual(testObject.getEnablementState(target), EnablementState.EnabledWorkspace); }); + test('test enable an extension with a dependency extension that cannot be enabled', async () => { + instantiationService.stub(IExtensionManagementServerService, anExtensionManagementServerService(anExtensionManagementServer('vscode-local', instantiationService), anExtensionManagementServer('vscode-remote', instantiationService), null)); + const localWorkspaceDepExtension = aLocalExtension2('pub.b', { extensionKind: ['workspace'] }, { location: URI.file(`pub.b`) }); + const remoteWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: ['workspace'], extensionDependencies: ['pub.b'] }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const remoteWorkspaceDepExtension = aLocalExtension2('pub.b', { extensionKind: ['workspace'] }, { location: URI.file(`pub.b`).with({ scheme: Schemas.vscodeRemote }) }); + installed.push(localWorkspaceDepExtension, remoteWorkspaceExtension, remoteWorkspaceDepExtension); + + testObject = new TestExtensionEnablementService(instantiationService); + await (testObject).waitUntilInitialized(); + + await testObject.setEnablement([remoteWorkspaceExtension], EnablementState.DisabledGlobally); + await testObject.setEnablement([remoteWorkspaceExtension], EnablementState.EnabledGlobally); + assert.ok(testObject.isEnabled(remoteWorkspaceExtension)); + assert.strictEqual(testObject.getEnablementState(remoteWorkspaceExtension), 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]; From a17bc4853ed5ef6922667a8b0e320d8adfdff7e8 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 30 Sep 2022 08:15:06 +0200 Subject: [PATCH 237/599] Accept merge with conflicts dialog (fix #162296) --- .../contrib/mergeEditor/browser/commands/commands.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 016ff819756..4ab7188c7eb 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Codicon } from 'vs/base/common/codicons'; +import { basename } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; @@ -632,8 +633,9 @@ export class AcceptMerge extends MergeEditorAction2 { if (viewModel.model.unhandledConflictsCount.get() > 0) { const confirmResult = await dialogService.confirm({ type: 'info', - message: localize('mergeEditor.acceptMerge.unhandledConflicts', "There are still unhandled conflicts. Are you sure you want to accept the merge?"), - primaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.accept', "Complete merge with unhandled conflicts"), + message: localize('mergeEditor.acceptMerge.unhandledConflicts.message', "Do you want to complete the merge of {0}?", basename(inputModel.resultUri)), + detail: localize('mergeEditor.acceptMerge.unhandledConflicts.detail', "The file contains unhandled conflicts."), + primaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.accept', "Complete with Conflicts"), secondaryButton: localize('mergeEditor.acceptMerge.unhandledConflicts.cancel', "Cancel"), }); From 4e7be941498479ef34591c4a71ba58ae92fc999d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 30 Sep 2022 09:24:35 +0200 Subject: [PATCH 238/599] IntelliSense in JSON keyboard shortcut editor doesn't work for non-default profiles --- extensions/configuration-editing/package.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index 641b3ca5669..37a5a9137bb 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -71,6 +71,10 @@ "fileMatch": "%APP_SETTINGS_HOME%/keybindings.json", "url": "vscode://schemas/keybindings" }, + { + "fileMatch": "%APP_SETTINGS_HOME%/profiles/*/keybindings.json", + "url": "vscode://schemas/keybindings" + }, { "fileMatch": "vscode://defaultsettings/*.json", "url": "vscode://schemas/settings/default" @@ -119,6 +123,10 @@ "fileMatch": "%APP_SETTINGS_HOME%/snippets/*.json", "url": "vscode://schemas/snippets" }, + { + "fileMatch": "%APP_SETTINGS_HOME%/profiles/*/snippets/.json", + "url": "vscode://schemas/snippets" + }, { "fileMatch": "%APP_SETTINGS_HOME%/sync/snippets/preview/*.json", "url": "vscode://schemas/snippets" From 9cad02738947df4655593aca6d4615f34c57e35e Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 30 Sep 2022 00:31:29 -0700 Subject: [PATCH 239/599] check artifact size after download and extraction (#162407) * just log it for now * add size check --- build/azure-pipelines/product-publish.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/azure-pipelines/product-publish.ps1 b/build/azure-pipelines/product-publish.ps1 index 5006ec61a30..05b2b2b3ae7 100644 --- a/build/azure-pipelines/product-publish.ps1 +++ b/build/azure-pipelines/product-publish.ps1 @@ -76,6 +76,13 @@ do { $null,$product,$os,$arch,$type = $artifactName -split '_' $asset = Get-ChildItem -rec "$env:AGENT_TEMPDIRECTORY/$artifactName" + + if ($asset.Size -ne $_.resource.properties.artifactsize) { + Write-Warning "Artifact size mismatch for '$artifactName'. Expected: $($_.resource.properties.artifactsize). Actual: $($asset.Size)" + $set.Remove($artifactName) | Out-Null + continue + } + Write-Host "Processing artifact with the following values:" # turning in into an object just to log nicely @{ From 9bc43c7f8acc1d3b2d572f75ca30dccc2fed643d Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 30 Sep 2022 09:42:20 +0200 Subject: [PATCH 240/599] Git - Rename git.fetchBeforeCheckout to git.pullBeforeCheckout (#162303) Rename git.fetchBeforeCheckout to git.pullBeforeCheckout --- extensions/git/package.json | 4 ++-- extensions/git/package.nls.json | 2 +- extensions/git/src/commands.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index a8764170aa6..b57ef4a0de9 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -2330,11 +2330,11 @@ "default": false, "description": "%config.rebaseWhenSync%" }, - "git.fetchBeforeCheckout": { + "git.pullBeforeCheckout": { "type": "boolean", "scope": "resource", "default": false, - "description": "%config.fetchBeforeCheckout%" + "description": "%config.pullBeforeCheckout%" }, "git.fetchOnPull": { "type": "boolean", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index cba41774355..fdc97d8afa2 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -200,7 +200,7 @@ "config.rebaseWhenSync": "Force git to use rebase when running the sync command.", "config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.", "config.fetchOnPull": "When enabled, fetch all branches when pulling. Otherwise, fetch just the current one.", - "config.fetchBeforeCheckout": "Controls whether a branch that does not have outgoing commits is fast-forwarded before it is checked out.", + "config.pullBeforeCheckout": "Controls whether a branch that does not have outgoing commits is fast-forwarded before it is checked out.", "config.pullTags": "Fetch all tags when pulling.", "config.pruneOnFetch": "Prune when fetching.", "config.autoStash": "Stash any changes before pulling and restore them after successful pull.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 5a6850f1efd..5a8f2e84dc6 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -38,9 +38,9 @@ class CheckoutItem implements QuickPickItem { } const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); - const fetchBeforeCheckout = config.get('fetchBeforeCheckout', false) === true; + const pullBeforeCheckout = config.get('pullBeforeCheckout', false) === true; - if (fetchBeforeCheckout) { + if (pullBeforeCheckout) { await this.repository.fastForwardBranch(this.ref.name!); } From c2a3e85d3c60870546a7769333cfe66cfb512a85 Mon Sep 17 00:00:00 2001 From: Marcus Date: Fri, 30 Sep 2022 13:02:16 +0200 Subject: [PATCH 241/599] # Provide correct response to applyEdit() --- src/vs/editor/browser/services/bulkEditService.ts | 1 + src/vs/workbench/api/browser/mainThreadBulkEdits.ts | 2 +- .../workbench/contrib/bulkEdit/browser/bulkEditService.ts | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 12d1417489a..4f06c9ca68b 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -108,6 +108,7 @@ export interface IBulkEditOptions { export interface IBulkEditResult { ariaSummary: string; + isApplied: boolean; } export type IBulkEditPreviewHandler = (edits: ResourceEdit[], options?: IBulkEditOptions) => Promise; diff --git a/src/vs/workbench/api/browser/mainThreadBulkEdits.ts b/src/vs/workbench/api/browser/mainThreadBulkEdits.ts index dabd351f2d8..0c59eb78b5a 100644 --- a/src/vs/workbench/api/browser/mainThreadBulkEdits.ts +++ b/src/vs/workbench/api/browser/mainThreadBulkEdits.ts @@ -27,7 +27,7 @@ export class MainThreadBulkEdits implements MainThreadBulkEditsShape { $tryApplyWorkspaceEdit(dto: IWorkspaceEditDto, undoRedoGroupId?: number, isRefactoring?: boolean): Promise { const edits = reviveWorkspaceEditDto(dto, this._uriIdentService); - return this._bulkEditService.apply(edits, { undoRedoGroupId, respectAutoSaveConfig: isRefactoring }).then(() => true, err => { + return this._bulkEditService.apply(edits, { undoRedoGroupId, respectAutoSaveConfig: isRefactoring }).then((res) => res.isApplied, err => { this._logService.warn(`IGNORING workspace edit: ${err}`); return false; }); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts index ae0212db0c5..9181c5a6dcb 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts @@ -88,6 +88,10 @@ class BulkEdit { } } + isApplied(): boolean { + return this._edits.length > 0; + } + async perform(): Promise { if (this._edits.length === 0) { @@ -184,7 +188,7 @@ export class BulkEditService implements IBulkEditService { let edits = liftEdits(Array.isArray(editsIn) ? editsIn : editsIn.edits); if (edits.length === 0) { - return { ariaSummary: localize('nothing', "Made no edits") }; + return { ariaSummary: localize('nothing', "Made no edits"), isApplied: false }; } if (this._previewHandler && (options?.showPreview || edits.some(value => value.metadata?.needsConfirmation))) { @@ -248,7 +252,7 @@ export class BulkEditService implements IBulkEditService { await this._saveAll(resources); } - return { ariaSummary: bulkEdit.ariaMessage() }; + return { ariaSummary: bulkEdit.ariaMessage(), isApplied: bulkEdit.isApplied() }; } catch (err) { // console.log('apply FAILED'); // console.log(err); From 20e2a1524df3b40b3d96e42d468ac6d3ed23e545 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 30 Sep 2022 13:44:10 +0200 Subject: [PATCH 242/599] CC enablement doesn't influence custom titlebar enablement (#162432) mitigates https://github.com/microsoft/vscode/issues/161948 undoes https://github.com/microsoft/vscode/issues/151892 (likely) fixes https://github.com/microsoft/vscode/issues/158359 --- src/vs/workbench/browser/layout.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index ea93a14b908..8d367d84589 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1061,11 +1061,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; } - // with the command center enabled, we should always show - if (this.configurationService.getValue('window.commandCenter')) { - return true; - } - // remaining behavior is based on menubar visibility switch (getMenuBarVisibility(this.configurationService)) { case 'classic': From 2fbc0c6394cfe17995f2efbd0054802e9b706fb8 Mon Sep 17 00:00:00 2001 From: Marcus Date: Fri, 30 Sep 2022 14:16:29 +0200 Subject: [PATCH 243/599] # add standole service isApplied --- src/vs/editor/standalone/browser/standaloneServices.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index c25434b6c38..e92f0bac98c 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -817,7 +817,8 @@ class StandaloneBulkEditService implements IBulkEditService { } return { - ariaSummary: strings.format(StandaloneServicesNLS.bulkEditServiceSummary, totalEdits, totalFiles) + ariaSummary: strings.format(StandaloneServicesNLS.bulkEditServiceSummary, totalEdits, totalFiles), + isApplied: totalEdits > 0 }; } } From 9fb452c4852ef098206ec67a2b236ad5fd0ba828 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 30 Sep 2022 14:38:21 +0200 Subject: [PATCH 244/599] for disable renderer cpu profiling, keep long task telemetry (#162307) fixes https://github.com/microsoft/vscode/issues/161767 Co-authored-by: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> --- .../electron-sandbox/rendererAutoProfiler.ts | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index 12134bca348..6464cd8d16f 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -37,7 +37,6 @@ export class RendererProfiling { const eventHistory = new RingBuffer<{ command: string; timestamp: number }>(5); this._disposables.add(commandService.onWillExecuteCommand(e => eventHistory.push({ command: e.commandId, timestamp: Date.now() }))); - const sessionDisposables = this._disposables.add(new DisposableStore()); const obs = new PerformanceObserver(list => { @@ -51,11 +50,7 @@ export class RendererProfiling { return; } - // pause observation, we'll take a detailed look - obs.disconnect(); - const sessionId = generateUuid(); - logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); // all visible views const views = viewsDescriptorService.viewContainers.map(container => { @@ -74,31 +69,34 @@ export class RendererProfiling { editors: JSON.stringify(editors), }); - // start heartbeat monitoring - nativeHostService.startHeartbeat(sessionId).then(success => { - if (!success) { - logService.warn('[perf] FAILED to start heartbeat sending'); - return; - } + // // start heartbeat monitoring + // const sessionDisposables = this._disposables.add(new DisposableStore()); + // logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); + // // pause observation, we'll take a detailed look + // obs.disconnect(); + // nativeHostService.startHeartbeat(sessionId).then(success => { + // if (!success) { + // logService.warn('[perf] FAILED to start heartbeat sending'); + // return; + // } - // start sending a repeated heartbeat which is expected to be received by the main side - const handle1 = setInterval(() => nativeHostService.sendHeartbeat(sessionId), 500); + // // start sending a repeated heartbeat which is expected to be received by the main side + // const handle1 = setInterval(() => nativeHostService.sendHeartbeat(sessionId), 500); - // stop heartbeat after 20s - const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); + // // stop heartbeat after 20s + // const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); - // cleanup - // - stop heartbeat - // - reconnect perf observer - sessionDisposables.add(toDisposable(() => { - clearInterval(handle1); - clearTimeout(handle2); - nativeHostService.stopHeartbeat(sessionId); - logService.warn(`[perf] STOPPING to send heartbeat`); - - obs.observe({ entryTypes: ['longtask'] }); - })); - }); + // // cleanup + // // - stop heartbeat + // // - reconnect perf observer + // sessionDisposables.add(toDisposable(() => { + // clearInterval(handle1); + // clearTimeout(handle2); + // nativeHostService.stopHeartbeat(sessionId); + // logService.warn(`[perf] STOPPING to send heartbeat`); + // obs.observe({ entryTypes: ['longtask'] }); + // })); + // }); }); this._disposables.add(toDisposable(() => obs.disconnect())); From e6c62a2a7782e4b4240cfecd44762eedbc05f506 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 30 Sep 2022 15:11:22 +0200 Subject: [PATCH 245/599] Using StickyScrollContext instead of StickyScrollMenu --- src/vs/platform/actions/common/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 3cf5d70339f..012322289a9 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -103,7 +103,7 @@ export class MenuId { static readonly SearchContext = new MenuId('SearchContext'); static readonly StatusBarWindowIndicatorMenu = new MenuId('StatusBarWindowIndicatorMenu'); static readonly StatusBarRemoteIndicatorMenu = new MenuId('StatusBarRemoteIndicatorMenu'); - static readonly StickyScroll = new MenuId('StickyScrollMenu'); + static readonly StickyScroll = new MenuId('StickyScrollContext'); static readonly TestItem = new MenuId('TestItem'); static readonly TestItemGutter = new MenuId('TestItemGutter'); static readonly TestPeekElement = new MenuId('TestPeekElement'); From f515120d74ec12415fa9a71a95699ae765dfb3dd Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 30 Sep 2022 15:15:49 +0200 Subject: [PATCH 246/599] Breadcrumbs can now be toglled from the menu that appears by right clicking on the sticky scroll --- src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 120b7c0343a..06cc1f7bb07 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -512,7 +512,8 @@ registerAction2(class ToggleBreadcrumb extends Action2 { menu: [ { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 3 }, - { id: MenuId.NotebookToolbar, group: 'notebookLayout', order: 2 } + { id: MenuId.NotebookToolbar, group: 'notebookLayout', order: 2 }, + { id: MenuId.StickyScroll } ] }); } From d49bf1cc6c58640805bde07b61e9bb7ba17e4c65 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 30 Sep 2022 15:20:19 +0200 Subject: [PATCH 247/599] Changing StickyScroll to StickyScrollContext --- .../editor/contrib/stickyScroll/browser/stickyScrollActions.ts | 2 +- src/vs/platform/actions/common/actions.ts | 2 +- src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts index 087aa6bc43e..30e8e3d9363 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts @@ -25,7 +25,7 @@ export class ToggleStickyScroll extends Action2 { menu: [ { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 6 }, - { id: MenuId.StickyScroll } + { id: MenuId.StickyScrollContext } ] }); } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 012322289a9..3af6f2d84b0 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -103,7 +103,7 @@ export class MenuId { static readonly SearchContext = new MenuId('SearchContext'); static readonly StatusBarWindowIndicatorMenu = new MenuId('StatusBarWindowIndicatorMenu'); static readonly StatusBarRemoteIndicatorMenu = new MenuId('StatusBarRemoteIndicatorMenu'); - static readonly StickyScroll = new MenuId('StickyScrollContext'); + static readonly StickyScrollContext = new MenuId('StickyScrollContext'); static readonly TestItem = new MenuId('TestItem'); static readonly TestItemGutter = new MenuId('TestItemGutter'); static readonly TestPeekElement = new MenuId('TestPeekElement'); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 06cc1f7bb07..437f2204ff7 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -513,7 +513,7 @@ registerAction2(class ToggleBreadcrumb extends Action2 { { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 3 }, { id: MenuId.NotebookToolbar, group: 'notebookLayout', order: 2 }, - { id: MenuId.StickyScroll } + { id: MenuId.StickyScrollContext } ] }); } From e86e2a11a5bf0eb26ee3251bedc502a92877e3d2 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 30 Sep 2022 15:29:31 +0200 Subject: [PATCH 248/599] StickyScroll to StickyScrollContext --- .../contrib/stickyScroll/browser/stickyScrollController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts index cecddbb5034..c67a8564a16 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts @@ -64,7 +64,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib } private onContextMenu(event: MouseEvent) { - const menu = this._menuService.createMenu(MenuId.StickyScroll, this._contextKeyService); + const menu = this._menuService.createMenu(MenuId.StickyScrollContext, this._contextKeyService); const actions: IAction[] = []; createAndFillInContextMenuActions(menu, undefined, actions); this._contextMenuService.showContextMenu({ From f1789f1e30c0c53d5132d87c2ce3bc2b07348239 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 30 Sep 2022 15:46:17 +0200 Subject: [PATCH 249/599] Fixes #162275 --- .../contrib/mergeEditor/browser/view/conflictActions.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index 6a2fd58509c..dfb6979f5b1 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -320,6 +320,15 @@ class ActionsContentWidget extends Disposable implements IContentWidget { } getPosition(): IContentWidgetPosition | null { + // We cannot put the content widget after line 0, as line 0 gets normalized to line 1. + // Thus, we put the content widget before line 1 to make it slightly less buggy. + // TODO: Fix this properly. + if (this.lineNumber === 0) { + return { + position: { lineNumber: 1, column: 1, }, + preference: [ContentWidgetPositionPreference.ABOVE], + }; + } return { position: { lineNumber: this.lineNumber, column: 1, }, preference: [ContentWidgetPositionPreference.BELOW], From cfd3a08c638ac814c223db8e4cfbe3a686b345d0 Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 30 Sep 2022 16:37:05 +0200 Subject: [PATCH 250/599] add support so that `IContextMenuService` can open with just a menu identifier --- .../contextview/browser/contextMenuService.ts | 49 +++++++++++++++++-- .../contextview/browser/contextView.ts | 25 +++++++++- .../electron-sandbox/contextmenuService.ts | 40 +++++++++------ 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts index c80851be9ac..fe80ed05a20 100644 --- a/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -5,14 +5,18 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; import { ModifierKeyEmitter } from 'vs/base/browser/dom'; +import { IAction, Separator } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ContextMenuHandler, IContextMenuHandlerOptions } from './contextMenuHandler'; -import { IContextMenuService, IContextViewService } from './contextView'; +import { IContextMenuMenuDelegate, IContextMenuService, IContextViewService } from './contextView'; export class ContextMenuService extends Disposable implements IContextMenuService { @@ -27,10 +31,10 @@ export class ContextMenuService extends Disposable implements IContextMenuServic return this._contextMenuHandler; } - private readonly _onDidShowContextMenu = new Emitter(); + private readonly _onDidShowContextMenu = this._store.add(new Emitter()); readonly onDidShowContextMenu = this._onDidShowContextMenu.event; - private readonly _onDidHideContextMenu = new Emitter(); + private readonly _onDidHideContextMenu = this._store.add(new Emitter()); readonly onDidHideContextMenu = this._onDidHideContextMenu.event; constructor( @@ -38,7 +42,9 @@ export class ContextMenuService extends Disposable implements IContextMenuServic @INotificationService private readonly notificationService: INotificationService, @IContextViewService private readonly contextViewService: IContextViewService, @IKeybindingService private readonly keybindingService: IKeybindingService, - @IThemeService private readonly themeService: IThemeService + @IThemeService private readonly themeService: IThemeService, + @IMenuService private readonly menuService: IMenuService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, ) { super(); } @@ -49,7 +55,10 @@ export class ContextMenuService extends Disposable implements IContextMenuServic // ContextMenu - showContextMenu(delegate: IContextMenuDelegate): void { + showContextMenu(delegate: IContextMenuDelegate | IContextMenuMenuDelegate): void { + + delegate = ContextMenuMenuDelegate.transform(delegate, this.menuService, this.contextKeyService); + this.contextMenuHandler.showContextMenu({ ...delegate, onHide: (didCancel) => { @@ -62,3 +71,33 @@ export class ContextMenuService extends Disposable implements IContextMenuServic this._onDidShowContextMenu.fire(); } } + +export namespace ContextMenuMenuDelegate { + + function is(thing: IContextMenuDelegate | IContextMenuMenuDelegate): thing is IContextMenuMenuDelegate { + return thing && (thing).menuId instanceof MenuId; + } + + export function transform(delegate: IContextMenuDelegate | IContextMenuMenuDelegate, menuService: IMenuService, globalContextKeyService: IContextKeyService): IContextMenuDelegate { + if (!is(delegate)) { + return delegate; + } + const { menuId, menuActionOptions, contextKeyService } = delegate; + return { + ...delegate, + getActions: () => { + const target: IAction[] = []; + if (menuId) { + const menu = menuService.createMenu(menuId, contextKeyService ?? globalContextKeyService); + createAndFillInContextMenuActions(menu, menuActionOptions, target); + menu.dispose(); + } + if (!delegate.getActions) { + return target; + } else { + return Separator.join(delegate.getActions(), target); + } + } + }; + } +} diff --git a/src/vs/platform/contextview/browser/contextView.ts b/src/vs/platform/contextview/browser/contextView.ts index b99bfdc0aa5..505d76eabfb 100644 --- a/src/vs/platform/contextview/browser/contextView.ts +++ b/src/vs/platform/contextview/browser/contextView.ts @@ -5,8 +5,11 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; import { AnchorAlignment, AnchorAxisAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { IAction } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { IMenuActionOptions, MenuId } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IContextViewService = createDecorator('contextViewService'); @@ -44,5 +47,25 @@ export interface IContextMenuService { readonly onDidShowContextMenu: Event; readonly onDidHideContextMenu: Event; - showContextMenu(delegate: IContextMenuDelegate): void; + showContextMenu(delegate: IContextMenuDelegate | IContextMenuMenuDelegate): void; } + +export type IContextMenuMenuDelegate = { + /** + * The MenuId that should be used to populate the context menu. + */ + menuId?: MenuId; + /** + * Optional options how menu actions are invoked + */ + menuActionOptions?: IMenuActionOptions; + /** + * Optional context key service which drives the given menu + */ + contextKeyService?: IContextKeyService; + + /** + * Optional getter for extra actions. They will be prepended to the menu actions. + */ + getActions?(): IAction[]; +} & Omit; diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index fa2034e1ee7..f70812f2e09 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -5,7 +5,7 @@ import { IAction, IActionRunner, ActionRunner, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, Separator, SubmenuAction } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; -import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuMenuDelegate, IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { getZoomFactor } from 'vs/base/browser/browser'; @@ -13,25 +13,27 @@ import { unmnemonicLabel } from 'vs/base/common/labels'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IContextMenuDelegate, IContextMenuEvent } from 'vs/base/browser/contextmenu'; import { once } from 'vs/base/common/functional'; -import { Disposable } from 'vs/base/common/lifecycle'; import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu'; import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu'; import { getTitleBarStyle } from 'vs/platform/window/common/window'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; +import { ContextMenuMenuDelegate, ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { stripIcons } from 'vs/base/common/iconLabels'; import { coalesce } from 'vs/base/common/arrays'; import { Event, Emitter } from 'vs/base/common/event'; import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { IMenuService } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { Disposable } from 'vs/base/common/lifecycle'; -export class ContextMenuService extends Disposable implements IContextMenuService { +export class ContextMenuService implements IContextMenuService { declare readonly _serviceBrand: undefined; - private impl: IContextMenuService; + private impl: HTMLContextMenuService | NativeContextMenuService; get onDidShowContextMenu(): Event { return this.impl.onDidShowContextMenu; } get onDidHideContextMenu(): Event { return this.impl.onDidHideContextMenu; } @@ -42,22 +44,27 @@ export class ContextMenuService extends Disposable implements IContextMenuServic @IKeybindingService keybindingService: IKeybindingService, @IConfigurationService configurationService: IConfigurationService, @IContextViewService contextViewService: IContextViewService, - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super(); // Custom context menu: Linux/Windows if custom title is enabled if (!isMacintosh && getTitleBarStyle(configurationService) === 'custom') { - this.impl = new HTMLContextMenuService(telemetryService, notificationService, contextViewService, keybindingService, themeService); + this.impl = new HTMLContextMenuService(telemetryService, notificationService, contextViewService, keybindingService, themeService, menuService, contextKeyService); } // Native context menu: otherwise else { - this.impl = new NativeContextMenuService(notificationService, telemetryService, keybindingService); + this.impl = new NativeContextMenuService(notificationService, telemetryService, keybindingService, menuService, contextKeyService); } } - showContextMenu(delegate: IContextMenuDelegate): void { + dispose(): void { + this.impl.dispose(); + } + + showContextMenu(delegate: IContextMenuDelegate | IContextMenuMenuDelegate): void { this.impl.showContextMenu(delegate); } } @@ -66,21 +73,26 @@ class NativeContextMenuService extends Disposable implements IContextMenuService declare readonly _serviceBrand: undefined; - private readonly _onDidShowContextMenu = new Emitter(); + private readonly _onDidShowContextMenu = this._store.add(new Emitter()); readonly onDidShowContextMenu = this._onDidShowContextMenu.event; - private readonly _onDidHideContextMenu = new Emitter(); + private readonly _onDidHideContextMenu = this._store.add(new Emitter()); readonly onDidHideContextMenu = this._onDidHideContextMenu.event; constructor( @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IKeybindingService private readonly keybindingService: IKeybindingService + @IKeybindingService private readonly keybindingService: IKeybindingService, + @IMenuService private readonly menuService: IMenuService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, ) { super(); } - showContextMenu(delegate: IContextMenuDelegate): void { + showContextMenu(delegate: IContextMenuDelegate | IContextMenuMenuDelegate): void { + + delegate = ContextMenuMenuDelegate.transform(delegate, this.menuService, this.contextKeyService); + const actions = delegate.getActions(); if (actions.length) { const onHide = once(() => { From 88c6e023dbc1ce77d3c69065a90d074ce360e71f Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 30 Sep 2022 17:06:37 +0200 Subject: [PATCH 251/599] adopt `showContextMenu`-users that have been using `createAndFillInContextMenuActions` --- .../standalone/browser/standaloneServices.ts | 6 +++-- src/vs/platform/actions/browser/toolbar.ts | 18 ++++--------- .../browser/parts/editor/editorGroupView.ts | 19 +++++--------- .../browser/parts/editor/titleControl.ts | 14 ++++------ .../browser/parts/titlebar/titlebarPart.ts | 15 +++-------- .../bulkEdit/browser/preview/bulkEditPane.ts | 26 +++++++------------ .../contrib/comments/browser/commentMenus.ts | 4 --- .../contrib/comments/browser/commentNode.ts | 10 +++---- .../files/browser/views/explorerView.ts | 19 ++++---------- .../files/browser/views/openEditorsView.ts | 14 +++------- .../contrib/markers/browser/markersView.ts | 8 ++---- .../notebook/browser/notebookEditorWidget.ts | 14 +++------- .../view/renderers/backLayerWebView.ts | 15 +++-------- .../contrib/remote/browser/tunnelView.ts | 11 +++----- .../contrib/search/browser/searchView.ts | 17 +++--------- .../contrib/webview/browser/webviewElement.ts | 21 +++++---------- .../parts/titlebar/titlebarPart.ts | 5 ++-- 17 files changed, 72 insertions(+), 164 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index c25434b6c38..4db794486e7 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -948,9 +948,11 @@ class StandaloneContextMenuService extends ContextMenuService { @INotificationService notificationService: INotificationService, @IContextViewService contextViewService: IContextViewService, @IKeybindingService keybindingService: IKeybindingService, - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super(telemetryService, notificationService, contextViewService, keybindingService, themeService); + super(telemetryService, notificationService, contextViewService, keybindingService, themeService, menuService, contextKeyService); this.configure({ blockMouse: false }); // we do not want that in the standalone editor } } diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index 3886e3e5556..619af9e09b9 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -10,7 +10,7 @@ import { coalesceInPlace } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; -import { createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuActionOptions, IMenuService, MenuId, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -182,23 +182,15 @@ export class WorkbenchToolBar extends ToolBar { })); } - // add context menu actions (iff appicable) - if (this._options?.contextMenu) { - const menu = this._menuService.createMenu(this._options.contextMenu, this._contextKeyService); - const contextMenuActions: IAction[] = []; - createAndFillInContextMenuActions(menu, { ...this._options?.menuOptions, renderShortTitle: true, }, contextMenuActions); - menu.dispose(); - - if (contextMenuActions.length > 0) { - actions = [...actions, new Separator(), ...contextMenuActions]; - } - } - // this.getElement().classList.toggle('config', true); this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions, + // add context menu actions (iff appicable) + menuId: this._options?.contextMenu, + menuActionOptions: { renderShortTitle: true, ...this._options?.menuOptions }, + contextKeyService: this._contextKeyService, onHide: () => this.getElement().classList.toggle('config', false), }); })); diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 3049500d7f8..2495583b51f 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -36,9 +36,9 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IAction } from 'vs/base/common/actions'; import { NoTabsTitleControl } from 'vs/workbench/browser/parts/editor/noTabsTitleControl'; -import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { hash } from 'vs/base/common/hash'; @@ -364,13 +364,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } private createContainerContextMenu(): void { - const menu = this._register(this.menuService.createMenu(MenuId.EmptyEditorGroupContext, this.contextKeyService)); - - this._register(addDisposableListener(this.element, EventType.CONTEXT_MENU, e => this.onShowContainerContextMenu(menu, e))); - this._register(addDisposableListener(this.element, TouchEventType.Contextmenu, () => this.onShowContainerContextMenu(menu))); + this._register(addDisposableListener(this.element, EventType.CONTEXT_MENU, e => this.onShowContainerContextMenu(e))); + this._register(addDisposableListener(this.element, TouchEventType.Contextmenu, () => this.onShowContainerContextMenu())); } - private onShowContainerContextMenu(menu: IMenu, e?: MouseEvent): void { + private onShowContainerContextMenu(e?: MouseEvent): void { if (!this.isEmpty) { return; // only for empty editor groups } @@ -382,14 +380,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { anchor = { x: event.posx, y: event.posy }; } - // Fill in contributed actions - const actions: IAction[] = []; - createAndFillInContextMenuActions(menu, undefined, actions); - // Show it this.contextMenuService.showContextMenu({ + menuId: MenuId.EmptyEditorGroupContext, + contextKeyService: this.contextKeyService, getAnchor: () => anchor, - getActions: () => actions, onHide: () => { this.focus(); } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 57fae3e0bc1..2ff9d39896b 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -12,8 +12,8 @@ import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/bro import { IAction, SubmenuAction, ActionRunner } from 'vs/base/common/actions'; import { ResolvedKeybinding } from 'vs/base/common/keybindings'; import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; -import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { createActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -108,7 +108,6 @@ export abstract class TitleControl extends Themable { private readonly editorToolBarMenuDisposables = this._register(new DisposableStore()); - private contextMenu: IMenu; private renderDropdownAsChildElement: boolean; constructor( @@ -140,7 +139,6 @@ export abstract class TitleControl extends Themable { this.groupLockedContext = ActiveEditorGroupLockedContext.bindTo(contextKeyService); - this.contextMenu = this._register(this.menuService.createMenu(MenuId.EditorTitleContext, this.contextKeyService)); this.renderDropdownAsChildElement = false; this.create(parent); @@ -374,14 +372,12 @@ export abstract class TitleControl extends Themable { anchor = { x: event.posx, y: event.posy }; } - // Fill in contributed actions - const actions: IAction[] = []; - createAndFillInContextMenuActions(this.contextMenu, { shouldForwardArgs: true, arg: this.resourceContext.get() }, actions); - // Show it this.contextMenuService.showContextMenu({ getAnchor: () => anchor, - getActions: () => actions, + menuId: MenuId.EditorTitleContext, + menuActionOptions: { shouldForwardArgs: true, arg: this.resourceContext.get() }, + contextKeyService: this.contextKeyService, getActionsContext: () => ({ groupId: this.group.id, editorIndex: this.group.getIndexOfEditor(editor) }), getKeyBinding: action => this.getKeybinding(action), onHide: () => { diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 90cb274b662..3c3da926ab7 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -11,7 +11,6 @@ import { getZoomFactor } from 'vs/base/browser/browser'; import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/window/common/window'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IAction } from 'vs/base/common/actions'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -25,8 +24,8 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { createActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { Action2, IMenuService, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { Codicon } from 'vs/base/common/codicons'; @@ -92,7 +91,6 @@ export class TitlebarPart extends Part implements ITitleService { @IThemeService themeService: IThemeService, @IStorageService storageService: IStorageService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, - @IMenuService private readonly menuService: IMenuService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IHostService private readonly hostService: IHostService, @IHoverService hoverService: IHoverService, @@ -382,16 +380,11 @@ export class TitlebarPart extends Part implements ITitleService { const event = new StandardMouseEvent(e); const anchor = { x: event.posx, y: event.posy }; - // Fill in contributed actions - const menu = this.menuService.createMenu(menuId, this.contextKeyService); - const actions: IAction[] = []; - createAndFillInContextMenuActions(menu, undefined, actions); - menu.dispose(); - // Show it this.contextMenuService.showContextMenu({ getAnchor: () => anchor, - getActions: () => actions, + menuId, + contextKeyService: this.contextKeyService, domForShadowRoot: isMacintosh && isNative ? event.target : undefined }); } diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts index cb829e3eb0b..33aae4de46f 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts @@ -26,9 +26,7 @@ import { ResourceLabels, IResourceLabelsContainer } from 'vs/workbench/browser/l import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import Severity from 'vs/base/common/severity'; import { basename, dirname } from 'vs/base/common/resources'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; -import { IAction } from 'vs/base/common/actions'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; @@ -78,10 +76,9 @@ export class BulkEditPane extends ViewPane { @ILabelService private readonly _labelService: ILabelService, @ITextModelService private readonly _textModelService: ITextModelService, @IDialogService private readonly _dialogService: IDialogService, - @IMenuService private readonly _menuService: IMenuService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IStorageService private readonly _storageService: IStorageService, + @IContextKeyService contextKeyService: IContextKeyService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, @@ -92,13 +89,13 @@ export class BulkEditPane extends ViewPane { ) { super( { ...options, titleMenuId: MenuId.BulkEditTitle }, - keybindingService, contextMenuService, configurationService, _contextKeyService, viewDescriptorService, _instaService, openerService, themeService, telemetryService + keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, _instaService, openerService, themeService, telemetryService ); this.element.classList.add('bulk-edit-panel', 'show-file-icons'); - this._ctxHasCategories = BulkEditPane.ctxHasCategories.bindTo(_contextKeyService); - this._ctxGroupByFile = BulkEditPane.ctxGroupByFile.bindTo(_contextKeyService); - this._ctxHasCheckedChanges = BulkEditPane.ctxHasCheckedChanges.bindTo(_contextKeyService); + this._ctxHasCategories = BulkEditPane.ctxHasCategories.bindTo(contextKeyService); + this._ctxGroupByFile = BulkEditPane.ctxGroupByFile.bindTo(contextKeyService); + this._ctxHasCheckedChanges = BulkEditPane.ctxHasCheckedChanges.bindTo(contextKeyService); } override dispose(): void { @@ -380,16 +377,11 @@ export class BulkEditPane extends ViewPane { } private _onContextMenu(e: ITreeContextMenuEvent): void { - const menu = this._menuService.createMenu(MenuId.BulkEditContext, this._contextKeyService); - const actions: IAction[] = []; - createAndFillInContextMenuActions(menu, undefined, actions); this._contextMenuService.showContextMenu({ - getActions: () => actions, - getAnchor: () => e.anchor, - onHide: () => { - menu.dispose(); - } + menuId: MenuId.BulkEditContext, + contextKeyService: this.contextKeyService, + getAnchor: () => e.anchor }); } } diff --git a/src/vs/workbench/contrib/comments/browser/commentMenus.ts b/src/vs/workbench/contrib/comments/browser/commentMenus.ts index 79e647f9121..dae9f44956f 100644 --- a/src/vs/workbench/contrib/comments/browser/commentMenus.ts +++ b/src/vs/workbench/contrib/comments/browser/commentMenus.ts @@ -35,10 +35,6 @@ export class CommentMenus implements IDisposable { return this.getMenu(MenuId.CommentThreadTitleContext, contextKeyService); } - getCommentThreadCommentContextActions(contextKeyService: IContextKeyService): IMenu { - return this.getMenu(MenuId.CommentThreadCommentContext, contextKeyService); - } - private getMenu(menuId: MenuId, contextKeyService: IContextKeyService): IMenu { const menu = this.menuService.createMenu(menuId, contextKeyService); diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index df7f71d462a..8ca985d8f43 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -26,7 +26,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; -import { MenuItemAction, SubmenuItemAction, IMenu } from 'vs/platform/actions/common/actions'; +import { MenuItemAction, SubmenuItemAction, IMenu, MenuId } from 'vs/platform/actions/common/actions'; import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions'; @@ -574,13 +574,11 @@ export class CommentNode extends Disposable { private onContextMenu(e: MouseEvent) { - const actions = this._commentMenus.getCommentThreadCommentContextActions(this._contextKeyService).getActions({ shouldForwardArgs: true }).map((value) => value[1]).flat(); - if (!actions.length) { - return; - } this.contextMenuService.showContextMenu({ getAnchor: () => e, - getActions: () => actions, + menuId: MenuId.CommentThreadCommentContext, + menuActionOptions: { shouldForwardArgs: true }, + contextKeyService: this._contextKeyService, actionRunner: new ActionRunner(), getActionsContext: () => { return this.commentNodeContext; diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 8dc7c9a2e1e..158ea94cbfb 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import * as perf from 'vs/base/common/performance'; -import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; +import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID, ExplorerResourceNotReadonlyContext, ViewHasSomeCollapsibleRootItemContext } from 'vs/workbench/contrib/files/common/files'; import { FileCopiedContext, NEW_FILE_COMMAND_ID, NEW_FOLDER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileActions'; @@ -31,8 +31,7 @@ import { ExplorerDelegate, ExplorerDataSource, FilesRenderer, ICompressedNavigat import { IThemeService, IFileIconTheme } from 'vs/platform/theme/common/themeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ITreeContextMenuEvent, TreeVisibility } from 'vs/base/browser/ui/tree/tree'; -import { IMenuService, MenuId, IMenu, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { MenuId, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { ResourceLabels } from 'vs/workbench/browser/labels'; @@ -202,7 +201,6 @@ export class ExplorerView extends ViewPane implements IExplorerView { @IDecorationsService private readonly decorationService: IDecorationsService, @ILabelService private readonly labelService: ILabelService, @IThemeService themeService: IWorkbenchThemeService, - @IMenuService private readonly menuService: IMenuService, @ITelemetryService telemetryService: ITelemetryService, @IExplorerService private readonly explorerService: IExplorerService, @IStorageService private readonly storageService: IStorageService, @@ -242,13 +240,6 @@ export class ExplorerView extends ViewPane implements IExplorerView { // noop } - // Memoized locals - @memoize private get contributedContextMenu(): IMenu { - const contributedContextMenu = this.menuService.createMenu(MenuId.ExplorerContext, this.tree.contextKeyService); - this._register(contributedContextMenu); - return contributedContextMenu; - } - @memoize private get fileCopiedContextKey(): IContextKey { return FileCopiedContext.bindTo(this.contextKeyService); } @@ -582,7 +573,6 @@ export class ExplorerView extends ViewPane implements IExplorerView { const selection = this.tree.getSelection(); - const actions: IAction[] = []; const roots = this.explorerService.roots; // If the click is outside of the elements pass the root resource if there is only one root. If there are multiple roots pass empty object. let arg: URI | {}; if (stat instanceof ExplorerItem) { @@ -591,11 +581,12 @@ export class ExplorerView extends ViewPane implements IExplorerView { } else { arg = roots.length === 1 ? roots[0].resource : {}; } - createAndFillInContextMenuActions(this.contributedContextMenu, { arg, shouldForwardArgs: true }, actions); this.contextMenuService.showContextMenu({ + menuId: MenuId.ExplorerContext, + menuActionOptions: { arg, shouldForwardArgs: true }, + contextKeyService: this.tree.contextKeyService, getAnchor: () => anchor, - getActions: () => actions, onHide: (wasCancelled?: boolean) => { if (wasCancelled) { this.tree.domFocus(); diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 3d2a4c48a6e..90494a4ffd5 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -28,8 +28,7 @@ import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenuService, MenuId, IMenu, Action2, registerAction2, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuId, Action2, registerAction2, MenuRegistry } from 'vs/platform/actions/common/actions'; import { OpenEditorsDirtyEditorContext, OpenEditorsGroupContext, OpenEditorsReadonlyEditorContext, SAVE_ALL_LABEL, SAVE_ALL_COMMAND_ID, NEW_UNTITLED_FILE_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileConstants'; import { ResourceContextKey } from 'vs/workbench/common/contextkeys'; import { CodeDataTransfers, containsDragType } from 'vs/platform/dnd/browser/dnd'; @@ -69,7 +68,6 @@ export class OpenEditorsView extends ViewPane { private structuralRefreshDelay: number; private list!: WorkbenchList; private listLabels: ResourceLabels | undefined; - private contributedContextMenu!: IMenu; private needsRefresh = false; private elements: (OpenEditor | IEditorGroup)[] = []; private sortOrder: 'editorOrder' | 'alphabetical' | 'fullPath'; @@ -89,7 +87,6 @@ export class OpenEditorsView extends ViewPane { @IContextKeyService contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @ITelemetryService telemetryService: ITelemetryService, - @IMenuService private readonly menuService: IMenuService, @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService, @IOpenerService openerService: IOpenerService, @@ -243,9 +240,6 @@ export class OpenEditorsView extends ViewPane { this._register(this.list); this._register(this.listLabels); - this.contributedContextMenu = this.menuService.createMenu(MenuId.OpenEditorsContext, this.list.contextKeyService); - this._register(this.contributedContextMenu); - this.updateSize(); // Bind context keys @@ -396,12 +390,12 @@ export class OpenEditorsView extends ViewPane { } const element = e.element; - const actions: IAction[] = []; - createAndFillInContextMenuActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? EditorResourceAccessor.getOriginalUri(element.editor) : {} }, actions); this.contextMenuService.showContextMenu({ + menuId: MenuId.OpenEditorsContext, + menuActionOptions: { shouldForwardArgs: true, arg: element instanceof OpenEditor ? EditorResourceAccessor.getOriginalUri(element.editor) : {} }, + contextKeyService: this.list.contextKeyService, getAnchor: () => e.anchor, - getActions: () => actions, getActionsContext: () => element instanceof OpenEditor ? { groupId: element.groupId, editorIndex: element.group.getIndexOfEditor(element.editor) } : { groupId: element.id } }); } diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index 826270e143a..bf9a407742a 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -32,7 +32,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, MarkersWidgetAccessibilityProvider, MarkersViewModel } from 'vs/workbench/contrib/markers/browser/markersTreeViewer'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ResourceLabels } from 'vs/workbench/browser/labels'; @@ -53,7 +53,6 @@ import { groupBy } from 'vs/base/common/arrays'; import { ResourceMap } from 'vs/base/common/map'; import { EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; import { IMarkersView } from 'vs/workbench/contrib/markers/browser/markers'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { ResourceListDnDHandler } from 'vs/workbench/browser/dnd'; import { ITableContextMenuEvent, ITableEvent } from 'vs/base/browser/ui/table/table'; import { MarkersTable } from 'vs/workbench/contrib/markers/browser/markersTable'; @@ -148,7 +147,6 @@ export class MarkersView extends ViewPane implements IMarkersView { @IContextKeyService contextKeyService: IContextKeyService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IContextMenuService contextMenuService: IContextMenuService, - @IMenuService private readonly menuService: IMenuService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @IKeybindingService keybindingService: IKeybindingService, @IStorageService storageService: IStorageService, @@ -803,6 +801,7 @@ export class MarkersView extends ViewPane implements IMarkersView { this.contextMenuService.showContextMenu({ getAnchor: () => e.anchor!, + menuId: MenuId.ProblemsPanelContext, getActions: () => this.getMenuActions(element), getActionViewItem: (action) => { const keybinding = this.keybindingService.lookupKeybinding(action.id); @@ -833,9 +832,6 @@ export class MarkersView extends ViewPane implements IMarkersView { } } - const menu = this.menuService.createMenu(MenuId.ProblemsPanelContext, this.widget.contextKeyService); - createAndFillInContextMenuActions(menu, undefined, result); - menu.dispose(); return result; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index eab8921da11..e7b2dc19892 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -14,7 +14,6 @@ import * as DOM from 'vs/base/browser/dom'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; -import { IAction } from 'vs/base/common/actions'; import { DeferredPromise, runWhenIdle, SequencerByKey } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Color, RGBA } from 'vs/base/common/color'; @@ -33,8 +32,7 @@ import { Range } from 'vs/editor/common/core/range'; import { IEditor } from 'vs/editor/common/editorCommon'; import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController'; import * as nls from 'vs/nls'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -252,7 +250,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD @IContextKeyService contextKeyService: IContextKeyService, @ILayoutService private readonly layoutService: ILayoutService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IMenuService private readonly menuService: IMenuService, @ITelemetryService private readonly telemetryService: ITelemetryService, @INotebookExecutionService private readonly notebookExecutionService: INotebookExecutionService, @INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService, @@ -953,13 +950,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD private showListContextMenu(e: IListContextMenuEvent) { this.contextMenuService.showContextMenu({ - getActions: () => { - const result: IAction[] = []; - const menu = this.menuService.createMenu(MenuId.NotebookCellTitle, this.scopedContextKeyService); - createAndFillInContextMenuActions(menu, undefined, result); - menu.dispose(); - return result; - }, + menuId: MenuId.NotebookCellTitle, + contextKeyService: this.scopedContextKeyService, getAnchor: () => e.anchor }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 30da51aa51c..44447bf61f0 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IAction } from 'vs/base/common/actions'; import { coalesce } from 'vs/base/common/arrays'; import { decodeBase64 } from 'vs/base/common/buffer'; import { Emitter, Event } from 'vs/base/common/event'; @@ -21,8 +20,7 @@ import { ILanguageService } from 'vs/editor/common/languages/language'; import { generateTokensCSSForColorMap } from 'vs/editor/common/languages/supports/tokenization'; import { tokenizeToString } from 'vs/editor/common/languages/textToHtmlTokenizer'; import * as nls from 'vs/nls'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -130,7 +128,6 @@ export class BackLayerWebView extends Disposable { @IFileDialogService private readonly fileDialogService: IFileDialogService, @IFileService private readonly fileService: IFileService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IMenuService private readonly menuService: IMenuService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -766,13 +763,8 @@ var requirejs = (function() { // Then show the context menu const webviewRect = this.element.getBoundingClientRect(); this.contextMenuService.showContextMenu({ - getActions: () => { - const result: IAction[] = []; - const menu = this.menuService.createMenu(MenuId.NotebookCellTitle, this.contextKeyService); - createAndFillInContextMenuActions(menu, undefined, result); - menu.dispose(); - return result; - }, + menuId: MenuId.NotebookCellTitle, + contextKeyService: this.contextKeyService, getAnchor: () => ({ x: webviewRect.x + data.clientX, y: webviewRect.y + data.clientY @@ -1529,4 +1521,3 @@ function getTokenizationCss() { const tokenizationCss = colorMap ? generateTokensCSSForColorMap(colorMap) : ''; return tokenizationCss; } - diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index b087ee0bd88..09222cf1888 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -23,7 +23,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IMenuService, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ILocalizedString } from 'vs/platform/action/common/action'; -import { createAndFillInContextMenuActions, createAndFillInActionBarActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { createAndFillInActionBarActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, TUNNEL_VIEW_ID, parseAddress, CandidatePort, TunnelEditId, mapHasAddressLocalhostOrAllInterfaces, Attributes, TunnelSource } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -1023,14 +1023,11 @@ export class TunnelPanel extends ViewPane { this.portChangableContextKey.set(false); } - const menu = this.menuService.createMenu(MenuId.TunnelContext, this.table.contextKeyService); - const actions: IAction[] = []; - createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, actions); - menu.dispose(); - this.contextMenuService.showContextMenu({ + menuId: MenuId.TunnelContext, + menuActionOptions: { shouldForwardArgs: true }, + contextKeyService: this.table.contextKeyService, getAnchor: () => event.anchor, - getActions: () => actions, getActionViewItem: (action) => { const keybinding = this.keybindingService.lookupKeybinding(action.id); if (keybinding) { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 4595b58eb50..9d98dbbadf4 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -10,7 +10,6 @@ import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; -import { IAction } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Color, RGBA } from 'vs/base/common/color'; import * as errors from 'vs/base/common/errors'; @@ -33,8 +32,7 @@ import { CommonFindController } from 'vs/editor/contrib/find/browser/findControl import { MultiCursorSelectionController } from 'vs/editor/contrib/multicursor/browser/multicursor'; import * as nls from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -122,8 +120,6 @@ export class SearchView extends ViewPane { private hasFilePatternKey: IContextKey; private hasSomeCollapsibleResultKey: IContextKey; - private contextMenu: IMenu | null = null; - private tree!: WorkbenchCompressibleObjectTree; private treeLabels!: ResourceLabels; private viewletState: MementoObject; @@ -179,7 +175,6 @@ export class SearchView extends ViewPane { @IThemeService themeService: IThemeService, @ISearchHistoryService private readonly searchHistoryService: ISearchHistoryService, @IContextMenuService contextMenuService: IContextMenuService, - @IMenuService private readonly menuService: IMenuService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, @IKeybindingService keybindingService: IKeybindingService, @IStorageService storageService: IStorageService, @@ -824,19 +819,15 @@ export class SearchView extends ViewPane { } private onContextMenu(e: ITreeContextMenuEvent): void { - if (!this.contextMenu) { - this.contextMenu = this._register(this.menuService.createMenu(MenuId.SearchContext, this.contextKeyService)); - } e.browserEvent.preventDefault(); e.browserEvent.stopPropagation(); - const actions: IAction[] = []; - createAndFillInContextMenuActions(this.contextMenu, { shouldForwardArgs: true }, actions); - this.contextMenuService.showContextMenu({ + menuId: MenuId.SearchContext, + menuActionOptions: { shouldForwardArgs: true }, + contextKeyService: this.contextKeyService, getAnchor: () => e.anchor, - getActions: () => actions, getActionsContext: () => e.element, }); } diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 88266a40eeb..2d7cb9c0866 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -6,7 +6,6 @@ import { isFirefox } from 'vs/base/browser/browser'; import { addDisposableListener, EventType } from 'vs/base/browser/dom'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { IAction } from 'vs/base/common/actions'; import { ThrottledDelayer } from 'vs/base/common/async'; import { streamToBuffer, VSBufferReadableStream } from 'vs/base/common/buffer'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; @@ -17,7 +16,6 @@ import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { localize } from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -340,19 +338,14 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD return; } const elementBox = this.element.getBoundingClientRect(); + const contextKeyService = this._contextKeyService!.createOverlay([ + ...Object.entries(data.context), + [webviewIdContext, this.providedViewType], + ]); contextMenuService.showContextMenu({ - getActions: () => { - const contextKeyService = this._contextKeyService!.createOverlay([ - ...Object.entries(data.context), - [webviewIdContext, this.providedViewType], - ]); - - const result: IAction[] = []; - const menu = menuService.createMenu(MenuId.WebviewContext, contextKeyService); - createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result); - menu.dispose(); - return result; - }, + menuId: MenuId.WebviewContext, + menuActionOptions: { shouldForwardArgs: true }, + contextKeyService, getActionsContext: (): WebviewActionContext => ({ ...data.context, webview: this.providedViewType }), getAnchor: () => ({ x: elementBox.x + data.clientX, diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts index 2f991be2339..062d06db50f 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts @@ -11,7 +11,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { isMacintosh, isWindows, isLinux, isNative } from 'vs/base/common/platform'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { TitlebarPart as BrowserTitleBarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -62,13 +62,12 @@ export class TitlebarPart extends BrowserTitleBarPart { @IThemeService themeService: IThemeService, @IStorageService storageService: IStorageService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, - @IMenuService menuService: IMenuService, @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, @INativeHostService private readonly nativeHostService: INativeHostService, @IHoverService hoverService: IHoverService, ) { - super(contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, menuService, contextKeyService, hostService, hoverService); + super(contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, hoverService); this.environmentService = environmentService; } From 64c7d125c7d18f0c9adc77300829ab87d6d1e7dd Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 30 Sep 2022 16:05:17 -0700 Subject: [PATCH 252/599] testing: add support for jumping to test messages in terminal output (#162406) --- .../testing/browser/testingOutputPeek.ts | 20 ++++++++++++--- .../browser/testingOutputTerminalService.ts | 21 ++++++++++++---- .../contrib/testing/common/testResult.ts | 25 ++++++++++++++++--- .../contrib/testing/common/testTypes.ts | 7 ++++++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index bed3955d83c..d401d33c5da 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -1166,6 +1166,7 @@ class TestMessageElement implements ITreeElement { public readonly uri: URI; public readonly location?: IRichLocation; public readonly description?: string; + public readonly marker?: number; constructor( public readonly result: ITestResult, @@ -1173,9 +1174,10 @@ class TestMessageElement implements ITreeElement { public readonly taskIndex: number, public readonly messageIndex: number, ) { - const { message, location } = test.tasks[taskIndex].messages[messageIndex]; + const m = test.tasks[taskIndex].messages[messageIndex]; - this.location = location; + this.location = m.location; + this.marker = m.type === TestMessageType.Output ? m.marker : undefined; this.uri = this.context = buildTestUri({ type: TestUriType.ResultMessage, messageIndex, @@ -1186,7 +1188,7 @@ class TestMessageElement implements ITreeElement { this.id = this.uri.toString(); - const asPlaintext = renderStringAsPlaintext(message); + const asPlaintext = renderStringAsPlaintext(m.message); const lines = count(asPlaintext.trimRight(), '\n'); this.label = firstLine(asPlaintext); if (lines > 0) { @@ -1597,6 +1599,18 @@ class TreeActionsProvider { } } + if (element instanceof TestMessageElement) { + if (element.marker !== undefined) { + primary.push(new Action( + 'testing.outputPeek.showMessageInTerminal', + localize('testing.showMessageInTerminal', "Show Output in Terminal"), + Codicon.terminal.classNames, + undefined, + () => this.testTerminalService.open(element.result, element.marker), + )); + } + } + const result = { primary, secondary }; createAndFillInActionBarActions(menu, { shouldForwardArgs: true, diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts index 70f9d91907a..1786fe37813 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts @@ -17,15 +17,17 @@ import { TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal' import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons'; import { ITestResult } from 'vs/workbench/contrib/testing/common/testResult'; import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { getMarkId } from 'vs/workbench/contrib/testing/common/testTypes'; export interface ITestingOutputTerminalService { _serviceBrand: undefined; /** - * Opens a terminal for the given test's output. + * Opens a terminal for the given test's output. Optionally, scrolls to and + * selects the given marker in the test results. */ - open(result: ITestResult): Promise; + open(result: ITestResult, marker?: number): Promise; } const friendlyDate = (date: number) => { @@ -78,7 +80,7 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi /** * @inheritdoc */ - public async open(result: ITestResult | undefined): Promise { + public async open(result: ITestResult | undefined, marker?: number): Promise { const testOutputPtys = this.terminalService.instances .map(t => { const output = this.outputTerminals.get(t); @@ -95,6 +97,8 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi } else { this.terminalGroupService.showPanel(); } + + this.revealMarker(existing[0], marker); return; } @@ -114,10 +118,10 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi customPtyImplementation: () => output, name: getTitle(result), }, - }), output, result); + }), output, result, marker); } - private async showResultsInTerminal(terminal: ITerminalInstance, output: TestOutputProcess, result: ITestResult | undefined) { + private async showResultsInTerminal(terminal: ITerminalInstance, output: TestOutputProcess, result: ITestResult | undefined, thenSelectMarker?: number) { this.outputTerminals.set(terminal, output); output.resetFor(result?.id, getTitle(result)); this.terminalService.setActiveInstance(terminal); @@ -151,9 +155,16 @@ export class TestingOutputTerminalService implements ITestingOutputTerminalServi const text = localize('runFinished', 'Test run finished at {0}', completedAt.toLocaleString()); output.pushData(`\r\n\r\n\x1b[1m> ${text} <\x1b[0m\r\n\r\n`); output.ended = true; + this.revealMarker(terminal, thenSelectMarker); }, }); } + + private revealMarker(terminal: ITerminalInstance, marker?: number) { + if (marker !== undefined) { + terminal.scrollToMark(getMarkId(marker, true), getMarkId(marker, false), true); + } + } } class TestOutputProcess extends Disposable implements ITerminalChildProcess { diff --git a/src/vs/workbench/contrib/testing/common/testResult.ts b/src/vs/workbench/contrib/testing/common/testResult.ts index eb0114497e2..670d740e1ba 100644 --- a/src/vs/workbench/contrib/testing/common/testResult.ts +++ b/src/vs/workbench/contrib/testing/common/testResult.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contrib/testing/common/getComputedState'; import { IObservableValue, MutableObservableValue, staticObservableValue } from 'vs/workbench/contrib/testing/common/observableValue'; -import { IRichLocation, ISerializedTestResults, ITestItem, ITestMessage, ITestOutputMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestItemExpandState, TestMessageType, TestResultItem, TestResultState } from 'vs/workbench/contrib/testing/common/testTypes'; +import { getMarkId, IRichLocation, ISerializedTestResults, ITestItem, ITestMessage, ITestOutputMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestItemExpandState, TestMessageType, TestResultItem, TestResultState } from 'vs/workbench/contrib/testing/common/testTypes'; import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage'; import { maxPriority, statesInOrder, terminalStatePriorities } from 'vs/workbench/contrib/testing/common/testingStates'; import { removeAnsiEscapeCodes } from 'vs/base/common/strings'; @@ -130,6 +130,7 @@ export const maxCountPriority = (counts: Readonly) => { return TestResultState.Unset; }; +const getMarkCode = (marker: number, start: boolean) => `\x1b]633;SetMark;Id=${getMarkId(marker, start)};Hidden\x07`; /** * Deals with output of a {@link LiveTestResult}. By default we pass-through @@ -162,11 +163,19 @@ export class LiveOutputController { /** * Appends data to the output. */ - public append(data: VSBuffer): Promise | void { + public append(data: VSBuffer, marker?: number): Promise | void { if (this.closed) { return this.closed; } + if (marker !== undefined) { + data = VSBuffer.concat([ + VSBuffer.fromString(getMarkCode(marker, true)), + data, + VSBuffer.fromString(getMarkCode(marker, false)), + ]); + } + this.previouslyWritten?.push(data); this.dataEmitter.fire(data); this._offset += data.byteLength; @@ -285,6 +294,7 @@ export class LiveTestResult implements ITestResult { private readonly completeEmitter = new Emitter(); private readonly changeEmitter = new Emitter(); private readonly testById = new Map(); + private testMarkerCounter = 0; private _completedAt?: number; public readonly onChange = this.changeEmitter.event; @@ -352,15 +362,24 @@ export class LiveTestResult implements ITestResult { */ public appendOutput(output: VSBuffer, taskId: string, location?: IRichLocation, testId?: string): void { const preview = output.byteLength > 100 ? output.slice(0, 100).toString() + '…' : output.toString(); + let marker: number | undefined; + + // currently, the UI only exposes jump-to-message from tests or locations, + // so no need to mark outputs that don't come from either of those. + if (testId || location) { + marker = this.testMarkerCounter++; + } + const message: ITestOutputMessage = { location, message: removeAnsiEscapeCodes(preview), offset: this.output.offset, length: output.byteLength, + marker: marker, type: TestMessageType.Output, }; - this.output.append(output); + this.output.append(output, marker); const index = this.mustGetTaskIndex(taskId); if (testId) { diff --git a/src/vs/workbench/contrib/testing/common/testTypes.ts b/src/vs/workbench/contrib/testing/common/testTypes.ts index bf2ac6d4ba6..f7c2f4d0aae 100644 --- a/src/vs/workbench/contrib/testing/common/testTypes.ts +++ b/src/vs/workbench/contrib/testing/common/testTypes.ts @@ -163,9 +163,16 @@ export interface ITestOutputMessage { type: TestMessageType.Output; offset: number; length: number; + marker?: number; location: IRichLocation | undefined; } +/** + * Gets the TTY marker ID for either starting or ending + * an ITestOutputMessage.marker of the given ID. + */ +export const getMarkId = (marker: number, start: boolean) => `${start ? 's' : 'e'}${marker}`; + export namespace ITestOutputMessage { export interface Serialized { message: string; From 61f8dee571efac71035000f4c57f1c42ada04e46 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 30 Sep 2022 18:52:06 -0700 Subject: [PATCH 253/599] Use correct context key service in code action widget (#162478) Fixes #162477 This fixes a bug where the code action widget could get stuck using the wrong context key service --- .../codeAction/browser/codeActionUi.ts | 6 ++-- .../codeAction/browser/codeActionWidget.ts | 30 ++++++++++--------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index 13e0d5fe187..3066ae54574 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -15,6 +15,7 @@ import { CodeActionTriggerType } from 'vs/editor/common/languages'; import { CodeActionItem, CodeActionSet } from 'vs/editor/contrib/codeAction/browser/codeAction'; import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CodeActionsState } from './codeActionModel'; import { CodeActionShowOptions, CodeActionWidget } from './codeActionWidget'; @@ -34,8 +35,9 @@ export class CodeActionUi extends Disposable { private readonly delegate: { applyCodeAction: (action: CodeActionItem, regtriggerAfterApply: boolean, preview: boolean) => Promise; }, - @IInstantiationService private readonly _instantiationService: IInstantiationService, @IConfigurationService private readonly _configurationService: IConfigurationService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); @@ -166,7 +168,7 @@ export class CodeActionUi extends Disposable { onHide: () => { this._editor?.focus(); }, - }); + }, this._contextKeyService); } private toCoords(position: IPosition): IAnchor { diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts index 559128914f4..a35cb65a441 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.ts @@ -20,7 +20,7 @@ import { CodeActionKind, CodeActionTrigger, CodeActionTriggerSource } from 'vs/e import 'vs/editor/contrib/symbolIcons/browser/symbolIcons'; // The codicon symbol colors are defined here and must be loaded to get colors import { localize } from 'vs/nls'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -369,40 +369,44 @@ export class CodeActionWidget extends Disposable { readonly container: HTMLElement | undefined; readonly codeActions: CodeActionSet; readonly delegate: CodeActionWidgetDelegate; + readonly contextKeyService: IContextKeyService; }; - private readonly _ctxMenuWidgetVisible: IContextKey; - constructor( @ICommandService private readonly _commandService: ICommandService, - @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IContextViewService private readonly _contextViewService: IContextViewService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @ITelemetryService private readonly _telemetryService: ITelemetryService, ) { super(); - - this._ctxMenuWidgetVisible = Context.Visible.bindTo(this._contextKeyService); } get isVisible(): boolean { return !!this.currentShowingContext; } - public async show(trigger: CodeActionTrigger, codeActions: CodeActionSet, anchor: IAnchor, container: HTMLElement | undefined, options: CodeActionShowOptions, delegate: CodeActionWidgetDelegate): Promise { + public async show(trigger: CodeActionTrigger, codeActions: CodeActionSet, anchor: IAnchor, container: HTMLElement | undefined, options: CodeActionShowOptions, delegate: CodeActionWidgetDelegate, contextKeyService: IContextKeyService): Promise { this.currentShowingContext = undefined; + const visibleContext = Context.Visible.bindTo(contextKeyService); const actionsToShow = options.includeDisabledActions && (showDisabled || codeActions.validActions.length === 0) ? codeActions.allActions : codeActions.validActions; if (!actionsToShow.length) { + visibleContext.reset(); return; } - this.currentShowingContext = { trigger, codeActions, anchor, container, delegate, options }; + this.currentShowingContext = { trigger, codeActions, anchor, container, delegate, options, contextKeyService }; this._contextViewService.showContextView({ getAnchor: () => anchor, - render: (container: HTMLElement) => this.renderWidget(container, trigger, codeActions, options, actionsToShow, delegate), - onHide: (didCancel: boolean) => this.onWidgetClosed(trigger, options, codeActions, didCancel, delegate), + render: (container: HTMLElement) => { + visibleContext.set(true); + return this.renderWidget(container, trigger, codeActions, options, actionsToShow, delegate); + }, + onHide: (didCancel: boolean) => { + visibleContext.reset(); + return this.onWidgetClosed(trigger, options, codeActions, didCancel, delegate); + }, }, container, false); } @@ -487,8 +491,6 @@ export class CodeActionWidget extends Disposable { const focusTracker = renderDisposables.add(dom.trackFocus(element)); renderDisposables.add(focusTracker.onDidBlur(() => this.hide())); - this._ctxMenuWidgetVisible.set(true); - return renderDisposables; } @@ -503,7 +505,7 @@ export class CodeActionWidget extends Disposable { showDisabled = newShowDisabled; if (previousCtx) { - this.show(previousCtx.trigger, previousCtx.codeActions, previousCtx.anchor, previousCtx.container, previousCtx.options, previousCtx.delegate); + this.show(previousCtx.trigger, previousCtx.codeActions, previousCtx.anchor, previousCtx.container, previousCtx.options, previousCtx.delegate, previousCtx.contextKeyService); } } @@ -529,7 +531,7 @@ export class CodeActionWidget extends Disposable { }); this.currentShowingContext = undefined; - this._ctxMenuWidgetVisible.reset(); + delegate.onHide(cancelled); } From ef802ebe7af412860387ac984682f6c86880af5c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 2 Oct 2022 23:11:47 -0700 Subject: [PATCH 254/599] Properly fire selection change event when switching from a dynamic config to a configured config with the same name (#162501) Fix #156632 --- .../browser/debugConfigurationManager.ts | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index 3c2568989db..fe3d0e29842 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -3,41 +3,41 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { Event, Emitter } from 'vs/base/common/event'; -import * as objects from 'vs/base/common/objects'; -import * as json from 'vs/base/common/json'; -import { URI as uri } from 'vs/base/common/uri'; -import * as resources from 'vs/base/common/resources'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { IEditorPane } from 'vs/workbench/common/editor'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IDebugConfigurationProvider, ICompound, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, CONTEXT_DEBUG_CONFIGURATION_TYPE, IConfigPresentation, DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug'; -import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; -import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { launchSchema } from 'vs/workbench/contrib/debug/common/debugSchemas'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { withUndefinedAsNull } from 'vs/base/common/types'; +import { distinct, flatten } from 'vs/base/common/arrays'; import { sequence } from 'vs/base/common/async'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { flatten, distinct } from 'vs/base/common/arrays'; -import { getVisibleAndSorted } from 'vs/workbench/contrib/debug/common/debugUtils'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { Emitter, Event } from 'vs/base/common/event'; +import * as json from 'vs/base/common/json'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import * as objects from 'vs/base/common/objects'; +import * as resources from 'vs/base/common/resources'; +import { withUndefinedAsNull } from 'vs/base/common/types'; +import { URI as uri } from 'vs/base/common/uri'; +import * as nls from 'vs/nls'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IEditorPane } from 'vs/workbench/common/editor'; import { AdapterManager } from 'vs/workbench/contrib/debug/browser/debugAdapterManager'; import { debugConfigure } from 'vs/workbench/contrib/debug/browser/debugIcons'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { CONTEXT_DEBUG_CONFIGURATION_TYPE, DebugConfigurationProviderTriggerKind, ICompound, IConfig, IConfigPresentation, IConfigurationManager, IDebugConfigurationProvider, IGlobalConfig, ILaunch } from 'vs/workbench/contrib/debug/common/debug'; +import { launchSchema } from 'vs/workbench/contrib/debug/common/debugSchemas'; +import { getVisibleAndSorted } from 'vs/workbench/contrib/debug/common/debugUtils'; +import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); jsonRegistry.registerSchema(launchSchemaId, launchSchema); @@ -56,6 +56,7 @@ export class ConfigurationManager implements IConfigurationManager { private selectedLaunch: ILaunch | undefined; private getSelectedConfig: () => Promise = () => Promise.resolve(undefined); private selectedType: string | undefined; + private selectedDynamic = false; private toDispose: IDisposable[]; private readonly _onDidSelectConfigurationName = new Emitter(); private configProviders: IDebugConfigurationProvider[]; @@ -279,7 +280,7 @@ export class ConfigurationManager implements IConfigurationManager { removeRecentDynamicConfigurations(name: string, type: string) { const remaining = this.getRecentDynamicConfigurations().filter(c => c.name !== name || c.type !== type); this.storageService.store(DEBUG_RECENT_DYNAMIC_CONFIGURATIONS, JSON.stringify(remaining), StorageScope.WORKSPACE, StorageTarget.USER); - if (this.selectedConfiguration.name === name && this.selectedType === type) { + if (this.selectedConfiguration.name === name && this.selectedType === type && this.selectedDynamic) { this.selectConfiguration(undefined, undefined); } else { this._onDidSelectConfigurationName.fire(); @@ -377,6 +378,7 @@ export class ConfigurationManager implements IConfigurationManager { const previousLaunch = this.selectedLaunch; const previousName = this.selectedName; + const previousSelectedDynamic = this.selectedDynamic; this.selectedLaunch = launch; if (this.selectedLaunch) { @@ -436,6 +438,7 @@ export class ConfigurationManager implements IConfigurationManager { } this.selectedType = dynamicConfig?.type || config?.type; + this.selectedDynamic = !!dynamicConfig; // Only store the selected type if we are having a dynamic configuration. Otherwise restoring this configuration from storage might be misindentified as a dynamic configuration this.storageService.store(DEBUG_SELECTED_TYPE, dynamicConfig ? this.selectedType : undefined, StorageScope.WORKSPACE, StorageTarget.MACHINE); @@ -445,7 +448,7 @@ export class ConfigurationManager implements IConfigurationManager { this.debugConfigurationTypeContext.reset(); } - if (this.selectedLaunch !== previousLaunch || this.selectedName !== previousName) { + if (this.selectedLaunch !== previousLaunch || this.selectedName !== previousName || previousSelectedDynamic !== this.selectedDynamic) { this._onDidSelectConfigurationName.fire(); } } From 35c9252094e00ea1eac490c57b1be7d70273fdac Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 3 Oct 2022 11:43:39 +0200 Subject: [PATCH 255/599] fix debt/issue with symbol navigation for inline hints (#162545) --- .../editor/contrib/gotoSymbol/browser/goToCommands.ts | 10 +++++++--- .../contrib/inlayHints/browser/inlayHintsLocations.ts | 11 +++++------ src/vs/platform/actions/common/actions.ts | 10 +++++++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts index cc7d0b8c67a..c3f073892da 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts @@ -79,9 +79,11 @@ export abstract class SymbolNavigationAction extends EditorAction2 { private static _allSymbolNavigationCommands = new Map(); private static _activeAlternativeCommands = new Set(); - readonly configuration: SymbolNavigationActionConfig; + static all(): IterableIterator { + return SymbolNavigationAction._allSymbolNavigationCommands.values(); + } - private static aaa(opts: IAction2Options): IAction2Options { + private static _patchConfig(opts: IAction2Options): IAction2Options { const result = { ...opts, f1: true }; // patch context menu when clause if (result.menu) { @@ -95,8 +97,10 @@ export abstract class SymbolNavigationAction extends EditorAction2 { return result; } + readonly configuration: SymbolNavigationActionConfig; + constructor(configuration: SymbolNavigationActionConfig, opts: IAction2Options) { - super(SymbolNavigationAction.aaa(opts)); + super(SymbolNavigationAction._patchConfig(opts)); this.configuration = configuration; SymbolNavigationAction._allSymbolNavigationCommands.set(opts.id, this); } diff --git a/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts b/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts index 89f650807bb..77706619c1c 100644 --- a/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts +++ b/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts @@ -7,7 +7,6 @@ import * as dom from 'vs/base/browser/dom'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { Location } from 'vs/editor/common/languages'; @@ -16,7 +15,7 @@ import { DefinitionAction, SymbolNavigationAction, SymbolNavigationAnchor } from import { ClickLinkMouseEvent } from 'vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture'; import { RenderedInlayHintLabelPart } from 'vs/editor/contrib/inlayHints/browser/inlayHintsController'; import { PeekContext } from 'vs/editor/contrib/peekView/browser/peekView'; -import { isIMenuItem, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { isIMenuItem, MenuId, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -41,13 +40,13 @@ export async function showGoToContextMenu(accessor: ServicesAccessor, editor: IC const menuActions: IAction[] = []; // from all registered (not active) context menu actions select those - // that are a symbol navigation action + // that are a symbol navigation actions const filter = new Set(MenuRegistry.getMenuItems(MenuId.EditorContext) .map(item => isIMenuItem(item) ? item.command.id : '')); - for (const delegate of EditorExtensionsRegistry.getEditorActions()) { - if (delegate instanceof SymbolNavigationAction && filter.has(delegate.id)) { - menuActions.push(new Action(delegate.id, delegate.label, undefined, true, async () => { + for (const delegate of SymbolNavigationAction.all()) { + if (filter.has(delegate.desc.id)) { + menuActions.push(new Action(delegate.desc.id, MenuItemAction.label(delegate.desc, { renderShortTitle: true }), undefined, true, async () => { const ref = await resolverService.createModelReference(location.uri); try { await instaService.invokeFunction(delegate.run.bind(delegate), editor, new SymbolNavigationAnchor(ref.object.textEditorModel, Range.getStartPosition(location.range))); diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index ea836c330a6..d139df46141 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -397,6 +397,12 @@ export interface IMenuItemHide { // subscribes to events of Action or modified properties export class MenuItemAction implements IAction { + static label(action: ICommandAction, options?: IMenuActionOptions): string { + return options?.renderShortTitle && action.shortTitle + ? (typeof action.shortTitle === 'string' ? action.shortTitle : action.shortTitle.value) + : (typeof action.title === 'string' ? action.title : action.title.value); + } + readonly item: ICommandAction; readonly alt: MenuItemAction | undefined; @@ -418,9 +424,7 @@ export class MenuItemAction implements IAction { @ICommandService private _commandService: ICommandService ) { this.id = item.id; - this.label = options?.renderShortTitle && item.shortTitle - ? (typeof item.shortTitle === 'string' ? item.shortTitle : item.shortTitle.value) - : (typeof item.title === 'string' ? item.title : item.title.value); + this.label = MenuItemAction.label(item, options); this.tooltip = (typeof item.tooltip === 'string' ? item.tooltip : item.tooltip?.value) ?? ''; this.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition); this.checked = undefined; From 85bf7f1d9b96183e3876c78664433777ad89ce19 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Mon, 3 Oct 2022 11:04:56 +0200 Subject: [PATCH 256/599] Update schema with new properties (microsoft/vscode-remote-release#7278) --- .../devContainer.schema.generated.json | 439 +++++++++++++++--- .../schemas/devContainer.schema.src.json | 94 +++- 2 files changed, 461 insertions(+), 72 deletions(-) diff --git a/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json index 14fdc3648b3..f94a40021e1 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -62,24 +62,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -278,6 +260,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -679,24 +738,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -895,6 +936,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -1262,24 +1380,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -1478,6 +1578,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -2035,6 +2212,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -2557,6 +2811,83 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ + "SYS_PTRACE" + ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ + "seccomp=unconfined" + ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { diff --git a/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json index e8bb724d8cb..f908f29ac59 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -177,6 +177,55 @@ "type": "boolean", "description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default when opening from a local folder." }, + "containerEnv": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Container environment variables." + }, + "containerUser": { + "type": "string", + "description": "The user the container will be started with. The default is the user on the Docker image." + }, + "mounts": { + "type": "array", + "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/Mount" + }, + { + "type": "string" + } + ] + } + }, + "init": { + "type": "boolean", + "description": "Passes the --init flag when creating the dev container." + }, + "privileged": { + "type": "boolean", + "description": "Passes the --privileged flag when creating the dev container." + }, + "capAdd": { + "type": "array", + "description": "Passes docker capabilities to include when creating the dev container.", + "examples": [ "SYS_PTRACE" ], + "items": { + "type": "string" + } + }, + "securityOpt": { + "type": "array", + "description": "Passes docker security options to include when creating the dev container.", + "examples": [ "seccomp=unconfined" ], + "items": { + "type": "string" + } + }, "remoteEnv": { "type": "object", "additionalProperties": { @@ -536,24 +585,6 @@ ] } }, - "containerEnv": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Container environment variables." - }, - "containerUser": { - "type": "string", - "description": "The user the container will be started with. The default is the user on the Docker image." - }, - "mounts": { - "type": "array", - "description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.", - "items": { - "type": "string" - } - }, "runArgs": { "type": "array", "description": "The arguments required when starting in the container.", @@ -735,6 +766,33 @@ "service", "workspaceFolder" ] + }, + "Mount": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "bind", + "volume" + ], + "description": "Mount type." + }, + "source": { + "type": "string", + "description": "Mount source." + }, + "target": { + "type": "string", + "description": "Mount target." + } + }, + "required": [ + "type", + "source", + "target" + ], + "additionalProperties": false } }, "oneOf": [ From 24dce19e24abdbb698274c4a1deb49da10fa1c5e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 3 Oct 2022 11:52:46 +0200 Subject: [PATCH 257/599] delayed IExtensionUrlTrustService, (#162554) https://github.com/microsoft/vscode/issues/159178 --- .../extensionManagement/browser/extensionUrlTrustService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts index 9df7560ac34..31127de9b07 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; class ExtensionUrlTrustService implements IExtensionUrlTrustService { @@ -15,4 +15,4 @@ class ExtensionUrlTrustService implements IExtensionUrlTrustService { } } -registerSingleton(IExtensionUrlTrustService, ExtensionUrlTrustService, false); +registerSingleton(IExtensionUrlTrustService, ExtensionUrlTrustService, InstantiationType.Delayed); From 8da400cf7079dac625ea59ee7822cab7a03cc5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 3 Oct 2022 03:06:08 -0700 Subject: [PATCH 258/599] make sure VSCODE_RELEASE works even if quality is frozen (#162556) --- build/azure-pipelines/common/releaseBuild.js | 17 ++++++++++------- build/azure-pipelines/common/releaseBuild.ts | 19 ++++++++++++------- build/azure-pipelines/product-build.yml | 2 ++ build/azure-pipelines/product-release.yml | 6 +++++- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/build/azure-pipelines/common/releaseBuild.js b/build/azure-pipelines/common/releaseBuild.js index 9e96781eb67..eba9b2dc8b7 100644 --- a/build/azure-pipelines/common/releaseBuild.js +++ b/build/azure-pipelines/common/releaseBuild.js @@ -28,22 +28,25 @@ async function getConfig(client, quality) { } return res.resources[0]; } -async function main() { +async function main(force) { const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); const quality = getEnv('VSCODE_QUALITY'); const aadCredentials = new identity_1.ClientSecretCredential(process.env['AZURE_TENANT_ID'], process.env['AZURE_CLIENT_ID'], process.env['AZURE_CLIENT_SECRET']); const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], aadCredentials }); - const config = await getConfig(client, quality); - console.log('Quality config:', config); - if (config.frozen) { - console.log(`Skipping release because quality ${quality} is frozen.`); - return; + if (!force) { + const config = await getConfig(client, quality); + console.log('Quality config:', config); + if (config.frozen) { + console.log(`Skipping release because quality ${quality} is frozen.`); + return; + } } console.log(`Releasing build ${commit}...`); const scripts = client.database('builds').container(quality).scripts; await (0, retry_1.retry)(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); } -main().then(() => { +const [, , force] = process.argv; +main(force === 'true').then(() => { console.log('Build successfully released'); process.exit(0); }, err => { diff --git a/build/azure-pipelines/common/releaseBuild.ts b/build/azure-pipelines/common/releaseBuild.ts index 3b163b6b619..68476cc2952 100644 --- a/build/azure-pipelines/common/releaseBuild.ts +++ b/build/azure-pipelines/common/releaseBuild.ts @@ -41,19 +41,22 @@ async function getConfig(client: CosmosClient, quality: string): Promise return res.resources[0] as Config; } -async function main(): Promise { +async function main(force: boolean): Promise { const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); const quality = getEnv('VSCODE_QUALITY'); const aadCredentials = new ClientSecretCredential(process.env['AZURE_TENANT_ID']!, process.env['AZURE_CLIENT_ID']!, process.env['AZURE_CLIENT_SECRET']!); const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, aadCredentials }); - const config = await getConfig(client, quality); - console.log('Quality config:', config); + if (!force) { + const config = await getConfig(client, quality); - if (config.frozen) { - console.log(`Skipping release because quality ${quality} is frozen.`); - return; + console.log('Quality config:', config); + + if (config.frozen) { + console.log(`Skipping release because quality ${quality} is frozen.`); + return; + } } console.log(`Releasing build ${commit}...`); @@ -62,7 +65,9 @@ async function main(): Promise { await retry(() => scripts.storedProcedure('releaseBuild').execute('', [commit])); } -main().then(() => { +const [, , force] = process.argv; + +main(force === 'true').then(() => { console.log('Build successfully released'); process.exit(0); }, err => { diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 666d9489da3..5781f0b3cef 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -621,3 +621,5 @@ stages: displayName: Release Build steps: - template: product-release.yml + parameters: + VSCODE_RELEASE: ${{ parameters.VSCODE_RELEASE }} diff --git a/build/azure-pipelines/product-release.yml b/build/azure-pipelines/product-release.yml index a1086945595..8be900a9b41 100644 --- a/build/azure-pipelines/product-release.yml +++ b/build/azure-pipelines/product-release.yml @@ -1,3 +1,7 @@ +parameters: + - name: VSCODE_RELEASE + type: boolean + steps: - task: NodeTool@0 inputs: @@ -20,4 +24,4 @@ steps: AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - node build/azure-pipelines/common/releaseBuild.js + node build/azure-pipelines/common/releaseBuild.js ${{ parameters.VSCODE_RELEASE }} From e36a81800fd6823851731d76b8494e832f551aa6 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 3 Oct 2022 12:06:50 +0200 Subject: [PATCH 259/599] Fixes #160269 (#162557) --- .../common/diff/standardLinesDiffComputer.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/vs/editor/common/diff/standardLinesDiffComputer.ts b/src/vs/editor/common/diff/standardLinesDiffComputer.ts index ce0b07c8a2e..464d33592fb 100644 --- a/src/vs/editor/common/diff/standardLinesDiffComputer.ts +++ b/src/vs/editor/common/diff/standardLinesDiffComputer.ts @@ -57,13 +57,45 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer { })(); const alignments: RangeMapping[] = []; + + const scanForWhitespaceChanges = (equalLinesCount: number) => { + for (let i = 0; i < equalLinesCount; i++) { + const seq1Offset = seq1LastStart + i; + const seq2Offset = seq2LastStart + i; + if (originalLines[seq1Offset] !== modifiedLines[seq2Offset]) { + // This is because of whitespace changes, diff these lines + const characterDiffs = this.refineDiff(originalLines, modifiedLines, new SequenceDiff( + new OffsetRange(seq1Offset, seq1Offset + 1), + new OffsetRange(seq2Offset, seq2Offset + 1) + )); + for (const a of characterDiffs) { + alignments.push(a); + } + } + } + }; + + let seq1LastStart = 0; + let seq2LastStart = 0; + for (const diff of lineAlignments) { + assertFn(() => diff.seq1Range.start - seq1LastStart === diff.seq2Range.start - seq2LastStart); + + const equalLinesCount = diff.seq1Range.start - seq1LastStart; + + scanForWhitespaceChanges(equalLinesCount); + + seq1LastStart = diff.seq1Range.endExclusive; + seq2LastStart = diff.seq2Range.endExclusive; + const characterDiffs = this.refineDiff(originalLines, modifiedLines, diff); for (const a of characterDiffs) { alignments.push(a); } } + scanForWhitespaceChanges(originalLines.length - seq1LastStart); + const changes: LineRangeMapping[] = lineRangeMappingFromRangeMappings(alignments); return { From f5b2542ccb4a6e0424654d0bd88a8c79e73d7cfb Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:12:00 +0200 Subject: [PATCH 260/599] Engineering - Update setting (#162558) Update setting --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3907bc758b4..0f3f3d6e48b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -70,7 +70,7 @@ ], "git.branchProtectionPrompt": "alwaysCommitToNewBranch", "git.branchRandomName.enable": true, - "git.fetchBeforeCheckout": true, + "git.pullBeforeCheckout": true, "git.mergeEditor": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" From 71e1ce19358fa1e6d1ec792ad3a32d36b5cfe037 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 3 Oct 2022 12:13:14 +0200 Subject: [PATCH 261/599] Enables experimental diff algorithm for merge editor. (#162559) --- .../contrib/mergeEditor/browser/mergeEditor.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index 6a5a7cd3bdc..4e3de4815a6 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -39,7 +39,7 @@ Registry.as(Extensions.Configuration).registerConfigurat 'mergeEditor.diffAlgorithm': { type: 'string', enum: ['smart', 'experimental'], - default: 'smart', + default: 'experimental', markdownEnumDescriptions: [ localize('diffAlgorithm.smart', "Uses the default diffing algorithm."), localize('diffAlgorithm.experimental', "Uses an experimental diffing algorithm."), From f74e6923dc2f8cb21e95a07bb04ec96ebe267db5 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:33:41 +0200 Subject: [PATCH 262/599] Engineering - Add reason filter to issue notebooks (#162560) Add reason filter to issue notebooks --- .vscode/notebooks/endgame.github-issues | 12 ++++++------ .vscode/notebooks/my-endgame.github-issues | 14 +++++++------- .vscode/notebooks/verification.github-issues | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index a9a74d1af88..bf214cf3c68 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -32,7 +32,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS -$MILESTONE is:issue is:closed label:bug label:insiders-released -label:verified -label:*duplicate -label:*as-designed -label:z-author-verified -label:on-testplan" + "value": "$REPOS -$MILESTONE is:issue is:closed reason:completed label:bug label:insiders-released -label:verified -label:*duplicate -label:*as-designed -label:z-author-verified -label:on-testplan" }, { "kind": 1, @@ -42,7 +42,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS -$MILESTONE is:issue is:closed label:feature-request label:insiders-released -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS -$MILESTONE is:issue is:closed reason:completed label:feature-request label:insiders-released -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -62,7 +62,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -97,7 +97,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed label:verification-needed -label:verified" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed label:verification-needed -label:verified" }, { "kind": 1, @@ -112,7 +112,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified -label:unreleased" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified -label:unreleased" }, { "kind": 1, @@ -122,7 +122,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE is:issue is:closed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified label:unreleased" + "value": "$REPOS $MILESTONE is:issue is:closed reason:completed sort:updated-asc label:bug -label:verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -label:z-author-verified label:unreleased" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 19381c385ae..4e86fcf6b63 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -42,7 +42,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" + "value": "$REPOS $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request -label:verification-needed -label:on-testplan -label:verified -label:*duplicate" }, { "kind": 1, @@ -62,7 +62,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE $MINE is:issue is:closed label:feature-request label:verification-needed -label:verified" + "value": "$REPOS $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request label:verification-needed -label:verified" }, { "kind": 1, @@ -87,7 +87,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed -label:verification-steps-needed -label:unreleased" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed -assignee:@me -label:verified -label:z-author-verified label:feature-request label:verification-needed -label:verification-steps-needed -label:unreleased" }, { "kind": 1, @@ -147,7 +147,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:triage-needed -label:verification-found" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:triage-needed -label:verification-found" }, { "kind": 1, @@ -157,7 +157,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:andreamah -author:bamurtaugh -author:bpasero -author:chrisdias -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:egamma -author:fiveisprime -author:gregvanl -author:hediet -author:IanMatthewHuff -author:isidorn -author:joaomoreno -author:joyceerhl -author:jrieken -author:karrtikr -author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:roblourens -author:rzhao271 -author:sandy081 -author:sbatten -author:stevencl -author:tanhakabir -author:TylerLeonhardt -author:Tyriar -author:weinand -author:amunger" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:andreamah -author:bamurtaugh -author:bpasero -author:chrisdias -author:chrmarti -author:Chuxel -author:claudiaregio -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:DonJayamanne -author:egamma -author:fiveisprime -author:gregvanl -author:hediet -author:IanMatthewHuff -author:isidorn -author:joaomoreno -author:joyceerhl -author:jrieken -author:karrtikr -author:kieferrm -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:roblourens -author:rzhao271 -author:sandy081 -author:sbatten -author:stevencl -author:tanhakabir -author:TylerLeonhardt -author:Tyriar -author:weinand -author:amunger" }, { "kind": 1, @@ -167,7 +167,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed -author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed reason:completed -author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found" }, { "kind": 1, @@ -177,6 +177,6 @@ { "kind": 2, "language": "github-issues", - "value": "repo:microsoft/vscode $MILESTONE $MINE is:issue is:closed label:feature-request -label:on-release-notes" + "value": "repo:microsoft/vscode $MILESTONE $MINE is:issue is:closed reason:completed label:feature-request -label:on-release-notes" } ] \ No newline at end of file diff --git a/.vscode/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues index 7015a401be5..d34a821f2f9 100644 --- a/.vscode/notebooks/verification.github-issues +++ b/.vscode/notebooks/verification.github-issues @@ -22,7 +22,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate author:@me" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate author:@me" }, { "kind": 1, @@ -32,7 +32,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate -author:@me -assignee:@me label:bug -label:verified -author:@me -author:aeschli -author:alexdima -author:alexr00 -author:bpasero -author:chrisdias -author:chrmarti -author:connor4312 -author:dbaeumer -author:deepak1556 -author:eamodio -author:egamma -author:gregvanl -author:isidorn -author:JacksonKearl -author:joaomoreno -author:jrieken -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:RMacfarlane -author:roblourens -author:sana-ajani -author:sandy081 -author:sbatten -author:Tyriar -author:weinand -author:rzhao271 -author:kieferrm -author:TylerLeonhardt -author:bamurtaugh -author:hediet -author:joyceerhl -author:rchiodo -author:IanMatthewHuff" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate -author:@me -assignee:@me label:bug -label:verified -author:@me -author:aeschli -author:alexdima -author:alexr00 -author:bpasero -author:chrisdias -author:chrmarti -author:connor4312 -author:dbaeumer -author:deepak1556 -author:eamodio -author:egamma -author:gregvanl -author:isidorn -author:JacksonKearl -author:joaomoreno -author:jrieken -author:lramos15 -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:rebornix -author:RMacfarlane -author:roblourens -author:sana-ajani -author:sandy081 -author:sbatten -author:Tyriar -author:weinand -author:rzhao271 -author:kieferrm -author:TylerLeonhardt -author:bamurtaugh -author:hediet -author:joyceerhl -author:rchiodo -author:IanMatthewHuff" }, { "kind": 1, @@ -42,6 +42,6 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate" + "value": "$repos $milestone is:closed reason:completed -assignee:@me label:bug -label:verified -label:*duplicate" } ] \ No newline at end of file From 94ec9025eafbab9711ef24a86ce5e32409afb520 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 3 Oct 2022 21:35:58 +0900 Subject: [PATCH 263/599] build: use swiftshader on macOS CI (#162568) --- test/automation/src/electron.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/automation/src/electron.ts b/test/automation/src/electron.ts index f818b2b8136..1fea286c6cf 100644 --- a/test/automation/src/electron.ts +++ b/test/automation/src/electron.ts @@ -49,6 +49,15 @@ export async function resolveElectronConfiguration(options: LaunchOptions): Prom args.push('--disable-dev-shm-usage'); } + if (process.platform === 'darwin') { + // On macOS force software based rendering since we are seeing GPU process + // hangs when initializing GL context. This is very likely possible + // that there are new displays available in the CI hardware and + // the relevant drivers couldn't be loaded via the GPU sandbox. + // TODO(deepak1556): remove this switch with Electron update. + args.push('--use-gl=swiftshader'); + } + if (remote) { // Replace workspace path with URI args[0] = `--${workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(workspacePath).path}`; From 3551b7ec49b1ebc7f7614a7833ab7acce4fe384b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 3 Oct 2022 14:36:29 +0200 Subject: [PATCH 264/599] fix #162464 (#162564) --- src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts index 2697c75eb94..c6605c7ad7c 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts @@ -17,8 +17,8 @@ import { type ManualSyncTaskEvent = { manualSyncTaskId: string; data: T }; -function reviewSyncResource(syncResource: IUserDataSyncResource, userDataProfilesService: IUserDataProfilesService) { - return { ...syncResource, profie: reviveProfile(syncResource.profile, userDataProfilesService.profilesHome.scheme) }; +function reviewSyncResource(syncResource: IUserDataSyncResource, userDataProfilesService: IUserDataProfilesService): IUserDataSyncResource { + return { ...syncResource, profile: reviveProfile(syncResource.profile, userDataProfilesService.profilesHome.scheme) }; } export class UserDataSyncChannel implements IServerChannel { From d904014287cd51307b4595f42e0cd56bde7be0c0 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:02:24 +0200 Subject: [PATCH 265/599] Git - fix commitInProgress context key (#162562) Fix #154628 --- extensions/git/src/model.ts | 19 ++++++++++++++++++- extensions/git/src/repository.ts | 6 ++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 14ee4d66e74..1914f1fb134 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -5,7 +5,7 @@ import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, commands } from 'vscode'; import TelemetryReporter from '@vscode/extension-telemetry'; -import { Repository, RepositoryState } from './repository'; +import { Operation, Repository, RepositoryState } from './repository'; import { memoize, sequentialize, debounce } from './decorators'; import { dispose, anyEvent, filterEvent, isDescendant, pathEquals, toDisposable, eventToPromise } from './util'; import { Git } from './git'; @@ -467,11 +467,28 @@ export class Model implements IRemoteSourcePublisherRegistry, IPostCommitCommand }); checkForSubmodules(); + const updateCommitInProgressContext = () => { + let commitInProgress = false; + for (const { repository } of this.openRepositories.values()) { + if (repository.operations.isRunning(Operation.Commit)) { + commitInProgress = true; + break; + } + } + + commands.executeCommand('setContext', 'commitInProgress', commitInProgress); + }; + + const operationEvent = anyEvent(repository.onDidRunOperation as Event, repository.onRunOperation as Event); + const operationListener = operationEvent(() => updateCommitInProgressContext()); + updateCommitInProgressContext(); + const dispose = () => { disappearListener.dispose(); changeListener.dispose(); originalResourceChangeListener.dispose(); statusListener.dispose(); + operationListener.dispose(); repository.dispose(); this.openRepositories = this.openRepositories.filter(e => e !== openRepository); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 83120afcdc5..48dbdd5065d 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -460,10 +460,8 @@ class ProgressManager { this.updateEnablement(); this.repository.onDidChangeOperations(() => { - const commitInProgress = this.repository.operations.isRunning(Operation.Commit); - - this.repository.sourceControl.inputBox.enabled = !commitInProgress; - commands.executeCommand('setContext', 'commitInProgress', commitInProgress); + // Disable input box when the commit operation is running + this.repository.sourceControl.inputBox.enabled = !this.repository.operations.isRunning(Operation.Commit); }); } From 2ae09926ddbe9e6076a5736e3e393b614591dab9 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 3 Oct 2022 15:56:11 +0200 Subject: [PATCH 266/599] Fixes #162553 (#162576) --- .../mergeEditor/browser/view/editors/baseCodeEditorView.ts | 2 ++ .../browser/view/editors/inputCodeEditorView.ts | 3 ++- .../browser/view/editors/resultCodeEditorView.ts | 7 ++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts index b69a2d49b26..368dfff698e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts @@ -67,6 +67,7 @@ export class BaseCodeEditorView extends CodeEditorView { return []; } const model = viewModel.model; + const textModel = model.base; const activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader); const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); @@ -98,6 +99,7 @@ export class BaseCodeEditorView extends CodeEditorView { options: { showIfCollapsed: true, blockClassName: blockClassNames.join(' '), + blockIsAfterEnd: range.startLineNumber > textModel.getLineCount(), description: 'Merge Editor', minimap: { position: MinimapPosition.Gutter, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index 1ecc01b7864..dbebe6d026e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -122,6 +122,7 @@ export class InputCodeEditorView extends CodeEditorView { return []; } const model = viewModel.model; + const textModel = (this.inputNumber === 1 ? model.input1 : model.input2).textModel; const activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader); @@ -158,7 +159,7 @@ export class InputCodeEditorView extends CodeEditorView { options: { showIfCollapsed: true, blockClassName: blockClassNames.join(' '), - blockIsAfterEnd: range.startLineNumber > this.editor.getModel()!.getLineCount(), + blockIsAfterEnd: range.startLineNumber > textModel.getLineCount(), description: 'Merge Editor', minimap: { position: MinimapPosition.Gutter, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index 327707bed0b..a43d5ca319e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -113,6 +113,7 @@ export class ResultCodeEditorView extends CodeEditorView { return []; } const model = viewModel.model; + const textModel = model.resultTextModel; const result = new Array(); const baseRangeWithStoreAndTouchingDiffs = join( @@ -151,11 +152,13 @@ export class ResultCodeEditorView extends CodeEditorView { continue; } + const range = model.getLineRangeInResult(modifiedBaseRange.baseRange, reader); result.push({ - range: model.getLineRangeInResult(modifiedBaseRange.baseRange, reader).toInclusiveRangeOrEmpty(), + range: range.toInclusiveRangeOrEmpty(), options: { showIfCollapsed: true, blockClassName: blockClassNames.join(' '), + blockIsAfterEnd: range.startLineNumber > textModel.getLineCount(), description: 'Result Diff', minimap: { position: MinimapPosition.Gutter, @@ -167,10 +170,8 @@ export class ResultCodeEditorView extends CodeEditorView { } : undefined } }); - } - if (!modifiedBaseRange || modifiedBaseRange.isConflicting) { for (const diff of m.rights) { const range = diff.outputRange.toInclusiveRange(); From 44dc4afcdf84ee3d6a986f5c117735a60d322bf5 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 3 Oct 2022 16:08:40 +0200 Subject: [PATCH 267/599] use new, simpler way of showing context menu (fresh from the press) --- .../browser/stickyScrollController.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts index c67a8564a16..a5dc15c6e41 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts @@ -14,10 +14,7 @@ import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as dom from 'vs/base/browser/dom'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IAction } from 'vs/base/common/actions'; -import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; -import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { MenuId } from 'vs/platform/actions/common/actions'; export class StickyScrollController extends Disposable implements IEditorContribution { @@ -33,8 +30,6 @@ export class StickyScrollController extends Disposable implements IEditorContrib @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, @IInstantiationService _instaService: IInstantiationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IMenuService private readonly _menuService: IMenuService, - @IContextKeyService private readonly _contextKeyService: IContextKeyService, ) { super(); this._editor = _editor; @@ -64,15 +59,9 @@ export class StickyScrollController extends Disposable implements IEditorContrib } private onContextMenu(event: MouseEvent) { - const menu = this._menuService.createMenu(MenuId.StickyScrollContext, this._contextKeyService); - const actions: IAction[] = []; - createAndFillInContextMenuActions(menu, undefined, actions); this._contextMenuService.showContextMenu({ - getActions: () => actions, + menuId: MenuId.StickyScrollContext, getAnchor: () => event, - onHide: () => { - menu.dispose(); - } }); } From 3d6d3bfb475c7be71e18154e9851dd440bba43f9 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 3 Oct 2022 16:10:26 +0200 Subject: [PATCH 268/599] fix tests --- .../contrib/stickyScroll/test/browser/stickyScroll.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/test/browser/stickyScroll.test.ts b/src/vs/editor/contrib/stickyScroll/test/browser/stickyScroll.test.ts index 4f7e077bfbf..9e4e01fb994 100644 --- a/src/vs/editor/contrib/stickyScroll/test/browser/stickyScroll.test.ts +++ b/src/vs/editor/contrib/stickyScroll/test/browser/stickyScroll.test.ts @@ -13,12 +13,15 @@ import { DocumentSymbol, SymbolKind } from 'vs/editor/common/languages'; import { StickyLineCandidate, StickyLineCandidateProvider } from 'vs/editor/contrib/stickyScroll/browser/stickyScrollProvider'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { mock } from 'vs/base/test/common/mock'; suite('Sticky Scroll Tests', () => { const serviceCollection = new ServiceCollection( [ILanguageFeaturesService, new LanguageFeaturesService()], - [ILogService, new NullLogService()] + [ILogService, new NullLogService()], + [IContextMenuService, new class extends mock() { }] ); const text = [ From a69b853605b3b6fbdf1eebb7a6e78f68a14babca Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 3 Oct 2022 16:14:43 +0200 Subject: [PATCH 269/599] update notebook milestones (#162579) --- .vscode/notebooks/api.github-issues | 2 +- .vscode/notebooks/my-work.github-issues | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index fd582d87cf1..9bf483dbbcc 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"September 2022\"" + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"October 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 4562f07797d..376975e9dc3 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"September 2022\"" + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"October 2022\"" }, { "kind": 1, From 65c18dff87a12dac9c45861bf908daee71cf9afa Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 3 Oct 2022 16:15:37 +0200 Subject: [PATCH 270/599] Resolve `es5ClassCompat` performance issue (#162583) Co-authored-by: Qingpeng Li --- src/vs/workbench/api/common/extHostTypes.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 22e9e1f0441..7f44f88a23e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -28,12 +28,21 @@ import type * as vscode from 'vscode'; * but new ones must not be added * */ function es5ClassCompat(target: Function): any { - ///@ts-expect-error - function _() { return Reflect.construct(target, arguments, this.constructor); } - Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')!); - Object.setPrototypeOf(_, target); - Object.setPrototypeOf(_.prototype, target.prototype); - return _; + const interceptFunctions = { + apply: function () { + const args = arguments.length === 1 ? [] : arguments[1]; + return Reflect.construct(target, args, arguments[0].constructor); + }, + call: function () { + if (arguments.length === 0) { + return Reflect.construct(target, []); + } else { + const [thisArg, ...restArgs] = arguments; + return Reflect.construct(target, restArgs, thisArg.constructor); + } + } + }; + return Object.assign(target, interceptFunctions); } @es5ClassCompat From b274b3035ed57e34cbef407be569f7caf0f86024 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 3 Oct 2022 12:04:17 -0400 Subject: [PATCH 271/599] Don't call super withing keybinding input matches (#162588) Don't call super with Keybinding input --- .../services/preferences/browser/keybindingsEditorInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts b/src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts index 0e2f929af32..8987b464b18 100644 --- a/src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts +++ b/src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts @@ -44,7 +44,7 @@ export class KeybindingsEditorInput extends EditorInput { } override matches(otherInput: EditorInput | IUntypedEditorInput): boolean { - return super.matches(otherInput) || otherInput instanceof KeybindingsEditorInput; + return otherInput instanceof KeybindingsEditorInput; } override dispose(): void { From b7e1859c24108c47c2f006fb5982e5df0a72ada0 Mon Sep 17 00:00:00 2001 From: BK0717 <751533978@qq.com> Date: Tue, 4 Oct 2022 00:34:41 +0800 Subject: [PATCH 272/599] Add __vsc_prior_prompt2 (#156140) Co-authored-by: Megan Rogge --- .../contrib/terminal/browser/media/shellIntegration-rc.zsh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh index 0ab72f1886d..90612eb545b 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh @@ -87,6 +87,7 @@ if [[ -o NOUNSET ]]; then fi __vsc_update_prompt() { __vsc_prior_prompt="$PS1" + __vsc_prior_prompt2="$PS2" __vsc_in_command_execution="" PS1="%{$(__vsc_prompt_start)%}$PS1%{$(__vsc_prompt_end)%}" PS2="%{$(__vsc_continuation_start)%}$PS2%{$(__vsc_continuation_end)%}" @@ -115,6 +116,7 @@ __vsc_precmd() { __vsc_preexec() { PS1="$__vsc_prior_prompt" + PS2="$__vsc_prior_prompt2" if [ -n "$RPROMPT" ]; then RPROMPT="$__vsc_prior_rprompt" fi From 070558471f0a614b63724227a44cf4300ebe565c Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 3 Oct 2022 18:55:56 +0200 Subject: [PATCH 273/599] Some Cleanup (#162593) --- .../contrib/mergeEditor/browser/mergeEditorInput.ts | 5 +---- .../contrib/mergeEditor/browser/mergeEditorInputModel.ts | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 6f41a7f3632..d0e202909aa 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -66,7 +66,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements super.dispose(); } - get typeId(): string { + override get typeId(): string { return MergeEditorInput.ID; } @@ -76,11 +76,9 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements override get capabilities(): EditorInputCapabilities { let capabilities = super.capabilities | EditorInputCapabilities.MultipleEditors; - if (this.useWorkingCopy) { capabilities |= EditorInputCapabilities.Untitled; } - return capabilities; } @@ -171,6 +169,5 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements this._inputModel?.model.setLanguageId(languageId, source); } - // implement get/set languageId // implement get/set encoding } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index a7db1a6481e..2bd5c9b00c9 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -371,7 +371,6 @@ class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditor shouldConfirmClose(): boolean { // Always confirm return true; - //return this.resultTextFileModel.isDirty(); } async confirmClose(inputModels: IMergeEditorInputModel[]): Promise { @@ -400,7 +399,6 @@ class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditor ConfirmResult.SAVE, ], [localize('workspace.doNotSave', "Don't Save"), ConfirmResult.DONT_SAVE], - // TODO [localize('workspace.discard', "Discard changes"), ConfirmResult.DONT_SAVE], [localize('workspace.cancel', 'Cancel'), ConfirmResult.CANCEL], ]; @@ -426,7 +424,6 @@ class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditor : localize('workspace.close', 'Close'), ConfirmResult.SAVE, ], - // TODO [localize('workspace.discard', "Discard changes"), ConfirmResult.DONT_SAVE], [localize('workspace.cancel', 'Cancel'), ConfirmResult.CANCEL], ]; From bec1d5d1dc89da70f921cf5067dd0667b531ebb4 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 3 Oct 2022 09:59:34 -0700 Subject: [PATCH 274/599] Fix references to non-existent `runTests` API (#162543) --- src/vscode-dts/vscode.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index d1c831212b1..b6a65b4b93a 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -15818,9 +15818,9 @@ declare module 'vscode' { /** * A TestRunRequest is a precursor to a {@link TestRun}, which in turn is - * created by passing a request to {@link tests.runTests}. The TestRunRequest - * contains information about which tests should be run, which should not be - * run, and how they are run (via the {@link TestRunRequest.profile profile}). + * created by passing a request to {@link TestController.createTestRun}. The + * TestRunRequest contains information about which tests should be run, which + * should not be run, and how they are run (via the {@link TestRunRequest.profile profile}). * * In general, TestRunRequests are created by the editor and pass to * {@link TestRunProfile.runHandler}, however you can also create test @@ -15863,7 +15863,8 @@ declare module 'vscode' { } /** - * Options given to {@link TestController.runTests} + * A TestRun represents an in-progress or completed test run and + * provides methods to report the state of individual tests in the run. */ export interface TestRun { /** From 5edee3755c8994d0195d0b6596c3259d85e97747 Mon Sep 17 00:00:00 2001 From: Tomer Chachamu Date: Mon, 3 Oct 2022 19:44:25 +0100 Subject: [PATCH 275/599] Filter testing tree when test items are updated by extensions (#162169) Fixes #162168 --- src/vs/workbench/contrib/testing/browser/testingExplorerView.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 60a5566ddb0..9f30099a1eb 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -783,6 +783,8 @@ export class TestingExplorerViewModel extends Disposable { this.reevaluateWelcomeState(); this.projection.value?.applyTo(this.tree); + this.tree.refilter(); + if (this.hasPendingReveal) { this.revealById(this.filterState.reveal.value); } From 6df42b11be7e09622b2c0afe35a48670e6074a51 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 3 Oct 2022 21:04:43 +0200 Subject: [PATCH 276/599] support `NoHide` mode for workbench toolbar --- src/vs/platform/actions/browser/toolbar.ts | 53 ++++++++++++---------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index 619af9e09b9..db91b1c67f7 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -18,8 +18,12 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export const enum HiddenItemStrategy { + /** This toolbar doesn't support hiding*/ + NoHide = -1, + /** Hidden items aren't shown anywhere */ Ignore = 0, - RenderInSecondaryGroup = 1 + /** Hidden items move into the secondary group */ + RenderInSecondaryGroup = 1, } export type IWorkbenchToolBarOptions = IToolBarOptions & { @@ -104,32 +108,33 @@ export class WorkbenchToolBar extends ToolBar { const toggleActions: IAction[] = []; let someAreHidden = false; + // unless disabled, move all hidden items to secondary group or ignore them + if (this._options?.hiddenItemStrategy !== HiddenItemStrategy.NoHide) { + let shouldPrependSeparator = secondary.length > 0; + for (let i = 0; i < primary.length; i++) { + const action = primary[i]; + if (!(action instanceof MenuItemAction) && !(action instanceof SubmenuItemAction)) { + // console.warn(`Action ${action.id}/${action.label} is not a MenuItemAction`); + continue; + } + if (!action.hideActions) { + continue; + } - // move all hidden items to secondary group or ignore them - let shouldPrependSeparator = secondary.length > 0; - for (let i = 0; i < primary.length; i++) { - const action = primary[i]; - if (!(action instanceof MenuItemAction) && !(action instanceof SubmenuItemAction)) { - // console.warn(`Action ${action.id}/${action.label} is not a MenuItemAction`); - continue; - } - if (!action.hideActions) { - continue; - } + // collect all toggle actions + toggleActions.push(action.hideActions.toggle); - // collect all toggle actions - toggleActions.push(action.hideActions.toggle); - - // hidden items move into overflow or ignore - if (action.hideActions.isHidden) { - someAreHidden = true; - primary[i] = undefined!; - if (this._options?.hiddenItemStrategy !== HiddenItemStrategy.Ignore) { - if (shouldPrependSeparator) { - shouldPrependSeparator = false; - secondary.unshift(new Separator()); + // hidden items move into overflow or ignore + if (action.hideActions.isHidden) { + someAreHidden = true; + primary[i] = undefined!; + if (this._options?.hiddenItemStrategy !== HiddenItemStrategy.Ignore) { + if (shouldPrependSeparator) { + shouldPrependSeparator = false; + secondary.unshift(new Separator()); + } + secondary.unshift(action); } - secondary.unshift(action); } } } From 214f0106051231d202a3371530de1b1507039799 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 3 Oct 2022 21:05:03 +0200 Subject: [PATCH 277/599] remove dead code --- src/vs/platform/actions/common/menuService.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index 355fa5f43cf..d1c95179c67 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -10,7 +10,7 @@ import { IMenu, IMenuActionOptions, IMenuChangeEvent, IMenuCreateOptions, IMenuI import { ICommandAction, ILocalizedString } from 'vs/platform/action/common/action'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IAction, Separator, toAction } from 'vs/base/common/actions'; +import { Separator, toAction } from 'vs/base/common/actions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { removeFastWithoutKeepingOrder } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; @@ -217,13 +217,10 @@ class MenuInfo { createActionGroups(options: IMenuActionOptions | undefined): [string, Array][] { const result: [string, Array][] = []; - const allToggleActions: IAction[][] = []; for (const group of this._menuGroups) { const [id, items] = group; - const toggleActions: IAction[] = []; - const activeActions: Array = []; for (const item of items) { if (this._contextKeyService.contextMatchesRules(item.when)) { @@ -247,9 +244,6 @@ class MenuInfo { if (activeActions.length > 0) { result.push([id, activeActions]); } - if (toggleActions.length > 0) { - allToggleActions.push(toggleActions); - } } return result; } From bbd0c2063543f853a66b366836dafc6e7bf030b9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:35:50 -0700 Subject: [PATCH 278/599] Add did you mean with 2 dashes git quick fix Part of #161538 --- .../terminal/browser/terminalInstance.ts | 4 +-- .../browser/terminalQuickFixBuiltinActions.ts | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 543b6bc1514..3730d21cdeb 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -62,7 +62,7 @@ import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/termin import { TerminalLinkQuickpick } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick'; import { IRequestAddInstanceToGroupEvent, ITerminalQuickFixOptions, ITerminalExternalLinkProvider, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; -import { gitSimilarCommand, gitCreatePr, gitPushSetUpstream, freePort } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; +import { gitSimilarCommand, gitCreatePr, gitPushSetUpstream, freePort, gitTwoDashes } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; @@ -730,7 +730,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm = xterm; this._quickFixAddon = this._scopedInstantiationService.createInstance(TerminalQuickFixAddon, this.capabilities); this.xterm?.raw.loadAddon(this._quickFixAddon); - this.registerQuickFixProvider(gitSimilarCommand(), gitCreatePr(this._openerService), gitPushSetUpstream(), freePort(this)); + this.registerQuickFixProvider(gitSimilarCommand(), gitTwoDashes(), gitCreatePr(this._openerService), gitPushSetUpstream(), freePort(this)); this._register(this._quickFixAddon.onDidRequestRerunCommand((e) => this.sendText(e.command, e.addNewLine || false))); const lineDataEventAddon = new LineDataEventAddon(); this.xterm.raw.loadAddon(lineDataEventAddon); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index f3d6241a16e..68496b821df 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -47,6 +47,34 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { } }; } +export function gitTwoDashes(): ITerminalQuickFixOptions { + return { + commandLineMatcher: GitCommandLineRegex, + outputMatcher: { + lineMatcher: /error: did you mean `--(.+)` \(with two dashes\)\?/, + anchor: 'bottom', + offset: 0, + length: 2 + }, + exitStatus: false, + getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { + const actions: ITerminalQuickFixAction[] = []; + const problemArg = matchResult?.outputMatch?.[1]; + if (!problemArg) { + return; + } + const commandToRunInTerminal = command.command.replace(` -${problemArg}`, ` --${problemArg}`); + const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); + actions.push({ + class: undefined, tooltip: label, id: 'terminal.gitTwoDashes', label, enabled: true, + commandToRunInTerminal, + addNewLine: true, + run: () => { } + }); + return actions; + } + }; +} export function freePort(terminalInstance?: Partial): ITerminalQuickFixOptions { return { commandLineMatcher: AnyCommandLineRegex, From 15d76a961992b9e6516204018519a3fe93518760 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:38:24 -0700 Subject: [PATCH 279/599] Add tests for git two dashes --- .../browser/terminalQuickFixBuiltinActions.ts | 3 +- .../test/browser/quickFixAddon.test.ts | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 68496b821df..a8fa5ba8788 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -11,6 +11,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal' export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; +export const GitTwoDashesRegex = /error: did you mean `--(.+)` \(with two dashes\)\?/; export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /most similar command is\s*\n\s*([^\s]{3,})/m; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; @@ -51,7 +52,7 @@ export function gitTwoDashes(): ITerminalQuickFixOptions { return { commandLineMatcher: GitCommandLineRegex, outputMatcher: { - lineMatcher: /error: did you mean `--(.+)` \(with two dashes\)\?/, + lineMatcher: GitTwoDashesRegex, anchor: 'bottom', offset: 0, length: 2 diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index f786a336129..c8d9062fb8e 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -15,7 +15,7 @@ import { ITerminalCommand, ITerminalOutputMatcher, TerminalCapability } from 'vs import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; +import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex, gitTwoDashes, GitTwoDashesRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { Terminal } from 'xterm'; @@ -84,6 +84,42 @@ suite('QuickFixAddon', () => { }); }); }); + suite('gitTwoDashes', async () => { + const expectedMap = new Map(); + const command = `git add . -all`; + const output = 'error: did you mean `--all` (with two dashes)?'; + const exitCode = 1; + const actions = [ + { + id: 'terminal.gitTwoDashes', + label: 'Run: git add . --all', + run: true, + tooltip: 'Run: git add . --all', + enabled: true + } + ]; + setup(() => { + const command = gitTwoDashes(); + expectedMap.set(command.commandLineMatcher.toString(), [command]); + quickFixAddon.registerCommandFinishedListener(command); + }); + suite('returns undefined when', () => { + test('output does not match', () => { + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitTwoDashesRegex, exitCode), expectedMap), undefined); + }); + test('command does not match', () => { + strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitTwoDashesRegex, exitCode), expectedMap), undefined); + }); + }); + suite('returns undefined when', () => { + test('expected unix exit code', () => { + assertMatchOptions(getQuickFixes(createCommand(command, output, GitTwoDashesRegex, exitCode), expectedMap), actions); + }); + test('matching exit status', () => { + assertMatchOptions(getQuickFixes(createCommand(command, output, GitTwoDashesRegex, 2), expectedMap), actions); + }); + }); + }); if (!isWindows) { suite('freePort', () => { const expected = new Map(); From 96227675ad7189d33e17c7d7d32298cf2c2d8b98 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 3 Oct 2022 15:05:32 -0700 Subject: [PATCH 280/599] fix: give focus to testing view correctly (#162606) Fixes #161669 using the same approach that the search view uses. --- .../testing/browser/testingExplorerFilter.ts | 7 +++++ .../testing/browser/testingExplorerView.ts | 30 ++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index e2054a472cc..e980a313f04 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -24,6 +24,7 @@ import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue'; import { denamespaceTestTag } from 'vs/workbench/contrib/testing/common/testTypes'; import { ITestExplorerFilterState, TestFilterTerm } from 'vs/workbench/contrib/testing/common/testExplorerFilterState'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; +import { Emitter } from 'vs/base/common/event'; const testFilterDescriptions: { [K in TestFilterTerm]: string } = { [TestFilterTerm.Failed]: localize('testing.filters.showOnlyFailed', "Show Only Failed Tests"), @@ -35,6 +36,8 @@ const testFilterDescriptions: { [K in TestFilterTerm]: string } = { export class TestingExplorerFilter extends BaseActionViewItem { private input!: SuggestEnabledInputWithHistory; private wrapper!: HTMLDivElement; + private readonly focusEmitter = this._register(new Emitter()); + public readonly onDidFocus = this.focusEmitter.event; private readonly history: StoredValue<{ values: string[]; lastValue: string } | string[]> = this.instantiationService.createInstance(StoredValue, { key: 'testing.filterHistory2', scope: StorageScope.WORKSPACE, @@ -111,6 +114,10 @@ export class TestingExplorerFilter extends BaseActionViewItem { input.focus(); })); + this._register(input.onDidFocus(() => { + this.focusEmitter.fire(); + })); + this._register(input.onInputDidChange(() => updateDelayer.trigger(() => { input.addToHistory(); this.state.setText(input.getValue()); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 9f30099a1eb..fac697c8f62 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -69,14 +69,21 @@ import { IMainThreadTestCollection, ITestService, testCollectionIsEmpty } from ' import { InternalTestItem, ITestRunProfile, TestItemExpandState, TestResultState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +const enum LastFocusState { + Input, + Tree, +} + export class TestingExplorerView extends ViewPane { public viewModel!: TestingExplorerViewModel; private filterActionBar = this._register(new MutableDisposable()); private container!: HTMLElement; private treeHeader!: HTMLElement; private discoveryProgress = this._register(new MutableDisposable()); - private filter?: TestingExplorerFilter; + private readonly filter = this._register(new MutableDisposable()); + private readonly filterFocusListener = this._register(new MutableDisposable()); private readonly dimensions = { width: 0, height: 0 }; + private lastFocusState = LastFocusState.Input; constructor( options: IViewletViewOptions, @@ -110,13 +117,19 @@ export class TestingExplorerView extends ViewPane { this._register(testProfileService.onDidChange(() => this.updateActions())); } - /** - * @override - */ public override shouldShowWelcome() { return this.viewModel?.welcomeExperience === WelcomeExperience.ForWorkspace ?? true; } + public override focus() { + super.focus(); + if (this.lastFocusState === LastFocusState.Tree) { + this.viewModel.tree.domFocus(); + } else { + this.filter.value?.focus(); + } + } + public getSelectedOrVisibleItems(profile?: ITestRunProfile) { const projection = this.viewModel.projection.value; if (!projection) { @@ -226,6 +239,7 @@ export class TestingExplorerView extends ViewPane { const listContainer = dom.append(this.container, dom.$('.test-explorer-tree')); this.viewModel = this.instantiationService.createInstance(TestingExplorerViewModel, listContainer, this.onDidChangeBodyVisibility); + this._register(this.viewModel.tree.onDidFocus(() => this.lastFocusState = LastFocusState.Tree)); this._register(this.viewModel.onChangeWelcomeVisibility(() => this._onDidChangeViewWelcomeState.fire())); this._register(this.viewModel); this._onDidChangeViewWelcomeState.fire(); @@ -235,7 +249,9 @@ export class TestingExplorerView extends ViewPane { public override getActionViewItem(action: IAction): IActionViewItem | undefined { switch (action.id) { case TestCommandId.FilterAction: - return this.filter = this.instantiationService.createInstance(TestingExplorerFilter, action); + this.filter.value = this.instantiationService.createInstance(TestingExplorerFilter, action); + this.filterFocusListener.value = this.filter.value.onDidFocus(() => this.lastFocusState = LastFocusState.Input); + return this.filter.value; case TestCommandId.RunSelectedAction: return this.getRunGroupDropdown(TestRunProfileBitset.Run, action); case TestCommandId.DebugSelectedAction: @@ -321,7 +337,7 @@ export class TestingExplorerView extends ViewPane { * @override */ public override saveState() { - this.filter?.saveState(); + this.filter.value?.saveState(); super.saveState(); } @@ -377,7 +393,7 @@ export class TestingExplorerView extends ViewPane { this.dimensions.width = width; this.container.style.height = `${height}px`; this.viewModel.layout(height - this.treeHeader.clientHeight, width); - this.filter?.layout(width); + this.filter.value?.layout(width); } } From 8f1ab28258e4dfd40d61bbcbb55ed422ab15aca8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:22:47 -0700 Subject: [PATCH 281/599] Refactor actions to allow returning command or uri only Fixes #161599 --- .../contrib/terminal/browser/terminal.ts | 19 ++- .../terminal/browser/terminalInstance.ts | 2 +- .../browser/terminalQuickFixBuiltinActions.ts | 74 +++++------ .../terminal/browser/xterm/quickFixAddon.ts | 86 ++++++++++--- .../test/browser/quickFixAddon.test.ts | 118 +++++++++--------- 5 files changed, 169 insertions(+), 130 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 94377a2a85b..332819b1590 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -922,15 +922,22 @@ export interface ITerminalInstance { export interface ITerminalQuickFixOptions { commandLineMatcher: string | RegExp; outputMatcher?: ITerminalOutputMatcher; - getQuickFixes: QuickFixCallback; + getQuickFixes: TerminalQuickFixCallback; exitStatus?: boolean; } -export type QuickFixMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null }; -export type QuickFixCallback = (matchResult: QuickFixMatchResult, command: ITerminalCommand) => ITerminalQuickFixAction[] | undefined; +export type TerminalQuickFixMatchResult = { commandLineMatch: RegExpMatchArray; outputMatch?: RegExpMatchArray | null }; +export type TerminalQuickFixAction = IAction | ITerminalQuickFixCommandAction | ITerminalQuickFixOpenerAction; +export type TerminalQuickFixCallback = (matchResult: TerminalQuickFixMatchResult, command: ITerminalCommand) => TerminalQuickFixAction[] | TerminalQuickFixAction | undefined; -export interface ITerminalQuickFixAction extends IAction { - commandToRunInTerminal?: string; - addNewLine?: boolean; +export interface ITerminalQuickFixCommandAction { + type: 'command'; + command: string; + // TODO: Should this depend on whether alt is held? + addNewLine: boolean; +} +export interface ITerminalQuickFixOpenerAction { + type: 'opener'; + uri: URI; } export interface IXtermTerminal { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 543b6bc1514..66b533cd510 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -730,7 +730,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm = xterm; this._quickFixAddon = this._scopedInstantiationService.createInstance(TerminalQuickFixAddon, this.capabilities); this.xterm?.raw.loadAddon(this._quickFixAddon); - this.registerQuickFixProvider(gitSimilarCommand(), gitCreatePr(this._openerService), gitPushSetUpstream(), freePort(this)); + this.registerQuickFixProvider(gitSimilarCommand(), gitCreatePr(), gitPushSetUpstream(), freePort(this)); this._register(this._quickFixAddon.onDidRequestRerunCommand((e) => this.sendText(e.command, e.addNewLine || false))); const lineDataEventAddon = new LineDataEventAddon(); this.xterm.raw.loadAddon(lineDataEventAddon); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index f3d6241a16e..fffe05814de 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -3,11 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction } from 'vs/base/common/actions'; import { localize } from 'vs/nls'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { QuickFixMatchResult, ITerminalQuickFixAction, ITerminalQuickFixOptions, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { TerminalQuickFixMatchResult, ITerminalQuickFixOptions, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; +import { URI } from 'vs/base/common/uri'; export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; @@ -29,21 +28,16 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { length: 3 }, exitStatus: false, - getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { - const actions: ITerminalQuickFixAction[] = []; + getQuickFixes: (matchResult: TerminalQuickFixMatchResult, command: ITerminalCommand) => { const fixedCommand = matchResult?.outputMatch?.[1]; if (!fixedCommand) { return; } - const commandToRunInTerminal = `git ${fixedCommand}`; - const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); - actions.push({ - class: undefined, tooltip: label, id: 'terminal.gitSimilarCommand', label, enabled: true, - commandToRunInTerminal, - addNewLine: true, - run: () => { } - }); - return actions; + return { + type: 'command', + command: `git ${fixedCommand}`, + addNewLine: true + }; } }; } @@ -57,22 +51,20 @@ export function freePort(terminalInstance?: Partial): ITermin length: 30 }, exitStatus: false, - getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { + getQuickFixes: (matchResult: TerminalQuickFixMatchResult, command: ITerminalCommand) => { const port = matchResult?.outputMatch?.[1]; if (!port) { return; } - const actions: ITerminalQuickFixAction[] = []; const label = localize("terminal.freePort", "Free port {0}", port); - actions.push({ - class: undefined, tooltip: label, id: 'terminal.freePort', label, enabled: true, - run: async () => { - await terminalInstance?.freePortKillProcess?.(port); - }, - commandToRunInTerminal: command.command, - addNewLine: false - }); - return actions; + return { + class: undefined, + tooltip: label, + id: 'terminal.freePort', + label, + enabled: true, + run: async () => terminalInstance?.freePortKillProcess?.(port) + }; } }; } @@ -86,26 +78,21 @@ export function gitPushSetUpstream(): ITerminalQuickFixOptions { length: 5 }, exitStatus: false, - getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { + getQuickFixes: (matchResult: TerminalQuickFixMatchResult, command: ITerminalCommand) => { const branch = matchResult?.outputMatch?.[1]; if (!branch) { return; } - const actions: ITerminalQuickFixAction[] = []; - const commandToRunInTerminal = `git push --set-upstream origin ${branch}`; - const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); - actions.push({ - class: undefined, tooltip: label, id: 'terminal.gitPush', label, enabled: true, - commandToRunInTerminal, - addNewLine: true, - run: () => { } - }); - return actions; + return { + type: 'command', + command: `git push --set-upstream origin ${branch}`, + addNewLine: true + }; } }; } -export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOptions { +export function gitCreatePr(): ITerminalQuickFixOptions { return { commandLineMatcher: GitPushCommandLineRegex, outputMatcher: { @@ -115,7 +102,7 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOpt length: 5 }, exitStatus: true, - getQuickFixes: (matchResult: QuickFixMatchResult, command?: ITerminalCommand) => { + getQuickFixes: (matchResult: TerminalQuickFixMatchResult, command?: ITerminalCommand) => { if (!command) { return; } @@ -123,13 +110,10 @@ export function gitCreatePr(openerService: IOpenerService): ITerminalQuickFixOpt if (!link) { return; } - const actions: IAction[] = []; - const label = localize("terminal.openLink", "Open link: {0}", link); - actions.push({ - class: undefined, tooltip: label, id: 'terminal.gitCreatePr', label, enabled: true, - run: () => openerService.open(link) - }); - return actions; + return { + type: 'opener', + uri: URI.parse(link) + }; } }; } diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index e9f2e91fe93..92ecae13f74 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -10,7 +10,7 @@ import { ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from ' import type { ITerminalAddon } from 'xterm-headless'; import * as dom from 'vs/base/browser/dom'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ITerminalQuickFixAction, ITerminalQuickFixOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalQuickFixOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Terminal, IDecoration } from 'xterm'; @@ -20,6 +20,9 @@ import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService'; +import { asArray } from 'vs/base/common/arrays'; +import { localize } from 'vs/nls'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; export interface ITerminalQuickFix { showMenu(): void; @@ -46,14 +49,17 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, private _commandListeners: Map = new Map(); - private _quickFixes: ITerminalQuickFixAction[] | undefined; + private _quickFixes: IAction[] | undefined; private _decoration: IDecoration | undefined; - constructor(private readonly _capabilities: ITerminalCapabilityStore, + constructor( + private readonly _capabilities: ITerminalCapabilityStore, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IAudioCueService private readonly _audioCueService: IAudioCueService) { + @IAudioCueService private readonly _audioCueService: IAudioCueService, + @IOpenerService private readonly _openerService: IOpenerService + ) { super(); const commandDetectionCapability = this._capabilities.get(TerminalCapability.CommandDetection); if (commandDetectionCapability) { @@ -94,7 +100,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, this._register(commandDetection.onCommandFinished(async command => { this._decoration?.dispose(); this._decoration = undefined; - this._quickFixes = getQuickFixes(command, this._commandListeners, this._onDidRequestRerunCommand); + this._quickFixes = getQuickFixes(command, this._commandListeners, this._openerService, this._onDidRequestRerunCommand); })); // The buffer is not ready by the time command finish // is called. Add the decoration on command start using the actions, if any, @@ -135,7 +141,12 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, } } -export function getQuickFixes(command: ITerminalCommand, actionOptions: Map, onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }>): IAction[] | undefined { +export function getQuickFixes( + command: ITerminalCommand, + actionOptions: Map, + openerService: IOpenerService, + onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }> +): IAction[] | undefined { const actions: IAction[] = []; const newCommand = command.command; for (const options of actionOptions.values()) { @@ -154,20 +165,55 @@ export function getQuickFixes(command: ITerminalCommand, actionOptions: Map { - await quickFix.run(); - if (quickFix.commandToRunInTerminal) { - onDidRequestRerunCommand?.fire({ command: quickFix.commandToRunInTerminal, addNewLine: quickFix.addNewLine }); + for (const quickFix of asArray(quickFixes)) { + let action: IAction | undefined; + if ('type' in quickFix) { + switch (quickFix.type) { + case 'command': { + const label = localize('quickFix.command', 'Run: {0}', quickFix.command); + action = { + id: `quickFix.command`, + label, + class: undefined, + enabled: true, + run: () => { + onDidRequestRerunCommand?.fire({ + command: quickFix.command, + addNewLine: quickFix.addNewLine + }); + }, + tooltip: label, + command: quickFix.command + } as IAction; + break; } - }, - tooltip: quickFix.tooltip - }); + case 'opener': { + const label = localize('quickFix.opener', 'Open: {0}', quickFix.uri.toString()); + action = { + id: `quickFix.opener`, + label, + class: undefined, + enabled: true, + run: () => openerService.open(quickFix.uri), + tooltip: label, + uri: quickFix.uri + } as IAction; + break; + } + } + } else { + action = { + id: quickFix.id, + label: quickFix.label, + class: quickFix.class, + enabled: quickFix.enabled, + run: () => quickFix.run(), + tooltip: quickFix.tooltip + }; + } + if (action) { + actions.push(action); + } } } } @@ -175,6 +221,8 @@ export function getQuickFixes(command: ITerminalCommand, actionOptions: Map { diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index f786a336129..d790d190278 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual } from 'assert'; +import { IAction } from 'vs/base/common/actions'; import { isWindows } from 'vs/base/common/platform'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; @@ -14,9 +15,10 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITerminalCommand, ITerminalOutputMatcher, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; -import { ITerminalQuickFixAction, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; +import { URI } from 'vs/base/common/uri'; import { Terminal } from 'xterm'; suite('QuickFixAddon', () => { @@ -53,15 +55,13 @@ suite('QuickFixAddon', () => { The most similar command is status`; const exitCode = 1; - const actions = [ - { - id: 'terminal.gitSimilarCommand', - label: 'Run: git status', - run: true, - tooltip: 'Run: git status', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git status', + tooltip: 'Run: git status', + command: 'git status' + }]; setup(() => { const command = gitSimilarCommand(); expectedMap.set(command.commandLineMatcher.toString(), [command]); @@ -69,18 +69,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns undefined when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService), actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap, openerService), actions); }); }); }); @@ -116,11 +116,11 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected), undefined); + strictEqual(getQuickFixes(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected, openerService), undefined); }); }); test('returns actions', () => { - assertMatchOptions(getQuickFixes(createCommand(portCommand, output, FreePortOutputRegex), expected), actionOptions); + assertMatchOptions(getQuickFixes(createCommand(portCommand, output, FreePortOutputRegex), expected, openerService), actionOptions); }); }); } @@ -133,15 +133,13 @@ suite('QuickFixAddon', () => { git push --set-upstream origin test22`; const exitCode = 128; - const actions = [ - { - id: 'terminal.gitPush', - label: 'Run: git push --set-upstream origin test22', - run: true, - tooltip: 'Run: git push --set-upstream origin test22', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git push --set-upstream origin test22', + tooltip: 'Run: git push --set-upstream origin test22', + command: 'git push --set-upstream origin test22' + }]; setup(() => { const command = gitPushSetUpstream(); expectedMap.set(command.commandLineMatcher.toString(), [command]); @@ -149,18 +147,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService), actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService), actions); }); }); }); @@ -176,34 +174,32 @@ suite('QuickFixAddon', () => { * [new branch] test22 -> test22 Branch 'test22' set up to track remote branch 'test22' from 'origin'. `; const exitCode = 0; - const actions = [ - { - id: 'terminal.gitCreatePr', - label: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22', - run: true, - tooltip: 'Open link: https://github.com/meganrogge/xterm.js/pull/new/test22', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.opener`, + enabled: true, + label: 'Open: https://github.com/meganrogge/xterm.js/pull/new/test22', + tooltip: 'Open: https://github.com/meganrogge/xterm.js/pull/new/test22', + uri: URI.parse('https://github.com/meganrogge/xterm.js/pull/new/test22') + }]; setup(() => { - const command = gitCreatePr(openerService); + const command = gitCreatePr(); expectedMap.set(command.commandLineMatcher.toString(), [command]); quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('failure exit status', () => { - strictEqual(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), actions); }); }); }); @@ -216,36 +212,34 @@ suite('QuickFixAddon', () => { git push --set-upstream origin test22`; const exitCode = 128; - const actions = [ - { - id: 'terminal.gitPush', - label: 'Run: git push --set-upstream origin test22', - run: true, - tooltip: 'Run: git push --set-upstream origin test22', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git push --set-upstream origin test22', + tooltip: 'Run: git push --set-upstream origin test22', + command: 'git push --set-upstream origin test22' + }]; setup(() => { const pushCommand = gitPushSetUpstream(); - const prCommand = gitCreatePr(openerService); + const prCommand = gitCreatePr(); quickFixAddon.registerCommandFinishedListener(pushCommand); quickFixAddon.registerCommandFinishedListener(prCommand); expectedMap.set(pushCommand.commandLineMatcher.toString(), [pushCommand, prCommand]); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap), undefined); + strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService), actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap), actions); + assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService), actions); }); }); }); @@ -267,7 +261,8 @@ function createCommand(command: string, output: string, outputMatcher?: RegExp | }; } -function assertMatchOptions(actual: ITerminalQuickFixAction[] | undefined, expected: { id: string; label: string; run: boolean; tooltip: string; enabled: boolean }[]): void { +type TestAction = Pick & { command?: string; uri?: URI }; +function assertMatchOptions(actual: TestAction[] | undefined, expected: TestAction[]): void { strictEqual(actual?.length, expected.length); let index = 0; for (const i of actual) { @@ -275,8 +270,13 @@ function assertMatchOptions(actual: ITerminalQuickFixAction[] | undefined, expec strictEqual(i.id, j.id, `ID`); strictEqual(i.enabled, j.enabled, `enabled`); strictEqual(i.label, j.label, `label`); - strictEqual(!!i.run, j.run, `run`); strictEqual(i.tooltip, j.tooltip, `tooltip`); + if (j.command) { + strictEqual(i.command, j.command); + } + if (j.uri) { + strictEqual(i.uri!.toString(), j.uri.toString()); + } index++; } } From fd3c0b74cab6802a3dbd4ef77c5042ddd9b2124c Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 3 Oct 2022 15:34:00 -0700 Subject: [PATCH 282/599] Update profile indicator font size and weight (#162616) * Update profile indicator font size and weight * Fix formatting --- .../browser/parts/activitybar/media/activityaction.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 795c7e16267..a7b7e543420 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -183,7 +183,8 @@ padding: 0px; justify-content: center; align-items: center; - font-size: 14px; + font-size: 11px; + font-weight: 600; border-radius: 10px; } From 4771b2d481339701dc8a650ef47258d833e49d79 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 3 Oct 2022 18:24:14 -0700 Subject: [PATCH 283/599] testing: show last message per line, simplify logic (#162617) Fixes #161270 --- .../testing/browser/testingDecorations.ts | 53 +++++++++++-------- .../testing/common/testingDecorations.ts | 39 +------------- 2 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 7287bcccafa..97b16527952 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -10,6 +10,8 @@ import { equals } from 'vs/base/common/arrays'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent'; +import { stripIcons } from 'vs/base/common/iconLabels'; +import { Iterable } from 'vs/base/common/iterator'; import { Disposable, DisposableStore, IReference, MutableDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { Constants } from 'vs/base/common/uint'; @@ -39,7 +41,6 @@ import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from 'vs/work import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme'; import { DefaultGutterClickAction, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; import { labelForTestInState, Testing } from 'vs/workbench/contrib/testing/common/constants'; -import { IncrementalTestCollectionItem, InternalTestItem, IRichLocation, ITestMessage, ITestRunProfile, TestDiffOpType, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; import { ITestDecoration as IPublicTestDecoration, ITestingDecorationsService, TestDecorations } from 'vs/workbench/contrib/testing/common/testingDecorations'; import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener'; import { isFailedState, maxPriority } from 'vs/workbench/contrib/testing/common/testingStates'; @@ -48,7 +49,7 @@ import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testPro import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult'; import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { getContextForTestItem, ITestService, testsInFile } from 'vs/workbench/contrib/testing/common/testService'; -import { stripIcons } from 'vs/base/common/iconLabels'; +import { IncrementalTestCollectionItem, InternalTestItem, IRichLocation, ITestMessage, ITestRunProfile, TestDiffOpType, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; const MAX_INLINE_MESSAGE_LENGTH = 128; @@ -79,7 +80,8 @@ export class TestingDecorationService extends Disposable implements ITestingDeco rangeUpdateVersionId?: number; /** Counter for the results rendered in the document */ generation: number; - value: TestDecorations; + value: readonly ITestDecoration[]; + map: ReadonlyMap; }>(); /** @@ -150,15 +152,15 @@ export class TestingDecorationService extends Disposable implements ITestingDeco } /** @inheritdoc */ - public syncDecorations(resource: URI): TestDecorations { + public syncDecorations(resource: URI): ReadonlyMap { const model = this.modelService.getModel(resource); if (!model) { - return new TestDecorations(); + return new Map(); } const cached = this.decorationCache.get(resource); if (cached && cached.generation === this.generation && (cached.rangeUpdateVersionId === undefined || cached.rangeUpdateVersionId !== model.getVersionId())) { - return cached.value; + return cached.map; } return this.applyDecorations(model); @@ -171,7 +173,7 @@ export class TestingDecorationService extends Disposable implements ITestingDeco return undefined; } - const decoration = this.syncDecorations(resource).value.find(v => v instanceof RunTestDecoration && v.isForTest(testId)); + const decoration = Iterable.find(this.syncDecorations(resource).values(), v => v instanceof RunTestDecoration && v.isForTest(testId)); if (!decoration) { return undefined; } @@ -192,10 +194,10 @@ export class TestingDecorationService extends Disposable implements ITestingDeco const uriStr = model.uri.toString(); const cached = this.decorationCache.get(model.uri); const testRangesUpdated = cached?.rangeUpdateVersionId === model.getVersionId(); - const lastDecorations = cached?.value ?? new TestDecorations(); - const newDecorations = new TestDecorations(); + const lastDecorations = cached?.value ?? []; - model.changeDecorations(accessor => { + const map = model.changeDecorations(accessor => { + const newDecorations: ITestDecoration[] = []; const runDecorations = new TestDecorations<{ line: number; id: ''; test: IncrementalTestCollectionItem; resultItem: TestResultItem | undefined }>(); for (const test of this.testService.collection.all) { if (!test.item.range || test.item.uri?.toString() !== uriStr) { @@ -209,7 +211,7 @@ export class TestingDecorationService extends Disposable implements ITestingDeco for (const [line, tests] of runDecorations.lines()) { const multi = tests.length > 1; - let existing = lastDecorations.value.find(d => d instanceof RunTestDecoration && d.exactlyContainsTests(tests)) as RunTestDecoration | undefined; + let existing = lastDecorations.find(d => d instanceof RunTestDecoration && d.exactlyContainsTests(tests)) as RunTestDecoration | undefined; // see comment in the constructor for what's going on here if (existing && testRangesUpdated && model.getDecorationRange(existing.id)?.startLineNumber !== line) { @@ -233,14 +235,14 @@ export class TestingDecorationService extends Disposable implements ITestingDeco for (const task of lastResult.tasks) { for (const m of task.otherMessages) { if (!this.invalidatedMessages.has(m) && m.location?.uri.toString() === uriStr) { - const decoration = lastDecorations.findOnLine(m.location.range.startLineNumber, l => l instanceof TestMessageDecoration && l.testMessage === m) + const decoration = lastDecorations.find(l => l instanceof TestMessageDecoration && l.testMessage === m) || this.instantiationService.createInstance(TestMessageDecoration, m, undefined, model); newDecorations.push(decoration); } } } - const messageLines = new Set(); + const messageLines = new Map(); for (const test of lastResult.tests) { for (let taskId = 0; taskId < test.tasks.length; taskId++) { const state = test.tasks[taskId]; @@ -253,14 +255,17 @@ export class TestingDecorationService extends Disposable implements ITestingDeco // Only add one message per line number. Overlapping messages // don't appear well, and the peek will show all of them (#134129) const line = m.location.range.startLineNumber; + let index: number; if (messageLines.has(line)) { - continue; + index = messageLines.get(line)!; + } else { + index = newDecorations.length; + messageLines.set(line, index); } - messageLines.add(line); - const previous = lastDecorations.findOnLine(line, l => l instanceof TestMessageDecoration && l.testMessage === m); + const previous = lastDecorations.find(l => l instanceof TestMessageDecoration && l.testMessage === m); if (previous) { - newDecorations.push(previous); + newDecorations[index] = previous; continue; } @@ -279,7 +284,7 @@ export class TestingDecorationService extends Disposable implements ITestingDeco } const saveFromRemoval = new Set(); - for (const decoration of newDecorations.value) { + for (const decoration of newDecorations) { if (decoration.id === '') { decoration.id = accessor.addDecoration(decoration.editorDecoration.range, decoration.editorDecoration.options); } else { @@ -287,20 +292,24 @@ export class TestingDecorationService extends Disposable implements ITestingDeco } } - for (const decoration of lastDecorations.value) { + for (const decoration of lastDecorations) { if (!saveFromRemoval.has(decoration.id)) { accessor.removeDecoration(decoration.id); } } + const map = new Map(newDecorations.map(d => [d.id, d])); this.decorationCache.set(model.uri, { generation: this.generation, rangeUpdateVersionId: cached?.rangeUpdateVersionId, value: newDecorations, + map, }); + + return map; }); - return newDecorations; + return map || new Map(); } } @@ -338,8 +347,8 @@ export class TestingDecorations extends Disposable implements IEditorContributio if (e.target.position && this.currentUri) { const modelDecorations = editor.getModel()?.getDecorationsInRange(Range.fromPositions(e.target.position)) ?? []; for (const { id } of modelDecorations) { - const cache = decorations.syncDecorations(this.currentUri) as TestDecorations; - if (cache.get(id)?.click(e)) { + const cache = decorations.syncDecorations(this.currentUri); + if ((cache.get(id) as ITestDecoration | undefined)?.click(e)) { e.event.stopPropagation(); return; } diff --git a/src/vs/workbench/contrib/testing/common/testingDecorations.ts b/src/vs/workbench/contrib/testing/common/testingDecorations.ts index 3a148eb3e97..e82580cfd18 100644 --- a/src/vs/workbench/contrib/testing/common/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/common/testingDecorations.ts @@ -30,7 +30,7 @@ export interface ITestingDecorationsService { * Ensures decorations in the given document URI are up to date, * and returns them. */ - syncDecorations(resource: URI): TestDecorations; + syncDecorations(resource: URI): ReadonlyMap; /** * Gets the range where a test ID is displayed, in the given URI. @@ -59,49 +59,12 @@ export interface ITestDecoration { export class TestDecorations { public value: T[] = []; - - private _idMap?: Map; - - /** - * Looks up a decoration by ID. - */ - public get(decorationId: string) { - if (this._idMap) { - return this._idMap.get(decorationId); - } else if (this.value.length > 16) { - this._idMap = new Map(); - for (const value of this.value) { this._idMap.set(value.id, value); } - return this._idMap.get(decorationId); - } else { - return this.value.find(v => v.id === decorationId); - } - } - /** * Adds a new value to the decorations. */ public push(value: T) { const searchIndex = binarySearch(this.value, value, (a, b) => a.line - b.line); this.value.splice(searchIndex < 0 ? ~searchIndex : searchIndex, 0, value); - this._idMap = undefined; - } - - /** - * Finds the value that exists on the given line, if any. - */ - public findOnLine(line: number, predicate: (value: T) => boolean): T | undefined { - const lineStart = binarySearch<{ line: number }>(this.value, { line }, (a, b) => a.line - b.line); - if (lineStart < 0) { - return undefined; - } - - for (let i = lineStart; i < this.value.length && this.value[i].line === line; i++) { - if (predicate(this.value[i])) { - return this.value[i]; - } - } - - return undefined; } /** From beefa471113d4626ea47d7db466cfed981329926 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 3 Oct 2022 20:53:00 -0700 Subject: [PATCH 284/599] Allow better canceling of extension page rendering (#162622) Threads a cancellation token through some of the extension page rendering --- .../extensions/browser/extensionEditor.ts | 16 ++++++++++++---- .../markdown/browser/markdownDocumentRenderer.ts | 7 +++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 746a1af95ba..65d0cc03d7e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -675,7 +675,7 @@ export class ExtensionEditor extends EditorPane { private async openMarkdown(cacheResult: CacheResult, noContentCopy: string, container: HTMLElement, webviewIndex: WebviewIndex, token: CancellationToken): Promise { try { - const body = await this.renderMarkdown(cacheResult, container); + const body = await this.renderMarkdown(cacheResult, container, token); if (token.isCancellationRequested) { return Promise.resolve(null); } @@ -742,13 +742,21 @@ export class ExtensionEditor extends EditorPane { } } - private async renderMarkdown(cacheResult: CacheResult, container: HTMLElement) { + private async renderMarkdown(cacheResult: CacheResult, container: HTMLElement, token?: CancellationToken): Promise { const contents = await this.loadContents(() => cacheResult, container); - const content = await renderMarkdownDocument(contents, this.extensionService, this.languageService); + if (token?.isCancellationRequested) { + return ''; + } + + const content = await renderMarkdownDocument(contents, this.extensionService, this.languageService, true, false, token); + if (token?.isCancellationRequested) { + return ''; + } + return this.renderBody(content); } - private async renderBody(body: string): Promise { + private renderBody(body: string): string { const nonce = generateUuid(); const colorMap = TokenizationRegistry.getColorMap(); const css = colorMap ? generateTokensCSSForColorMap(colorMap) : ''; diff --git a/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts b/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts index f45f3a3c145..be11c3073ba 100644 --- a/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts +++ b/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts @@ -6,6 +6,7 @@ import { hookDomPurifyHrefAndSrcSanitizer, basicMarkupHtmlTags } from 'vs/base/browser/dom'; import * as dompurify from 'vs/base/browser/dompurify/dompurify'; import { allowedMarkdownAttr } from 'vs/base/browser/markdownRenderer'; +import { CancellationToken } from 'vs/base/common/cancellation'; import { marked } from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; import { ILanguageService } from 'vs/editor/common/languages/language'; @@ -189,6 +190,7 @@ export async function renderMarkdownDocument( languageService: ILanguageService, shouldSanitize: boolean = true, allowUnknownProtocols: boolean = false, + token?: CancellationToken, ): Promise { const highlight = (code: string, lang: string | undefined, callback: ((error: any, code: string) => void) | undefined): any => { @@ -202,6 +204,11 @@ export async function renderMarkdownDocument( } extensionService.whenInstalledExtensionsRegistered().then(async () => { + if (token?.isCancellationRequested) { + callback(null, ''); + return; + } + const languageId = languageService.getLanguageIdByLanguageName(lang); const html = await tokenizeToString(languageService, code, languageId); callback(null, `${html}`); From 90e165a528b5c81f884eb35eadb2f653921610ce Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 3 Oct 2022 21:21:05 -0700 Subject: [PATCH 285/599] testing: remove redundant parent in InternalTestItem (#162621) Initially, test IDs were just the strings given by the extension, but a while ago we changed to the "extId", which is a concatenation of the ID the extension provided, with all the parent IDs and the test controller ID, so that we can uniquely identify any given test. ``` someController\0parent1\0parent2\0my test case ``` Because of this, we can derive the parent extId from any test's extId, but we never got rid of this duplicate information. In this PR, we do. --- src/vs/workbench/api/common/extHostTesting.ts | 3 +- .../api/common/extHostTypeConverters.ts | 3 +- .../api/test/browser/extHostTesting.test.ts | 14 ++++---- .../hierarchalByLocation.ts | 4 ++- .../explorerProjections/hierarchalByName.ts | 4 ++- .../testing/browser/testingDecorations.ts | 7 ++-- .../common/mainThreadTestCollection.ts | 4 +-- .../contrib/testing/common/testId.ts | 22 +++++++++++-- .../testing/common/testItemCollection.ts | 3 -- .../contrib/testing/common/testResult.ts | 28 ++++++---------- .../contrib/testing/common/testService.ts | 6 ++-- .../contrib/testing/common/testTypes.ts | 33 +++++++++++-------- .../hierarchalByLocation.test.ts | 7 ++-- .../hierarchalByName.test.ts | 10 +++--- .../contrib/testing/test/common/testStubs.ts | 26 +++++++++------ 15 files changed, 98 insertions(+), 76 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index c436a936cf6..bf44c8939d4 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -751,7 +751,8 @@ class MirroredChangeCollector extends IncrementalChangeCollector(); for (const item of serialized.items) { byInternalId.set(item.item.extId, item); - if (serialized.request.targets.some(t => t.controllerId === item.controllerId && t.testIds.includes(item.item.extId))) { + const controllerId = TestId.root(item.item.extId); + if (serialized.request.targets.some(t => t.controllerId === controllerId && t.testIds.includes(item.item.extId))) { roots.push(item); } } diff --git a/src/vs/workbench/api/test/browser/extHostTesting.test.ts b/src/vs/workbench/api/test/browser/extHostTesting.test.ts index dad5ae26397..fe0116c1b72 100644 --- a/src/vs/workbench/api/test/browser/extHostTesting.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTesting.test.ts @@ -102,19 +102,19 @@ suite('ExtHost Testing', () => { assert.deepStrictEqual(single.collectDiff(), [ { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: null, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(single.root) } } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(single.root) } } }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(a) } } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(a) } } }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-aa') as TestItemImpl) } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-aa') as TestItemImpl) } }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-ab') as TestItemImpl) } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-ab') as TestItemImpl) } }, { op: TestDiffOpType.Update, @@ -122,7 +122,7 @@ suite('ExtHost Testing', () => { }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) } }, { op: TestDiffOpType.Update, @@ -184,7 +184,6 @@ suite('ExtHost Testing', () => { { op: TestDiffOpType.Add, item: { controllerId: 'ctrlId', - parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(child), } @@ -213,7 +212,6 @@ suite('ExtHost Testing', () => { { op: TestDiffOpType.Add, item: { controllerId: 'ctrlId', - parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(child), } @@ -326,7 +324,7 @@ suite('ExtHost Testing', () => { }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) } + item: { controllerId: 'ctrlId', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) } }, ]); diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts index d0929417060..b20d910337b 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts @@ -18,6 +18,7 @@ import { InternalTestItem, TestDiffOpType, TestItemExpandState, TestResultState, import { TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult'; import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; const computedStateAccessor: IComputedStateAndDurationAccessor = { getOwnState: i => i instanceof TestItemTreeElement ? i.ownState : TestResultState.Unset, @@ -212,7 +213,8 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes } protected createItem(item: InternalTestItem): ByLocationTestItemElement { - const parent = item.parent ? this.items.get(item.parent)! : null; + const parentId = TestId.parentId(item.item.extId); + const parent = parentId ? this.items.get(parentId)! : null; return new ByLocationTestItemElement(item, parent, n => this.changes.addedOrRemoved(n)); } diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts index cd34647d6d0..eeedf8de3d4 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts @@ -12,6 +12,7 @@ import { NodeRenderDirective } from 'vs/workbench/contrib/testing/browser/explor import { InternalTestItem } from 'vs/workbench/contrib/testing/common/testTypes'; import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; /** * Type of test element in the list. @@ -97,7 +98,8 @@ export class HierarchicalByNameProjection extends HierarchicalByLocationProjecti * @override */ protected override createItem(item: InternalTestItem): ByLocationTestItemElement { - const actualParent = item.parent ? this.items.get(item.parent) as ByNameTestItemElement : undefined; + const parentId = TestId.parentId(item.item.extId); + const actualParent = parentId ? this.items.get(parentId.toString()) as ByNameTestItemElement : undefined; if (!actualParent) { return new ByNameTestItemElement(item, null, r => this.changes.addedOrRemoved(r)); } diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 97b16527952..3aaff497077 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -41,6 +41,7 @@ import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from 'vs/work import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme'; import { DefaultGutterClickAction, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; import { labelForTestInState, Testing } from 'vs/workbench/contrib/testing/common/constants'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; import { ITestDecoration as IPublicTestDecoration, ITestingDecorationsService, TestDecorations } from 'vs/workbench/contrib/testing/common/testingDecorations'; import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener'; import { isFailedState, maxPriority } from 'vs/workbench/contrib/testing/common/testingStates'; @@ -849,7 +850,7 @@ class MultiRunTestDecoration extends RunTestDecoration implements ITestDecoratio const testItems = this.tests.map(testItem => ({ currentLabel: testItem.test.item.label, testItem, - parent: testItem.test.parent, + parent: TestId.fromString(testItem.test.item.extId).parentId, })); const getLabelConflicts = (tests: typeof testItems) => { @@ -865,9 +866,9 @@ class MultiRunTestDecoration extends RunTestDecoration implements ITestDecoratio while ((conflicts = getLabelConflicts(testItems)).length && hasParent) { for (const conflict of conflicts) { if (conflict.parent) { - const parent = this.testService.collection.getNodeById(conflict.parent); + const parent = this.testService.collection.getNodeById(conflict.parent.toString()); conflict.currentLabel = parent?.item.label + ' > ' + conflict.currentLabel; - conflict.parent = parent?.parent ? parent.parent : null; + conflict.parent = conflict.parent.parentId; } else { hasParent = false; } diff --git a/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.ts b/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.ts index f8b3c45493a..4ac746110c3 100644 --- a/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.ts +++ b/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.ts @@ -89,11 +89,11 @@ export class MainThreadTestCollection extends AbstractIncrementalTestCollection< for (const child of queue.pop()!) { const item = this.items.get(child)!; ops.push({ - op: TestDiffOpType.Add, item: { + op: TestDiffOpType.Add, + item: { controllerId: item.controllerId, expand: item.expand, item: item.item, - parent: item.parent, } }); queue.push(item.children); diff --git a/src/vs/workbench/contrib/testing/common/testId.ts b/src/vs/workbench/contrib/testing/common/testId.ts index a5b5323aff9..2f0965c9e5b 100644 --- a/src/vs/workbench/contrib/testing/common/testId.ts +++ b/src/vs/workbench/contrib/testing/common/testId.ts @@ -84,6 +84,14 @@ export class TestId { return base.toString() + TestIdPathParts.Delimiter + b; } + /** + * Cheaply gets the parent ID of a test identified with the string. + */ + public static parentId(idString: string) { + const idx = idString.lastIndexOf(TestIdPathParts.Delimiter); + return idx === -1 ? undefined : idString.slice(0, idx); + } + /** * Compares the position of the two ID strings. */ @@ -115,8 +123,8 @@ export class TestId { /** * Gets the ID of the parent test. */ - public get parentId(): TestId { - return this.viewEnd > 1 ? new TestId(this.path, this.viewEnd - 1) : this; + public get parentId(): TestId | undefined { + return this.viewEnd > 1 ? new TestId(this.path, this.viewEnd - 1) : undefined; } /** @@ -150,6 +158,16 @@ export class TestId { } } + /** + * Returns an iterable that yields IDs of the current item up to the root + * item. + */ + public *idsToRoot() { + for (let i = this.viewEnd; i > 0; i--) { + yield new TestId(this.path, i); + } + } + /** * Compares the other test ID with this one. */ diff --git a/src/vs/workbench/contrib/testing/common/testItemCollection.ts b/src/vs/workbench/contrib/testing/common/testItemCollection.ts index 34ef310d046..e255f1d068d 100644 --- a/src/vs/workbench/contrib/testing/common/testItemCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testItemCollection.ts @@ -16,7 +16,6 @@ import { URI } from 'vs/base/common/uri'; */ interface CollectionItem { readonly fullId: TestId; - readonly parent: TestId | null; actual: T; expand: TestItemExpandState; /** @@ -351,7 +350,6 @@ export class TestItemCollection extends Disposable { internal = { fullId, actual, - parent: parent ? fullId.parentId : null, expandLevels: parent?.expandLevels /* intentionally undefined or 0 */ ? parent.expandLevels - 1 : undefined, expand: TestItemExpandState.NotExpandable, // updated by `connectItemAndChildren` }; @@ -362,7 +360,6 @@ export class TestItemCollection extends Disposable { this.pushDiff({ op: TestDiffOpType.Add, item: { - parent: internal.parent && internal.parent.toString(), controllerId: this.options.controllerId, expand: internal.expand, item: this.options.toITestItem(actual), diff --git a/src/vs/workbench/contrib/testing/common/testResult.ts b/src/vs/workbench/contrib/testing/common/testResult.ts index 670d740e1ba..b84725e61d0 100644 --- a/src/vs/workbench/contrib/testing/common/testResult.ts +++ b/src/vs/workbench/contrib/testing/common/testResult.ts @@ -7,7 +7,6 @@ import { newWriteableBufferStream, VSBuffer, VSBufferReadableStream, VSBufferWri import { Emitter } from 'vs/base/common/event'; import { Lazy } from 'vs/base/common/lazy'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contrib/testing/common/getComputedState'; import { IObservableValue, MutableObservableValue, staticObservableValue } from 'vs/workbench/contrib/testing/common/observableValue'; @@ -15,6 +14,7 @@ import { getMarkId, IRichLocation, ISerializedTestResults, ITestItem, ITestMessa import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage'; import { maxPriority, statesInOrder, terminalStatePriorities } from 'vs/workbench/contrib/testing/common/testingStates'; import { removeAnsiEscapeCodes } from 'vs/base/common/strings'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; export interface ITestRunTaskResults extends ITestRunTask { /** @@ -88,10 +88,8 @@ export interface ITestResult { } export const resultItemParents = function* (results: ITestResult, item: TestResultItem) { - let i: TestResultItem | undefined = item; - while (i) { - yield i; - i = i.parent ? results.getStateById(i.parent) : undefined; + for (const id of TestId.fromString(item.item.extId).idsToRoot()) { + yield results.getStateById(id.toString())!; } }; @@ -266,7 +264,6 @@ interface TestResultItemWithChildren extends TestResultItem { } const itemToNode = (controllerId: string, item: ITestItem, parent: string | null): TestResultItemWithChildren => ({ - parent, controllerId, expand: TestItemExpandState.NotExpandable, item: { ...item }, @@ -329,14 +326,11 @@ export class LiveTestResult implements ITestResult { getParents: i => { const { testById: testByExtId } = this; return (function* () { - for (let parentId = i.parent; parentId;) { - const parent = testByExtId.get(parentId); - if (!parent) { - break; + const parentId = TestId.fromString(i.item.extId).parentId; + if (parentId) { + for (const id of parentId.idsToRoot()) { + yield testByExtId.get(id.toString())!; } - - yield parent; - parentId = parent.parent; } })(); }, @@ -665,11 +659,9 @@ export class HydratedTestResult implements ITestResult { this.request = serialized.request; for (const item of serialized.items) { - const cast: TestResultItem = { ...item } as any; - cast.item.uri = URI.revive(cast.item.uri); - cast.retired = true; - this.counts[item.ownComputedState]++; - this.testById.set(item.item.extId, cast); + const de = TestResultItem.deserialize(item); + this.counts[de.ownComputedState]++; + this.testById.set(item.item.extId, de); } } diff --git a/src/vs/workbench/contrib/testing/common/testService.ts b/src/vs/workbench/contrib/testing/common/testService.ts index f4a19c91d99..5aeb3815ed6 100644 --- a/src/vs/workbench/contrib/testing/common/testService.ts +++ b/src/vs/workbench/contrib/testing/common/testService.ts @@ -77,10 +77,8 @@ export interface IMainThreadTestCollection extends AbstractIncrementalTestCollec * Iterates through the item and its parents to the root. */ export const getCollectionItemParents = function* (collection: IMainThreadTestCollection, item: InternalTestItem) { - let i: InternalTestItem | undefined = item; - while (i) { - yield i; - i = i.parent ? collection.getNodeById(i.parent) : undefined; + for (const id of TestId.fromString(item.item.extId).idsToRoot()) { + yield collection.getNodeById(id.toString())!; } }; diff --git a/src/vs/workbench/contrib/testing/common/testTypes.ts b/src/vs/workbench/contrib/testing/common/testTypes.ts index f7c2f4d0aae..cba30fb1288 100644 --- a/src/vs/workbench/contrib/testing/common/testTypes.ts +++ b/src/vs/workbench/contrib/testing/common/testTypes.ts @@ -8,6 +8,7 @@ import { MarshalledId } from 'vs/base/common/marshallingIds'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; export const enum TestResultState { Unset = 0, @@ -340,31 +341,27 @@ export interface InternalTestItem { controllerId: string; /** Expandability state */ expand: TestItemExpandState; - /** Parent ID, if any */ - parent: string | null; /** Raw test item properties */ item: ITestItem; } export namespace InternalTestItem { export interface Serialized { - controllerId: string; expand: TestItemExpandState; - parent: string | null; item: ITestItem.Serialized; } export const serialize = (item: InternalTestItem): Serialized => ({ - controllerId: item.controllerId, expand: item.expand, - parent: item.parent, item: ITestItem.serialize(item.item) }); export const deserialize = (serialized: Serialized): InternalTestItem => ({ - controllerId: serialized.controllerId, + // the `controllerId` is derived from the test.item.extId. It's redundant + // in the non-serialized InternalTestItem too, but there just because it's + // checked against in many hot paths. + controllerId: TestId.root(serialized.item.extId), expand: serialized.expand, - parent: serialized.parent, item: ITestItem.deserialize(serialized.item) }); } @@ -469,6 +466,14 @@ export namespace TestResultItem { tasks: original.tasks.map(ITestTaskState.serialize), retired: original.retired, }); + + export const deserialize = (serialized: Serialized): TestResultItem => ({ + ...InternalTestItem.deserialize(serialized), + ownComputedState: serialized.ownComputedState, + computedState: serialized.computedState, + tasks: serialized.tasks.map(ITestTaskState.deserialize), + retired: true, + }); } export interface ISerializedTestResults { @@ -684,13 +689,14 @@ export abstract class AbstractIncrementalTestCollection { harness.flush(); harness.pushDiff({ op: TestDiffOpType.Add, - item: { controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: new TestTestItem('ctrl2', 'c', 'c').toTestItem() }, + item: { controllerId: 'ctrl2', expand: TestItemExpandState.Expanded, item: new TestTestItem(new TestId(['ctrlId2']), 'c').toTestItem() }, }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrl2', parent: new TestId(['ctrl2', 'c']).toString(), expand: TestItemExpandState.NotExpandable, item: new TestTestItem('ctrl2', 'c-a', 'ca').toTestItem() }, + item: { controllerId: 'ctrl2', expand: TestItemExpandState.NotExpandable, item: new TestTestItem(new TestId(['ctrlId2', 'id-c']), 'ca').toTestItem() }, }); assert.deepStrictEqual(harness.flush(), [ @@ -76,7 +76,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => { { e: 'b' } ]); - harness.c.root.children.get('id-a')!.children.add(new TestTestItem('ctrlId', 'ac', 'ac')); + harness.c.root.children.get('id-a')!.children.add(new TestTestItem(new TestId(['ctrlId', 'id-a', 'id-ac']), 'ac')); assert.deepStrictEqual(harness.flush(), [ { e: 'a', children: [{ e: 'aa' }, { e: 'ab' }, { e: 'ac' }] }, @@ -117,7 +117,6 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => { tags: [], uri: undefined, }, - parent: 'id-root', tasks: [], ownComputedState: state, computedState: state, diff --git a/src/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByName.test.ts b/src/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByName.test.ts index ec4424b8edd..05f27076a0a 100644 --- a/src/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByName.test.ts +++ b/src/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByName.test.ts @@ -8,10 +8,10 @@ import { AbstractTreeViewState } from 'vs/base/browser/ui/tree/abstractTree'; import { Emitter } from 'vs/base/common/event'; import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName'; import { TestDiffOpType, TestItemExpandState } from 'vs/workbench/contrib/testing/common/testTypes'; -import { TestId } from 'vs/workbench/contrib/testing/common/testId'; import { TestResultItemChange } from 'vs/workbench/contrib/testing/common/testResult'; import { TestTreeTestHarness } from 'vs/workbench/contrib/testing/test/browser/testObjectTree'; import { TestTestItem } from 'vs/workbench/contrib/testing/test/common/testStubs'; +import { TestId } from 'vs/workbench/contrib/testing/common/testId'; suite('Workbench - Testing Explorer Hierarchal by Name Projection', () => { let harness: TestTreeTestHarness; @@ -44,10 +44,10 @@ suite('Workbench - Testing Explorer Hierarchal by Name Projection', () => { harness.flush(); harness.pushDiff({ op: TestDiffOpType.Add, - item: { controllerId: 'ctrl2', parent: null, expand: TestItemExpandState.Expanded, item: new TestTestItem('ctrl2', 'c', 'root2').toTestItem() }, + item: { controllerId: 'ctrl2', expand: TestItemExpandState.Expanded, item: new TestTestItem(new TestId(['ctrl2']), 'root2').toTestItem() }, }, { op: TestDiffOpType.Add, - item: { controllerId: 'ctrl2', parent: new TestId(['ctrl2', 'c']).toString(), expand: TestItemExpandState.NotExpandable, item: new TestTestItem('ctrl2', 'c-a', 'c', undefined).toTestItem() }, + item: { controllerId: 'ctrl2', expand: TestItemExpandState.NotExpandable, item: new TestTestItem(new TestId(['ctrl2', 'id-c']), 'c', undefined).toTestItem() }, }); assert.deepStrictEqual(harness.flush(), [ @@ -59,7 +59,7 @@ suite('Workbench - Testing Explorer Hierarchal by Name Projection', () => { test('updates nodes if they add children', async () => { harness.flush(); - harness.c.root.children.get('id-a')!.children.add(new TestTestItem('ctrl2', 'ac', 'ac')); + harness.c.root.children.get('id-a')!.children.add(new TestTestItem(new TestId(['ctrlId', 'id-a', 'id-ac']), 'ac')); assert.deepStrictEqual(harness.flush(), [ { e: 'aa' }, @@ -81,7 +81,7 @@ suite('Workbench - Testing Explorer Hierarchal by Name Projection', () => { test('swaps when node is no longer leaf', async () => { harness.flush(); - harness.c.root.children.get('id-b')!.children.add(new TestTestItem('ctrl2', 'ba', 'ba')); + harness.c.root.children.get('id-b')!.children.add(new TestTestItem(new TestId(['ctrlId', 'id-b', 'id-ba']), 'ba')); assert.deepStrictEqual(harness.flush(), [ { e: 'aa' }, diff --git a/src/vs/workbench/contrib/testing/test/common/testStubs.ts b/src/vs/workbench/contrib/testing/test/common/testStubs.ts index f05f2a55214..a8770a29e15 100644 --- a/src/vs/workbench/contrib/testing/test/common/testStubs.ts +++ b/src/vs/workbench/contrib/testing/test/common/testStubs.ts @@ -35,18 +35,21 @@ export class TestTestItem implements ITestItemLike { return this.api.parent; } - public api: ITestItemApi = { controllerId: this.controllerId }; + public get id() { + return this._extId.localId; + } + + public api: ITestItemApi = { controllerId: this._extId.controllerId }; public children = createTestItemChildren(this.api, i => i.api, TestTestItem); constructor( - public readonly controllerId: string, - public readonly id: string, + private readonly _extId: TestId, label: string, uri?: URI, ) { this.props = { - extId: '', + extId: _extId.toString(), busy: false, description: null, error: null, @@ -69,20 +72,23 @@ export class TestTestItem implements ITestItemLike { public toTestItem(): ITestItem { const props = { ...this.props }; - props.extId = TestId.fromExtHostTestItem(this, this.controllerId).toString(); + props.extId = this._extId.toString(); return props; } } export class TestTestCollection extends TestItemCollection { constructor(controllerId = 'ctrlId') { + const root = new TestTestItem(new TestId([controllerId]), 'root'); + (root as any)._isRoot = true; + super({ controllerId, getApiFor: t => t.api, toITestItem: t => t.toTestItem(), getChildren: t => t.children, getDocumentVersion: () => undefined, - root: new TestTestItem(controllerId, controllerId, 'root'), + root, }); } @@ -111,14 +117,14 @@ export const testStubs = { const collection = new TestTestCollection(); collection.resolveHandler = item => { if (item === undefined) { - const a = new TestTestItem('ctrlId', idPrefix + 'a', 'a', URI.file('/')); + const a = new TestTestItem(new TestId(['ctrlId', 'id-a']), 'a', URI.file('/')); a.canResolveChildren = true; - const b = new TestTestItem('ctrlId', idPrefix + 'b', 'b', URI.file('/')); + const b = new TestTestItem(new TestId(['ctrlId', 'id-b']), 'b', URI.file('/')); collection.root.children.add(a); collection.root.children.add(b); } else if (item.id === idPrefix + 'a') { - item.children.add(new TestTestItem('ctrlId', idPrefix + 'aa', 'aa', URI.file('/'))); - item.children.add(new TestTestItem('ctrlId', idPrefix + 'ab', 'ab', URI.file('/'))); + item.children.add(new TestTestItem(new TestId(['ctrlId', 'id-a', 'id-aa']), 'aa', URI.file('/'))); + item.children.add(new TestTestItem(new TestId(['ctrlId', 'id-a', 'id-ab']), 'ab', URI.file('/'))); } }; From c9338005f7210e26c529891f21a85d26a2bebc87 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 3 Oct 2022 23:02:53 -0700 Subject: [PATCH 286/599] Add 'reopen with' to open editors context menu (#162623) --- .../files/browser/fileActions.contribution.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 57bb796dfc4..a2b85639809 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -18,11 +18,11 @@ import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/com import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext, ExplorerResourceAvailableEditorIdsContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; -import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; +import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, REOPEN_WITH_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { Schemas } from 'vs/base/common/network'; -import { DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey } from 'vs/workbench/common/contextkeys'; +import { DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/contextkeys'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -226,6 +226,16 @@ MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { when: isFileOrUntitledResourceContextKey }); +MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { + group: '1_open', + order: 10, + command: { + id: REOPEN_WITH_COMMAND_ID, + title: nls.localize('reopenWith', "Reopen Editor With...") + }, + when: ActiveEditorAvailableEditorIdsContext +}); + MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { group: '1_cutcopypaste', order: 10, From aaa279648f6eb9e30bd47345bf04d8ad95e98f7b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 4 Oct 2022 11:55:38 +0200 Subject: [PATCH 287/599] clean up (#162649) --- .../extensions/test/electron-browser/extensionsActions.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index caabf67a2eb..4b6b310e139 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -68,7 +68,7 @@ let installEvent: Emitter, let disposables: DisposableStore; -async function setupTest() { +function setupTest() { disposables = new DisposableStore(); installEvent = new Emitter(); didInstallEvent = new Emitter(); From d70a688a39589ecea2ecb74b11a3c68001e2ffcf Mon Sep 17 00:00:00 2001 From: Marcus Date: Tue, 4 Oct 2022 14:00:53 +0200 Subject: [PATCH 288/599] # simplify response --- .../workbench/contrib/bulkEdit/browser/bulkEditService.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts index 9181c5a6dcb..34d4848bd12 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts @@ -88,10 +88,6 @@ class BulkEdit { } } - isApplied(): boolean { - return this._edits.length > 0; - } - async perform(): Promise { if (this._edits.length === 0) { @@ -252,7 +248,7 @@ export class BulkEditService implements IBulkEditService { await this._saveAll(resources); } - return { ariaSummary: bulkEdit.ariaMessage(), isApplied: bulkEdit.isApplied() }; + return { ariaSummary: bulkEdit.ariaMessage(), isApplied: edits.length > 0 }; } catch (err) { // console.log('apply FAILED'); // console.log(err); From 14d1b6f79ec1ad7a290c4930f5047838500a9f24 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2022 14:33:06 +0200 Subject: [PATCH 289/599] make `registerSingleton` only accept `InstantiationType` or `false` (#162654) https://github.com/microsoft/vscode/issues/159178 --- .../services/languageFeatureDebounce.ts | 4 +-- .../services/languageFeaturesService.ts | 4 +-- .../contrib/codelens/browser/codeLensCache.ts | 4 +-- .../documentSymbols/browser/outlineModel.ts | 4 +-- .../browser/markerNavigationService.ts | 4 +-- .../gotoSymbol/browser/symbolNavigation.ts | 4 +-- .../browser/inlayHintsController.ts | 4 +-- .../contrib/suggest/browser/suggestMemory.ts | 4 +-- .../browser/standaloneLayoutService.ts | 4 +-- .../extensionsScannerService.ts | 4 +-- .../instantiation/common/extensions.ts | 2 +- .../uriIdentity/common/uriIdentityService.ts | 4 +-- .../api/common/extHost.common.services.ts | 10 +++---- .../api/node/extHost.node.services.ts | 4 +-- .../browser/parts/editor/breadcrumbs.ts | 4 +-- .../browser/parts/paneCompositePart.ts | 4 +-- .../bulkEdit/browser/bulkEditService.ts | 4 +-- .../debug/browser/debug.contribution.ts | 4 +-- .../browser/extensionHostDebugService.ts | 4 +-- .../browser/experiments.contribution.ts | 4 +-- .../browser/extensions.contribution.ts | 2 +- .../extensions.contribution.ts | 4 +-- .../files/browser/files.contribution.ts | 4 +-- .../issue/browser/issue.web.contribution.ts | 4 +-- .../electron-sandbox/issue.contribution.ts | 4 +-- .../browser/localization.contribution.ts | 4 +-- .../localization.contribution.ts | 4 +-- .../notebook/browser/notebook.contribution.ts | 18 ++++++------ .../output/browser/output.contribution.ts | 4 +-- .../common/outputChannelModelService.ts | 4 +-- .../outputChannelModelService.ts | 4 +-- .../preferences/browser/preferencesSearch.ts | 4 +-- .../contrib/scm/browser/scm.contribution.ts | 6 ++-- .../search/browser/replaceContributions.ts | 4 +-- .../search/browser/search.contribution.ts | 6 ++-- .../snippets/browser/snippets.contribution.ts | 4 +-- .../splash/browser/splash.contribution.ts | 4 +-- .../electron-sandbox/splash.contribution.ts | 4 +-- .../tags/browser/workspaceTagsService.ts | 4 +-- .../electron-sandbox/workspaceTagsService.ts | 4 +-- .../contrib/tasks/browser/taskService.ts | 4 +-- .../tasks/electron-sandbox/taskService.ts | 4 +-- .../terminal/browser/terminal.contribution.ts | 12 ++++---- .../browser/terminal.web.contribution.ts | 4 +-- .../browser/terminalInstanceService.ts | 4 +-- .../environmentVariable.contribution.ts | 4 +-- .../terminalExtensionPoints.contribution.ts | 4 +-- .../electron-sandbox/terminal.contribution.ts | 4 +-- .../testing/browser/testing.contribution.ts | 20 ++++++------- .../timeline/browser/timeline.contribution.ts | 4 +-- .../browser/webview.web.contribution.ts | 4 +-- .../electron-sandbox/webview.contribution.ts | 4 +-- .../browser/webviewPanel.contribution.ts | 4 +-- .../browser/webviewView.contribution.ts | 4 +-- .../browser/gettingStartedService.ts | 4 +-- .../electron-sandbox/accessibilityService.ts | 4 +-- .../activity/browser/activityService.ts | 4 +-- .../assignment/common/assignmentService.ts | 4 +-- .../clipboard/browser/clipboardService.ts | 4 +-- .../electron-sandbox/clipboardService.ts | 4 +-- .../commands/common/commandService.ts | 4 +-- .../common/jsonEditingService.ts | 4 +-- .../browser/configurationResolverService.ts | 4 +-- .../configurationResolverService.ts | 4 +-- .../electron-sandbox/contextmenuService.ts | 4 +-- .../decorations/browser/decorationsService.ts | 4 +-- .../dialogs/browser/fileDialogService.ts | 4 +-- .../services/dialogs/common/dialogService.ts | 4 +-- .../electron-sandbox/fileDialogService.ts | 4 +-- .../editor/browser/codeEditorService.ts | 4 +-- .../encryption/browser/encryptionService.ts | 4 +-- .../shellEnvironmentService.ts | 4 +-- .../builtinExtensionsScannerService.ts | 4 +-- .../browser/extensionBisect.ts | 4 +-- .../browser/extensionEnablementService.ts | 4 +-- .../browser/webExtensionsScannerService.ts | 4 +-- .../extensionManagementServerService.ts | 4 +-- .../extensionManagementServerService.ts | 4 +-- .../extensionManagementService.ts | 4 +-- .../electron-sandbox/extensionTipsService.ts | 4 +-- .../extensionIgnoredRecommendationsService.ts | 4 +-- .../common/workspaceExtensionsConfig.ts | 4 +-- .../browser/extensionResourceLoaderService.ts | 4 +-- .../extensionResourceLoaderService.ts | 4 +-- .../extensionManifestPropertiesService.ts | 4 +-- .../files/browser/elevatedFileService.ts | 4 +-- .../electron-sandbox/elevatedFileService.ts | 4 +-- .../host/browser/browserHostService.ts | 4 +-- .../electron-sandbox/nativeHostService.ts | 6 ++-- .../services/hover/browser/hoverService.ts | 4 +-- .../integrity/browser/integrityService.ts | 4 +-- .../electron-sandbox/integrityService.ts | 4 +-- .../browser/keyboardLayoutService.ts | 4 +-- .../keybinding/common/keybindingEditing.ts | 4 +-- .../services/label/common/labelService.ts | 4 +-- .../common/languageStatusService.ts | 4 +-- .../services/model/common/modelService.ts | 4 +-- .../common/notificationService.ts | 4 +-- .../outline/browser/outlineService.ts | 4 +-- .../services/path/browser/pathService.ts | 4 +-- .../path/electron-sandbox/pathService.ts | 4 +-- .../preferences/browser/preferencesService.ts | 4 +-- .../progress/browser/progressService.ts | 4 +-- .../quickinput/browser/quickInputService.ts | 4 +-- .../remote/common/remoteExplorerService.ts | 4 +-- .../electron-sandbox/requestService.ts | 4 +-- .../services/search/browser/searchService.ts | 4 +-- .../search/electron-sandbox/searchService.ts | 4 +-- .../telemetry/browser/telemetryService.ts | 4 +-- .../electron-sandbox/telemetryService.ts | 4 +-- .../common/textModelResolverService.ts | 4 +-- .../common/textResourcePropertiesService.ts | 4 +-- .../browser/browserHostColorSchemeService.ts | 4 +-- .../nativeHostColorSchemeService.ts | 4 +-- .../timer/electron-sandbox/timerService.ts | 4 +-- .../services/tunnel/browser/tunnelService.ts | 4 +-- .../common/untitledTextEditorService.ts | 4 +-- .../services/url/browser/urlService.ts | 4 +-- .../userDataProfileImportExportService.ts | 4 +-- .../browser/userDataSyncEnablementService.ts | 4 +-- .../webUserDataSyncEnablementService.ts | 4 +-- .../userDataSync/common/userDataSyncUtil.ts | 4 +-- .../userDataAutoSyncService.ts | 4 +-- .../userDataSyncAccountService.ts | 4 +-- .../userDataSyncMachinesService.ts | 4 +-- .../userDataSyncStoreManagementService.ts | 4 +-- .../views/browser/viewDescriptorService.ts | 4 +-- .../browser/workingCopyHistoryService.ts | 4 +-- .../common/workingCopyEditorService.ts | 4 +-- .../common/workingCopyFileService.ts | 4 +-- .../workingCopy/common/workingCopyService.ts | 4 +-- .../workingCopyHistoryService.ts | 4 +-- .../browser/workspaceEditingService.ts | 4 +-- .../workspaces/browser/workspacesService.ts | 4 +-- .../common/editSessionIdentityService.ts | 4 +-- .../workspaceEditingService.ts | 4 +-- .../electron-sandbox/workspacesService.ts | 4 +-- src/vs/workbench/workbench.common.main.ts | 28 +++++++++---------- src/vs/workbench/workbench.desktop.main.ts | 4 +-- src/vs/workbench/workbench.web.main.ts | 28 +++++++++---------- 140 files changed, 327 insertions(+), 327 deletions(-) diff --git a/src/vs/editor/common/services/languageFeatureDebounce.ts b/src/vs/editor/common/services/languageFeatureDebounce.ts index e4e67bd700f..417a2d9dc08 100644 --- a/src/vs/editor/common/services/languageFeatureDebounce.ts +++ b/src/vs/editor/common/services/languageFeatureDebounce.ts @@ -8,7 +8,7 @@ import { LRUCache } from 'vs/base/common/map'; import { clamp, MovingAverage, SlidingWindowAverage } from 'vs/base/common/numbers'; import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry'; import { ITextModel } from 'vs/editor/common/model'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { matchesScheme } from 'vs/platform/opener/common/opener'; @@ -136,4 +136,4 @@ export class LanguageFeatureDebounceService implements ILanguageFeatureDebounceS } } -registerSingleton(ILanguageFeatureDebounceService, LanguageFeatureDebounceService, true); +registerSingleton(ILanguageFeatureDebounceService, LanguageFeatureDebounceService, InstantiationType.Delayed); diff --git a/src/vs/editor/common/services/languageFeaturesService.ts b/src/vs/editor/common/services/languageFeaturesService.ts index 4059a90b370..35d321b4ef2 100644 --- a/src/vs/editor/common/services/languageFeaturesService.ts +++ b/src/vs/editor/common/services/languageFeaturesService.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import { LanguageFeatureRegistry, NotebookInfo, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry'; import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DocumentPasteEditProvider, 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'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class LanguageFeaturesService implements ILanguageFeaturesService { @@ -55,4 +55,4 @@ export class LanguageFeaturesService implements ILanguageFeaturesService { } -registerSingleton(ILanguageFeaturesService, LanguageFeaturesService, true); +registerSingleton(ILanguageFeaturesService, LanguageFeaturesService, InstantiationType.Delayed); diff --git a/src/vs/editor/contrib/codelens/browser/codeLensCache.ts b/src/vs/editor/contrib/codelens/browser/codeLensCache.ts index f6696e42746..4ab8835ae2f 100644 --- a/src/vs/editor/contrib/codelens/browser/codeLensCache.ts +++ b/src/vs/editor/contrib/codelens/browser/codeLensCache.ts @@ -10,7 +10,7 @@ import { Range } from 'vs/editor/common/core/range'; import { ITextModel } from 'vs/editor/common/model'; import { CodeLens, CodeLensList, CodeLensProvider } from 'vs/editor/common/languages'; import { CodeLensModel } from 'vs/editor/contrib/codelens/browser/codelens'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage'; @@ -129,4 +129,4 @@ export class CodeLensCache implements ICodeLensCache { } } -registerSingleton(ICodeLensCache, CodeLensCache, true); +registerSingleton(ICodeLensCache, CodeLensCache, InstantiationType.Delayed); diff --git a/src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts index bbebc0a585e..e9746fec571 100644 --- a/src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts @@ -17,7 +17,7 @@ import { DocumentSymbol, DocumentSymbolProvider } from 'vs/editor/common/languag import { MarkerSeverity } from 'vs/platform/markers/common/markers'; import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IModelService } from 'vs/editor/common/services/model'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry'; @@ -485,4 +485,4 @@ export class OutlineModelService implements IOutlineModelService { } } -registerSingleton(IOutlineModelService, OutlineModelService, true); +registerSingleton(IOutlineModelService, OutlineModelService, InstantiationType.Delayed); diff --git a/src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts b/src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts index 8e7e0bb70d6..1162ef145ea 100644 --- a/src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts +++ b/src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ITextModel } from 'vs/editor/common/model'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -221,4 +221,4 @@ class MarkerNavigationService implements IMarkerNavigationService, IMarkerListPr } } -registerSingleton(IMarkerNavigationService, MarkerNavigationService, true); +registerSingleton(IMarkerNavigationService, MarkerNavigationService, InstantiationType.Delayed); diff --git a/src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts b/src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts index e0ff47c0935..2c7046f3d31 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts @@ -15,7 +15,7 @@ import { OneReference, ReferencesModel } from 'vs/editor/contrib/gotoSymbol/brow import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -149,7 +149,7 @@ class SymbolNavigationService implements ISymbolNavigationService { } } -registerSingleton(ISymbolNavigationService, SymbolNavigationService, true); +registerSingleton(ISymbolNavigationService, SymbolNavigationService, InstantiationType.Delayed); registerEditorCommand(new class extends EditorCommand { diff --git a/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts b/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts index 0e59778b739..4e7cce9783d 100644 --- a/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts @@ -29,7 +29,7 @@ import { ClickLinkGesture, ClickLinkMouseEvent } from 'vs/editor/contrib/gotoSym import { InlayHintAnchor, InlayHintItem, InlayHintsFragments } from 'vs/editor/contrib/inlayHints/browser/inlayHints'; import { goToDefinitionWithLocation, showGoToContextMenu } from 'vs/editor/contrib/inlayHints/browser/inlayHintsLocations'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import * as colors from 'vs/platform/theme/common/colorRegistry'; @@ -60,7 +60,7 @@ class InlayHintsCache { interface IInlayHintsCache extends InlayHintsCache { } const IInlayHintsCache = createDecorator('IInlayHintsCache'); -registerSingleton(IInlayHintsCache, InlayHintsCache, true); +registerSingleton(IInlayHintsCache, InlayHintsCache, InstantiationType.Delayed); // --- rendered label diff --git a/src/vs/editor/contrib/suggest/browser/suggestMemory.ts b/src/vs/editor/contrib/suggest/browser/suggestMemory.ts index 8b2868cbde9..dce5326c6da 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestMemory.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestMemory.ts @@ -12,7 +12,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { CompletionItemKind, CompletionItemKinds } from 'vs/editor/common/languages'; import { CompletionItem } from 'vs/editor/contrib/suggest/browser/suggest'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage'; @@ -306,4 +306,4 @@ export interface ISuggestMemoryService { select(model: ITextModel, pos: IPosition, items: CompletionItem[]): number; } -registerSingleton(ISuggestMemoryService, SuggestMemoryService, true); +registerSingleton(ISuggestMemoryService, SuggestMemoryService, InstantiationType.Delayed); diff --git a/src/vs/editor/standalone/browser/standaloneLayoutService.ts b/src/vs/editor/standalone/browser/standaloneLayoutService.ts index aba9ec78509..42b7b0786a3 100644 --- a/src/vs/editor/standalone/browser/standaloneLayoutService.ts +++ b/src/vs/editor/standalone/browser/standaloneLayoutService.ts @@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; import { ILayoutService, ILayoutOffsetInfo } from 'vs/platform/layout/browser/layoutService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; class StandaloneLayoutService implements ILayoutService { declare readonly _serviceBrand: undefined; @@ -63,4 +63,4 @@ export class EditorScopedLayoutService extends StandaloneLayoutService { } } -registerSingleton(ILayoutService, StandaloneLayoutService, true); +registerSingleton(ILayoutService, StandaloneLayoutService, InstantiationType.Delayed); diff --git a/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts b/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts index c13b4c23371..f99ba24598c 100644 --- a/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts @@ -8,7 +8,7 @@ import { INativeEnvironmentService } from 'vs/platform/environment/common/enviro import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IExtensionsScannerService, NativeExtensionsScannerService, } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -35,4 +35,4 @@ export class ExtensionsScannerService extends NativeExtensionsScannerService imp } -registerSingleton(IExtensionsScannerService, ExtensionsScannerService, true); +registerSingleton(IExtensionsScannerService, ExtensionsScannerService, InstantiationType.Delayed); diff --git a/src/vs/platform/instantiation/common/extensions.ts b/src/vs/platform/instantiation/common/extensions.ts index 474a9a59ea1..6b3cb6ac484 100644 --- a/src/vs/platform/instantiation/common/extensions.ts +++ b/src/vs/platform/instantiation/common/extensions.ts @@ -22,7 +22,7 @@ export const enum InstantiationType { Delayed = 1 } -export function registerSingleton(id: ServiceIdentifier, ctor: new (...services: Services) => T, supportsDelayedInstantiation: boolean | InstantiationType): void; +export function registerSingleton(id: ServiceIdentifier, ctor: new (...services: Services) => T, supportsDelayedInstantiation: false | InstantiationType): void; export function registerSingleton(id: ServiceIdentifier, descriptor: SyncDescriptor): void; export function registerSingleton(id: ServiceIdentifier, ctorOrDescriptor: { new(...services: Services): T } | SyncDescriptor, supportsDelayedInstantiation?: boolean | InstantiationType): void { if (!(ctorOrDescriptor instanceof SyncDescriptor)) { diff --git a/src/vs/platform/uriIdentity/common/uriIdentityService.ts b/src/vs/platform/uriIdentity/common/uriIdentityService.ts index a0bbc55fa66..a4a23090906 100644 --- a/src/vs/platform/uriIdentity/common/uriIdentityService.ts +++ b/src/vs/platform/uriIdentity/common/uriIdentityService.ts @@ -5,7 +5,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService, FileSystemProviderCapabilities, IFileSystemProviderCapabilitiesChangeEvent, IFileSystemProviderRegistrationEvent } from 'vs/platform/files/common/files'; import { ExtUri, IExtUri, normalizePath } from 'vs/base/common/resources'; import { SkipList } from 'vs/base/common/skipList'; @@ -114,4 +114,4 @@ export class UriIdentityService implements IUriIdentityService { } } -registerSingleton(IUriIdentityService, UriIdentityService, true); +registerSingleton(IUriIdentityService, UriIdentityService, InstantiationType.Delayed); diff --git a/src/vs/workbench/api/common/extHost.common.services.ts b/src/vs/workbench/api/common/extHost.common.services.ts index 4658a622298..f00aebebc47 100644 --- a/src/vs/workbench/api/common/extHost.common.services.ts +++ b/src/vs/workbench/api/common/extHost.common.services.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtHostOutputService, ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput'; import { IExtHostWorkspace, ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations'; @@ -30,9 +30,9 @@ import { ExtHostVariableResolverProviderService, IExtHostVariableResolverProvide import { ExtHostTelemetryLogService, IExtHostTelemetryLogService } from 'vs/workbench/api/common/extHostTelemetryLogService'; import { ExtHostLocalizationService, IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService'; -registerSingleton(IExtHostLocalizationService, ExtHostLocalizationService, true); -registerSingleton(ILoggerService, ExtHostLoggerService, true); -registerSingleton(ILogService, ExtHostLogService, true); +registerSingleton(IExtHostLocalizationService, ExtHostLocalizationService, InstantiationType.Delayed); +registerSingleton(ILoggerService, ExtHostLoggerService, InstantiationType.Delayed); +registerSingleton(ILogService, ExtHostLogService, InstantiationType.Delayed); registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService, false); registerSingleton(IExtHostCommands, ExtHostCommands, false); registerSingleton(IExtHostConfiguration, ExtHostConfiguration, false); @@ -41,7 +41,7 @@ registerSingleton(IExtHostDebugService, WorkerExtHostDebugService, false); registerSingleton(IExtHostDecorations, ExtHostDecorations, false); registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors, false); registerSingleton(IExtHostFileSystemInfo, ExtHostFileSystemInfo, false); -registerSingleton(IExtHostOutputService, ExtHostOutputService, true); +registerSingleton(IExtHostOutputService, ExtHostOutputService, InstantiationType.Delayed); registerSingleton(IExtHostSearch, ExtHostSearch, false); registerSingleton(IExtHostStorage, ExtHostStorage, false); registerSingleton(IExtHostTask, WorkerExtHostTask, false); diff --git a/src/vs/workbench/api/node/extHost.node.services.ts b/src/vs/workbench/api/node/extHost.node.services.ts index 27562ce32ca..98d300f7d8c 100644 --- a/src/vs/workbench/api/node/extHost.node.services.ts +++ b/src/vs/workbench/api/node/extHost.node.services.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService'; import { ExtHostTask } from 'vs/workbench/api/node/extHostTask'; import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService'; @@ -30,7 +30,7 @@ import { IExtHostVariableResolverProvider } from 'vs/workbench/api/common/extHos // ######################################################################### registerSingleton(IExtHostExtensionService, ExtHostExtensionService, false); -registerSingleton(ILoggerService, ExtHostLoggerService, true); +registerSingleton(ILoggerService, ExtHostLoggerService, InstantiationType.Delayed); registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths, false); registerSingleton(IExtHostDebugService, ExtHostDebugService, false); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts index f2a44d8b1db..af5bdc2b61f 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts @@ -10,7 +10,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { GroupIdentifier, IEditorPartOptions } from 'vs/workbench/common/editor'; @@ -48,7 +48,7 @@ export class BreadcrumbsService implements IBreadcrumbsService { } } -registerSingleton(IBreadcrumbsService, BreadcrumbsService, true); +registerSingleton(IBreadcrumbsService, BreadcrumbsService, InstantiationType.Delayed); //#region config diff --git a/src/vs/workbench/browser/parts/paneCompositePart.ts b/src/vs/workbench/browser/parts/paneCompositePart.ts index c0ee4b101f3..dd035d916fb 100644 --- a/src/vs/workbench/browser/parts/paneCompositePart.ts +++ b/src/vs/workbench/browser/parts/paneCompositePart.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { assertIsDefined } from 'vs/base/common/types'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressIndicator } from 'vs/platform/progress/common/progress'; import { PaneCompositeDescriptor } from 'vs/workbench/browser/panecomposite'; @@ -159,4 +159,4 @@ export class PaneCompositeParts extends Disposable implements IPaneCompositePart } } -registerSingleton(IPaneCompositePartService, PaneCompositeParts, true); +registerSingleton(IPaneCompositePartService, PaneCompositeParts, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts index ae0212db0c5..146a50b6483 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts @@ -16,7 +16,7 @@ import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IProgress, IProgressStep, Progress } from 'vs/platform/progress/common/progress'; @@ -289,7 +289,7 @@ export class BulkEditService implements IBulkEditService { } } -registerSingleton(IBulkEditService, BulkEditService, true); +registerSingleton(IBulkEditService, BulkEditService, InstantiationType.Delayed); const autoSaveSetting = 'files.refactoring.autoSave'; diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index d065ee2c811..cc89778fd07 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -9,7 +9,7 @@ import * as nls from 'vs/nls'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { BreakpointsView } from 'vs/workbench/contrib/debug/browser/breakpointsView'; import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'; @@ -61,7 +61,7 @@ import { DebugConsoleQuickAccess } from 'vs/workbench/contrib/debug/browser/debu const debugCategory = nls.localize('debugCategory', "Debug"); registerColors(); -registerSingleton(IDebugService, DebugService, true); +registerSingleton(IDebugService, DebugService, InstantiationType.Delayed); // Register Debug Workbench Contributions Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugStatusContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index a3fda1a7045..435d3fac617 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -9,7 +9,7 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IExtensionHostDebugService, IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug'; import { ExtensionHostDebugBroadcastChannel, ExtensionHostDebugChannelClient } from 'vs/platform/debug/common/extensionHostDebugIpc'; import { IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/window/common/window'; @@ -172,4 +172,4 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i } } -registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService, true); +registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts b/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts index 825e120e8e9..c2d36360806 100644 --- a/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts +++ b/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExperimentService, ExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -13,7 +13,7 @@ import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/browser/ex import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; -registerSingleton(IExperimentService, ExperimentService, true); +registerSingleton(IExperimentService, ExperimentService, InstantiationType.Delayed); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExperimentalPrompts, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index e356f6f316b..51e70fe0f8b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -81,7 +81,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService, InstantiationType.Eager /* Auto updates extensions */); -registerSingleton(IExtensionRecommendationNotificationService, ExtensionRecommendationNotificationService, true); +registerSingleton(IExtensionRecommendationNotificationService, ExtensionRecommendationNotificationService, InstantiationType.Delayed); registerSingleton(IExtensionRecommendationsService, ExtensionRecommendationsService, InstantiationType.Eager /* Prompts recommendations in the background */); Registry.as(OutputExtensions.OutputChannels) diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts index 4a10f305828..eeb6f4d4c6b 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts @@ -25,12 +25,12 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services import { ExtensionRecommendationNotificationServiceChannel } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc'; import { Codicon } from 'vs/base/common/codicons'; import { RemoteExtensionsInitializerContribution } from 'vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionProfileService'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsAutoProfiler'; // Singletons -registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); +registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, InstantiationType.Delayed); // Running Extensions Editor Registry.as(EditorExtensions.EditorPane).registerEditorPane( diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index b6ab06c8e97..d51f8cae859 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -22,7 +22,7 @@ import { ExplorerViewletViewsContribution } from 'vs/workbench/contrib/files/bro import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { ILabelService } from 'vs/platform/label/common/label'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExplorerService, UNDO_REDO_SOURCE } from 'vs/workbench/contrib/files/browser/explorerService'; import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/encoding'; import { Schemas } from 'vs/base/common/network'; @@ -53,7 +53,7 @@ class FileUriLabelContribution implements IWorkbenchContribution { } } -registerSingleton(IExplorerService, ExplorerService, true); +registerSingleton(IExplorerService, ExplorerService, InstantiationType.Delayed); // Register file editors Registry.as(EditorExtensions.EditorPane).registerEditorPane( diff --git a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts index 61a4bd29e40..dd60e5122aa 100644 --- a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ICommandAction } from 'vs/platform/action/common/action'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -106,4 +106,4 @@ CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { return nls.localize('statusUnsupported', "The --status argument is not yet supported in browsers."); }); -registerSingleton(IWorkbenchIssueService, WebIssueService, true); +registerSingleton(IWorkbenchIssueService, WebIssueService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts index de4f64639c2..10c981ce6c8 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts @@ -9,7 +9,7 @@ import { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/commo import { ICommandAction } from 'vs/platform/action/common/action'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer, StopTracing } from 'vs/workbench/contrib/issue/electron-sandbox/issueActions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; import { WorkbenchIssueService } from 'vs/workbench/services/issue/electron-sandbox/issueService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -105,7 +105,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { registerAction2(OpenProcessExplorer); registerAction2(StopTracing); -registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, true); +registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, InstantiationType.Delayed); CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { return accessor.get(IIssueService).getSystemStatus(); diff --git a/src/vs/workbench/contrib/localization/browser/localization.contribution.ts b/src/vs/workbench/contrib/localization/browser/localization.contribution.ts index 85716e8bcb9..e529fd5414d 100644 --- a/src/vs/workbench/contrib/localization/browser/localization.contribution.ts +++ b/src/vs/workbench/contrib/localization/browser/localization.contribution.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { registerAction2 } from 'vs/platform/actions/common/actions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { WebLocaleService } from 'vs/workbench/contrib/localization/browser/localeService'; import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions'; import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale'; -registerSingleton(ILocaleService, WebLocaleService, true); +registerSingleton(ILocaleService, WebLocaleService, InstantiationType.Delayed); // Register action to configure locale and related settings registerAction2(ConfigureDisplayLanguageAction); diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts index e23d92dddcc..72cf5f2f9f5 100644 --- a/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts +++ b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts @@ -25,11 +25,11 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { ViewContainerLocation } from 'vs/workbench/common/views'; import { registerAction2 } from 'vs/platform/actions/common/actions'; import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale'; import { NativeLocaleService } from 'vs/workbench/contrib/localization/electron-sandbox/localeService'; -registerSingleton(ILocaleService, NativeLocaleService, true); +registerSingleton(ILocaleService, NativeLocaleService, InstantiationType.Delayed); // Register action to configure locale and related settings registerAction2(ConfigureDisplayLanguageAction); diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 67c3e64ecbe..3ce47b6f33f 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -17,7 +17,7 @@ import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/s import * as nls from 'vs/nls'; import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -699,14 +699,14 @@ workbenchContributionsRegistry.registerWorkbenchContribution(ComplexNotebookWork registerSingleton(INotebookService, NotebookService, false); registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, false); -registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServiceImpl, true); -registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, true); -registerSingleton(INotebookEditorService, NotebookEditorWidgetService, true); -registerSingleton(INotebookKernelService, NotebookKernelService, true); -registerSingleton(INotebookExecutionService, NotebookExecutionService, true); -registerSingleton(INotebookExecutionStateService, NotebookExecutionStateService, true); -registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, true); -registerSingleton(INotebookKeymapService, NotebookKeymapService, true); +registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServiceImpl, InstantiationType.Delayed); +registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, InstantiationType.Delayed); +registerSingleton(INotebookEditorService, NotebookEditorWidgetService, InstantiationType.Delayed); +registerSingleton(INotebookKernelService, NotebookKernelService, InstantiationType.Delayed); +registerSingleton(INotebookExecutionService, NotebookExecutionService, InstantiationType.Delayed); +registerSingleton(INotebookExecutionStateService, NotebookExecutionStateService, InstantiationType.Delayed); +registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, InstantiationType.Delayed); +registerSingleton(INotebookKeymapService, NotebookKeymapService, InstantiationType.Delayed); const schemas: IJSONSchemaMap = {}; function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema }): x is IConfigurationPropertySchema { diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 090aff78b69..96e1254736d 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -10,7 +10,7 @@ import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { ModesRegistry } from 'vs/editor/common/languages/modesRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { OutputService, LogContentProvider } from 'vs/workbench/contrib/output/browser/outputServices'; import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, LOG_MODE_ID, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK, IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output'; import { OutputViewPane } from 'vs/workbench/contrib/output/browser/outputView'; @@ -34,7 +34,7 @@ import { CATEGORIES } from 'vs/workbench/common/actions'; import { EditorExtensions } from 'vs/workbench/common/editor'; // Register Service -registerSingleton(IOutputService, OutputService, true); +registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); // Register Output Mode ModesRegistry.registerLanguage({ diff --git a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts index b2cf6ad39d3..3c562328b0c 100644 --- a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts +++ b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IFileService } from 'vs/platform/files/common/files'; @@ -57,4 +57,4 @@ export class OutputChannelModelService extends AbstractOutputChannelModelService } } -registerSingleton(IOutputChannelModelService, OutputChannelModelService, true); +registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts b/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts index 211a3e73d83..db0b6be79de 100644 --- a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts +++ b/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { toLocalISOString } from 'vs/base/common/date'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { AbstractOutputChannelModelService, IOutputChannelModelService } from 'vs/workbench/contrib/output/common/outputChannelModelService'; @@ -26,4 +26,4 @@ export class OutputChannelModelService extends AbstractOutputChannelModelService } -registerSingleton(IOutputChannelModelService, OutputChannelModelService, true); +registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts index 2c59b8bfc44..809fefe402c 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts @@ -25,7 +25,7 @@ import { nullRange } from 'vs/workbench/services/preferences/common/preferencesM import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStringDictionary } from 'vs/base/common/collections'; import { IProductService } from 'vs/platform/product/common/productService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export interface IEndpointDetails { urlBase?: string; @@ -607,4 +607,4 @@ export class SettingMatches { } } -registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); +registerSingleton(IPreferencesSearchService, PreferencesSearchService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 69dfa264dad..b2353ef9da5 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -16,7 +16,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { SCMService } from 'vs/workbench/contrib/scm/common/scmService'; import { IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views'; import { SCMViewPaneContainer } from 'vs/workbench/contrib/scm/browser/scmViewPaneContainer'; @@ -383,5 +383,5 @@ MenuRegistry.appendMenuItem(MenuId.SCMSourceControl, { when: ContextKeyExpr.equals('scmProviderHasRootUri', true) }); -registerSingleton(ISCMService, SCMService, true); -registerSingleton(ISCMViewService, SCMViewService, true); +registerSingleton(ISCMService, SCMService, InstantiationType.Delayed); +registerSingleton(ISCMViewService, SCMViewService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/search/browser/replaceContributions.ts b/src/vs/workbench/contrib/search/browser/replaceContributions.ts index 3c32a737f8b..42176f2aeec 100644 --- a/src/vs/workbench/contrib/search/browser/replaceContributions.ts +++ b/src/vs/workbench/contrib/search/browser/replaceContributions.ts @@ -2,7 +2,7 @@ * 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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IReplaceService } from 'vs/workbench/contrib/search/common/replace'; import { ReplaceService, ReplacePreviewContentProvider } from 'vs/workbench/contrib/search/browser/replaceService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -10,6 +10,6 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; export function registerContributions(): void { - registerSingleton(IReplaceService, ReplaceService, true); + registerSingleton(IReplaceService, ReplaceService, InstantiationType.Delayed); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ReplacePreviewContentProvider, LifecyclePhase.Starting); } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 4d0dd55a919..6762eea280e 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -20,7 +20,7 @@ import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurati import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IFileService } from 'vs/platform/files/common/files'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService, WorkbenchListFocusContextKey, WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; @@ -57,8 +57,8 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { ISearchConfiguration, SearchSortOrder, SEARCH_EXCLUDE_CONFIG, VIEWLET_ID, ViewMode, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { Extensions, IConfigurationMigrationRegistry } from 'vs/workbench/common/configuration'; -registerSingleton(ISearchWorkbenchService, SearchWorkbenchService, true); -registerSingleton(ISearchHistoryService, SearchHistoryService, true); +registerSingleton(ISearchWorkbenchService, SearchWorkbenchService, InstantiationType.Delayed); +registerSingleton(ISearchHistoryService, SearchHistoryService, InstantiationType.Delayed); replaceContributions(); searchWidgetContributions(); diff --git a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts index 4da8e2b191d..cb5aa0de617 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts @@ -7,7 +7,7 @@ import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { registerAction2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import * as JSONContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; @@ -25,7 +25,7 @@ import 'vs/workbench/contrib/snippets/browser/tabCompletion'; import { editorConfigurationBaseNode } from 'vs/editor/common/config/editorConfigurationSchema'; // service -registerSingleton(ISnippetsService, SnippetsService, true); +registerSingleton(ISnippetsService, SnippetsService, InstantiationType.Delayed); // actions registerAction2(InsertSnippetAction); diff --git a/src/vs/workbench/contrib/splash/browser/splash.contribution.ts b/src/vs/workbench/contrib/splash/browser/splash.contribution.ts index a037c8fa2a2..a6b4093aed9 100644 --- a/src/vs/workbench/contrib/splash/browser/splash.contribution.ts +++ b/src/vs/workbench/contrib/splash/browser/splash.contribution.ts @@ -7,7 +7,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { ISplashStorageService } from 'vs/workbench/contrib/splash/browser/splash'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { PartsSplash } from 'vs/workbench/contrib/splash/browser/partsSplash'; import { IPartsSplash } from 'vs/platform/theme/common/themeService'; @@ -18,7 +18,7 @@ registerSingleton(ISplashStorageService, class SplashStorageService implements I const raw = JSON.stringify(splash); localStorage.setItem('monaco-parts-splash', raw); } -}, true); +}, InstantiationType.Delayed); Registry.as(Extensions.Workbench).registerWorkbenchContribution( PartsSplash, diff --git a/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts b/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts index 64bfeb23c2e..a2a88ad20e5 100644 --- a/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-sandbox/splash.contribution.ts @@ -8,7 +8,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { ISplashStorageService } from 'vs/workbench/contrib/splash/browser/splash'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { PartsSplash } from 'vs/workbench/contrib/splash/browser/partsSplash'; import { IPartsSplash } from 'vs/platform/theme/common/themeService'; @@ -21,7 +21,7 @@ class SplashStorageService implements ISplashStorageService { } } -registerSingleton(ISplashStorageService, SplashStorageService, true); +registerSingleton(ISplashStorageService, SplashStorageService, InstantiationType.Delayed); Registry.as(Extensions.Workbench).registerWorkbenchContribution( PartsSplash, diff --git a/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts index 0fbc6faa520..a955a05b091 100644 --- a/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts +++ b/src/vs/workbench/contrib/tags/browser/workspaceTagsService.ts @@ -5,7 +5,7 @@ import { WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkspaceTagsService, Tags } from 'vs/workbench/contrib/tags/common/workspaceTags'; export class NoOpWorkspaceTagsService implements IWorkspaceTagsService { @@ -25,4 +25,4 @@ export class NoOpWorkspaceTagsService implements IWorkspaceTagsService { } } -registerSingleton(IWorkspaceTagsService, NoOpWorkspaceTagsService, true); +registerSingleton(IWorkspaceTagsService, NoOpWorkspaceTagsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts index 603020d57eb..6859b738e2a 100644 --- a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts +++ b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts @@ -10,7 +10,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkspaceTagsService, Tags } from 'vs/workbench/contrib/tags/common/workspaceTags'; import { getHashedRemotesFromConfig } from 'vs/workbench/contrib/tags/electron-sandbox/workspaceTags'; import { splitLines } from 'vs/base/common/strings'; @@ -812,4 +812,4 @@ export class WorkspaceTagsService implements IWorkspaceTagsService { } } -registerSingleton(IWorkspaceTagsService, WorkspaceTagsService, true); +registerSingleton(IWorkspaceTagsService, WorkspaceTagsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/tasks/browser/taskService.ts b/src/vs/workbench/contrib/tasks/browser/taskService.ts index 75fac4be22a..2107166b2ce 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskService.ts @@ -9,7 +9,7 @@ import { ITaskSystem } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { ExecutionEngine } from 'vs/workbench/contrib/tasks/common/tasks'; import { AbstractTaskService, IWorkspaceFolderConfigurationResult } from 'vs/workbench/contrib/tasks/browser/abstractTaskService'; import { ITaskFilter, ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class TaskService extends AbstractTaskService { private static readonly ProcessTaskSystemSupportMessage = nls.localize('taskService.processTaskSystem', 'Process task system is not support in the web.'); @@ -44,4 +44,4 @@ export class TaskService extends AbstractTaskService { } } -registerSingleton(ITaskService, TaskService, true); +registerSingleton(ITaskService, TaskService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts index 5ae81823bcf..76f88556c89 100644 --- a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts +++ b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts @@ -11,7 +11,7 @@ import { ExecutionEngine } from 'vs/workbench/contrib/tasks/common/tasks'; import * as TaskConfig from '../common/taskConfiguration'; import { AbstractTaskService } from 'vs/workbench/contrib/tasks/browser/abstractTaskService'; import { ITaskFilter, ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { TerminalTaskSystem } from 'vs/workbench/contrib/tasks/browser/terminalTaskSystem'; import { IConfirmationResult, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { TerminateResponseCode } from 'vs/base/common/processes'; @@ -227,4 +227,4 @@ export class TaskService extends AbstractTaskService { } } -registerSingleton(ITaskService, TaskService, true); +registerSingleton(ITaskService, TaskService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 1d59a6cface..b8f232c2ee4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -23,7 +23,7 @@ import { TERMINAL_VIEW_ID, TerminalCommandId, ITerminalProfileService } from 'vs import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands'; import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ITerminalEditorService, ITerminalGroupService, ITerminalInstanceService, ITerminalService, TerminalDataTransfers, terminalEditorId } from 'vs/workbench/contrib/terminal/browser/terminal'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; @@ -54,11 +54,11 @@ import { TerminalMainContribution } from 'vs/workbench/contrib/terminal/browser/ import { Schemas } from 'vs/base/common/network'; // Register services -registerSingleton(ITerminalService, TerminalService, true); -registerSingleton(ITerminalEditorService, TerminalEditorService, true); -registerSingleton(ITerminalGroupService, TerminalGroupService, true); -registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); -registerSingleton(ITerminalProfileService, TerminalProfileService, true); +registerSingleton(ITerminalService, TerminalService, InstantiationType.Delayed); +registerSingleton(ITerminalEditorService, TerminalEditorService, InstantiationType.Delayed); +registerSingleton(ITerminalGroupService, TerminalGroupService, InstantiationType.Delayed); +registerSingleton(ITerminalInstanceService, TerminalInstanceService, InstantiationType.Delayed); +registerSingleton(ITerminalProfileService, TerminalProfileService, InstantiationType.Delayed); // Register quick accesses const quickAccessRegistry = (Registry.as(QuickAccessExtensions.Quickaccess)); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts index 6818669dbe7..ba94df376a0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts @@ -6,11 +6,11 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ITerminalProfileResolverService, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { BrowserTerminalProfileResolverService } from 'vs/workbench/contrib/terminal/browser/terminalProfileResolverService'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; -registerSingleton(ITerminalProfileResolverService, BrowserTerminalProfileResolverService, true); +registerSingleton(ITerminalProfileResolverService, BrowserTerminalProfileResolverService, InstantiationType.Delayed); // Register standard external terminal keybinding as integrated terminal when in web as the // external terminal is not available diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index 66b8abe772a..0ee01518589 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITerminalInstance, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; import { IShellLaunchConfig, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -90,4 +90,4 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst } } -registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); +registerSingleton(ITerminalInstanceService, TerminalInstanceService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts b/src/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts index 7fd4e951754..3897ed68693 100644 --- a/src/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts +++ b/src/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { EnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariableService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -registerSingleton(IEnvironmentVariableService, EnvironmentVariableService, true); +registerSingleton(IEnvironmentVariableService, EnvironmentVariableService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts index d3d2e293eb3..a705e6fc45f 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ITerminalContributionService, TerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; -registerSingleton(ITerminalContributionService, TerminalContributionService, true); +registerSingleton(ITerminalContributionService, TerminalContributionService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts index 1752c735948..b47d5943150 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; import { Registry } from 'vs/platform/registry/common/platform'; import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; @@ -17,7 +17,7 @@ import { LocalTerminalBackendContribution } from 'vs/workbench/contrib/terminal/ // Register services registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty); -registerSingleton(ITerminalProfileResolverService, ElectronTerminalProfileResolverService, true); +registerSingleton(ITerminalProfileResolverService, ElectronTerminalProfileResolverService, InstantiationType.Delayed); // Register workbench contributions const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index f6580294960..828affe2faf 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -11,7 +11,7 @@ import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'v import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IFileService } from 'vs/platform/files/common/files'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -44,15 +44,15 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { allTestActions, discoverAndRunTests } from './testExplorerActions'; import './testingConfigurationUi'; -registerSingleton(ITestService, TestService, true); -registerSingleton(ITestResultStorage, TestResultStorage, true); -registerSingleton(ITestProfileService, TestProfileService, true); -registerSingleton(ITestResultService, TestResultService, true); -registerSingleton(ITestExplorerFilterState, TestExplorerFilterState, true); -registerSingleton(ITestingOutputTerminalService, TestingOutputTerminalService, true); -registerSingleton(ITestingPeekOpener, TestingPeekOpener, true); -registerSingleton(ITestingProgressUiService, TestingProgressUiService, true); -registerSingleton(ITestingDecorationsService, TestingDecorationService, true); +registerSingleton(ITestService, TestService, InstantiationType.Delayed); +registerSingleton(ITestResultStorage, TestResultStorage, InstantiationType.Delayed); +registerSingleton(ITestProfileService, TestProfileService, InstantiationType.Delayed); +registerSingleton(ITestResultService, TestResultService, InstantiationType.Delayed); +registerSingleton(ITestExplorerFilterState, TestExplorerFilterState, InstantiationType.Delayed); +registerSingleton(ITestingOutputTerminalService, TestingOutputTerminalService, InstantiationType.Delayed); +registerSingleton(ITestingPeekOpener, TestingPeekOpener, InstantiationType.Delayed); +registerSingleton(ITestingProgressUiService, TestingProgressUiService, InstantiationType.Delayed); +registerSingleton(ITestingDecorationsService, TestingDecorationService, InstantiationType.Delayed); const viewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ id: Testing.ViewletId, diff --git a/src/vs/workbench/contrib/timeline/browser/timeline.contribution.ts b/src/vs/workbench/contrib/timeline/browser/timeline.contribution.ts index 8aae19bc264..f04d0d41651 100644 --- a/src/vs/workbench/contrib/timeline/browser/timeline.contribution.ts +++ b/src/vs/workbench/contrib/timeline/browser/timeline.contribution.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IViewsRegistry, IViewDescriptor, Extensions as ViewExtensions } from 'vs/workbench/common/views'; import { VIEW_CONTAINER } from 'vs/workbench/contrib/files/browser/explorerViewlet'; @@ -99,4 +99,4 @@ MenuRegistry.appendMenuItem(MenuId.TimelineTitle, { icon: timelineFilter }); -registerSingleton(ITimelineService, TimelineService, true); +registerSingleton(ITimelineService, TimelineService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/webview/browser/webview.web.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.web.contribution.ts index 2b1bb413023..9ac2a8ce935 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.web.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.web.contribution.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewService } from './webviewService'; -registerSingleton(IWebviewService, WebviewService, true); +registerSingleton(IWebviewService, WebviewService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts index 97ca0f24cdc..a19e67cf9c5 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/webview.contribution.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { registerAction2 } from 'vs/platform/actions/common/actions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import * as webviewCommands from 'vs/workbench/contrib/webview/electron-sandbox/webviewCommands'; import { ElectronWebviewService } from 'vs/workbench/contrib/webview/electron-sandbox/webviewService'; -registerSingleton(IWebviewService, ElectronWebviewService, true); +registerSingleton(IWebviewService, ElectronWebviewService, InstantiationType.Delayed); registerAction2(webviewCommands.OpenWebviewDeveloperToolsAction); diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts index 9b9f5741211..8d49c0221a1 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { registerAction2 } from 'vs/platform/actions/common/actions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; @@ -88,7 +88,7 @@ Registry.as(EditorExtensions.EditorFactory).registerEdit WebviewEditorInputSerializer.ID, WebviewEditorInputSerializer); -registerSingleton(IWebviewWorkbenchService, WebviewEditorService, true); +registerSingleton(IWebviewWorkbenchService, WebviewEditorService, InstantiationType.Delayed); registerAction2(ShowWebViewEditorFindWidgetAction); registerAction2(HideWebViewEditorFindCommand); diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts b/src/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts index 9dd05114160..91d7abcc1da 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWebviewViewService, WebviewViewService } from 'vs/workbench/contrib/webviewView/browser/webviewViewService'; -registerSingleton(IWebviewViewService, WebviewViewService, true); +registerSingleton(IWebviewViewService, WebviewViewService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts index d0b2d601f17..63ceca1e990 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts @@ -24,7 +24,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILink, LinkedText, parseLinkedText } from 'vs/base/common/linkedText'; import { walkthroughsExtensionPoint } from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedExtensionPoint'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { dirname } from 'vs/base/common/path'; import { coalesce, flatten } from 'vs/base/common/arrays'; import { IViewsService } from 'vs/workbench/common/views'; @@ -716,4 +716,4 @@ registerAction2(class extends Action2 { } }); -registerSingleton(IWalkthroughsService, WalkthroughsService, true); +registerSingleton(IWalkthroughsService, WalkthroughsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts index a7d574ca562..975240757c0 100644 --- a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts @@ -10,7 +10,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { AccessibilityService } from 'vs/platform/accessibility/browser/accessibilityService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -67,7 +67,7 @@ export class NativeAccessibilityService extends AccessibilityService implements } } -registerSingleton(IAccessibilityService, NativeAccessibilityService, true); +registerSingleton(IAccessibilityService, NativeAccessibilityService, InstantiationType.Delayed); // On linux we do not automatically detect that a screen reader is detected, thus we have to implicitly notify the renderer to enable accessibility when user configures it in settings class LinuxAccessibilityContribution implements IWorkbenchContribution { diff --git a/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts index 1d12dc5ffd6..77a8841dcb5 100644 --- a/src/vs/workbench/services/activity/browser/activityService.ts +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -5,7 +5,7 @@ import { IActivityService, IActivity } from 'vs/workbench/services/activity/common/activity'; import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; import { GLOBAL_ACTIVITY_ID, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity'; import { Event } from 'vs/base/common/event'; @@ -113,4 +113,4 @@ export class ActivityService implements IActivityService { } } -registerSingleton(IActivityService, ActivityService, true); +registerSingleton(IActivityService, ActivityService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/assignment/common/assignmentService.ts b/src/vs/workbench/services/assignment/common/assignmentService.ts index 93008a87c07..d3d939253f3 100644 --- a/src/vs/workbench/services/assignment/common/assignmentService.ts +++ b/src/vs/workbench/services/assignment/common/assignmentService.ts @@ -9,7 +9,7 @@ import { MementoObject, Memento } from 'vs/workbench/common/memento'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryData } from 'vs/base/common/actions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProductService } from 'vs/platform/product/common/productService'; import { IAssignmentService } from 'vs/platform/assignment/common/assignment'; @@ -131,4 +131,4 @@ export class WorkbenchAssignmentService extends BaseAssignmentService { } } -registerSingleton(IWorkbenchAssignmentService, WorkbenchAssignmentService, true); +registerSingleton(IWorkbenchAssignmentService, WorkbenchAssignmentService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/clipboard/browser/clipboardService.ts b/src/vs/workbench/services/clipboard/browser/clipboardService.ts index a59960511a7..21ecf79467e 100644 --- a/src/vs/workbench/services/clipboard/browser/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/browser/clipboardService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { BrowserClipboardService as BaseBrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -68,4 +68,4 @@ export class BrowserClipboardService extends BaseBrowserClipboardService { } } -registerSingleton(IClipboardService, BrowserClipboardService, true); +registerSingleton(IClipboardService, BrowserClipboardService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts b/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts index 326d09c3a37..43443e6cdc5 100644 --- a/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts @@ -6,7 +6,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { URI } from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -78,4 +78,4 @@ export class NativeClipboardService implements IClipboardService { } } -registerSingleton(IClipboardService, NativeClipboardService, true); +registerSingleton(IClipboardService, NativeClipboardService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts index 85faaa2fb3d..8a719346c3f 100644 --- a/src/vs/workbench/services/commands/common/commandService.ts +++ b/src/vs/workbench/services/commands/common/commandService.ts @@ -9,7 +9,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { timeout } from 'vs/base/common/async'; export class CommandService extends Disposable implements ICommandService { @@ -101,4 +101,4 @@ export class CommandService extends Disposable implements ICommandService { } } -registerSingleton(ICommandService, CommandService, true); +registerSingleton(ICommandService, CommandService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index 5251efc25b5..e906a376240 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -18,7 +18,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IJSONEditingService, IJSONValue, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ITextModel } from 'vs/editor/common/model'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class JSONEditingService implements IJSONEditingService { @@ -140,4 +140,4 @@ export class JSONEditingService implements IJSONEditingService { } } -registerSingleton(IJSONEditingService, JSONEditingService, true); +registerSingleton(IJSONEditingService, JSONEditingService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index 4a7d00a5b4d..70f5d1cd368 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -5,7 +5,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -33,4 +33,4 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi } } -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts index 14a385e3e06..bb1a8751e6d 100644 --- a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts @@ -10,7 +10,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; 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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; 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'; @@ -43,4 +43,4 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi } } -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index f70812f2e09..4433a8b533f 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -20,7 +20,7 @@ import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextMenuMenuDelegate, ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { stripIcons } from 'vs/base/common/iconLabels'; import { coalesce } from 'vs/base/common/arrays'; import { Event, Emitter } from 'vs/base/common/event'; @@ -259,4 +259,4 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } } -registerSingleton(IContextMenuService, ContextMenuService, true); +registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 42a7850a675..b8d5d9491ad 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -16,7 +16,7 @@ import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; import { isCancellationError } from 'vs/base/common/errors'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { hash } from 'vs/base/common/hash'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { asArray, distinct } from 'vs/base/common/arrays'; @@ -408,4 +408,4 @@ export class DecorationsService implements IDecorationsService { } } -registerSingleton(IDecorationsService, DecorationsService, true); +registerSingleton(IDecorationsService, DecorationsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 87f6e2ca052..68aab5fc304 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -5,7 +5,7 @@ import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, FileFilter } from 'vs/platform/dialogs/common/dialogs'; import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractFileDialogService } from 'vs/workbench/services/dialogs/browser/abstractFileDialogService'; import { Schemas } from 'vs/base/common/network'; import { memoize } from 'vs/base/common/decorators'; @@ -270,4 +270,4 @@ export class FileDialogService extends AbstractFileDialogService implements IFil } } -registerSingleton(IFileDialogService, FileDialogService, true); +registerSingleton(IFileDialogService, FileDialogService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/dialogs/common/dialogService.ts b/src/vs/workbench/services/dialogs/common/dialogService.ts index 7360fe7d875..13da7563bae 100644 --- a/src/vs/workbench/services/dialogs/common/dialogService.ts +++ b/src/vs/workbench/services/dialogs/common/dialogService.ts @@ -7,7 +7,7 @@ import Severity from 'vs/base/common/severity'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService, IInput, IInputResult, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { DialogsModel } from 'vs/workbench/common/dialogs'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ILogService } from 'vs/platform/log/common/log'; @@ -78,4 +78,4 @@ export class DialogService extends Disposable implements IDialogService { } } -registerSingleton(IDialogService, DialogService, true); +registerSingleton(IDialogService, DialogService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts index 36f7e3e76a1..bfbc3211a7f 100644 --- a/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts @@ -12,7 +12,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; @@ -200,4 +200,4 @@ export class FileDialogService extends AbstractFileDialogService implements IFil } } -registerSingleton(IFileDialogService, FileDialogService, true); +registerSingleton(IFileDialogService, FileDialogService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/editor/browser/codeEditorService.ts b/src/vs/workbench/services/editor/browser/codeEditorService.ts index 492e5077def..657f203312c 100644 --- a/src/vs/workbench/services/editor/browser/codeEditorService.ts +++ b/src/vs/workbench/services/editor/browser/codeEditorService.ts @@ -11,7 +11,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { isEqual } from 'vs/base/common/resources'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; @@ -113,4 +113,4 @@ export class CodeEditorService extends AbstractCodeEditorService { } } -registerSingleton(ICodeEditorService, CodeEditorService, true); +registerSingleton(ICodeEditorService, CodeEditorService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/encryption/browser/encryptionService.ts b/src/vs/workbench/services/encryption/browser/encryptionService.ts index e204f45bd49..8e745e85578 100644 --- a/src/vs/workbench/services/encryption/browser/encryptionService.ts +++ b/src/vs/workbench/services/encryption/browser/encryptionService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IEncryptionService } from 'vs/workbench/services/encryption/common/encryptionService'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -35,4 +35,4 @@ export class EncryptionService implements IEncryptionService { } } -registerSingleton(IEncryptionService, EncryptionService, true); +registerSingleton(IEncryptionService, EncryptionService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts index cee48fc8657..71ac3a7fbe6 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts @@ -6,7 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export const IShellEnvironmentService = createDecorator('shellEnvironmentService'); @@ -26,4 +26,4 @@ export class ShellEnvironmentService implements IShellEnvironmentService { } } -registerSingleton(IShellEnvironmentService, ShellEnvironmentService, true); +registerSingleton(IShellEnvironmentService, ShellEnvironmentService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts index 7fd4e622342..e614f82d01b 100644 --- a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts @@ -7,7 +7,7 @@ import { IBuiltinExtensionsScannerService, ExtensionType, IExtensionManifest, Ta import { isWeb, Language } from 'vs/base/common/platform'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { FileAccess } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; @@ -113,4 +113,4 @@ export class BuiltinExtensionsScannerService implements IBuiltinExtensionsScanne } } -registerSingleton(IBuiltinExtensionsScannerService, BuiltinExtensionsScannerService, true); +registerSingleton(IBuiltinExtensionsScannerService, BuiltinExtensionsScannerService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index ad8c116d0b3..3db527d7d97 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { IExtensionManagementService, IGlobalExtensionEnablementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ExtensionType, IExtension, isResolverExtension } from 'vs/platform/extensions/common/extensions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -161,7 +161,7 @@ class ExtensionBisectService implements IExtensionBisectService { } } -registerSingleton(IExtensionBisectService, ExtensionBisectService, true); +registerSingleton(IExtensionBisectService, ExtensionBisectService, InstantiationType.Delayed); // --- bisect UI diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index ee5d1794a65..94369a63ef3 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -14,7 +14,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtension, isAuthenticationProviderExtension, isLanguagePackExtension, isResolverExtension } from 'vs/platform/extensions/common/extensions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { StorageManager } from 'vs/platform/extensionManagement/common/extensionEnablementService'; import { webWorkerExtHostConfig, WebWorkerExtHostConfigValue } from 'vs/workbench/services/extensions/common/extensions'; import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount'; @@ -716,4 +716,4 @@ class ExtensionsManager extends Disposable { } } -registerSingleton(IWorkbenchExtensionEnablementService, ExtensionEnablementService, true); +registerSingleton(IWorkbenchExtensionEnablementService, ExtensionEnablementService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index 34432033ea5..bbe1bd7cb86 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -7,7 +7,7 @@ import { IBuiltinExtensionsScannerService, ExtensionType, IExtensionIdentifier, import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { IScannedExtension, IWebExtensionsScannerService, ScanOptions } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { isWeb, Language } from 'vs/base/common/platform'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; @@ -887,4 +887,4 @@ if (isWeb) { }); } -registerSingleton(IWebExtensionsScannerService, WebExtensionsScannerService, true); +registerSingleton(IWebExtensionsScannerService, WebExtensionsScannerService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts index 4db3f9b85cc..198844be7de 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -9,7 +9,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA import { Schemas } from 'vs/base/common/network'; import { Event } from 'vs/base/common/event'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { isWeb } from 'vs/base/common/platform'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -71,4 +71,4 @@ export class ExtensionManagementServerService implements IExtensionManagementSer } } -registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService, true); +registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts index 9c920ab4057..d539186ddb6 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts @@ -9,7 +9,7 @@ import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagem import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { NativeRemoteExtensionManagementService } from 'vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService'; import { ILabelService } from 'vs/platform/label/common/label'; import { IExtension } from 'vs/platform/extensions/common/extensions'; @@ -66,4 +66,4 @@ export class ExtensionManagementServerService extends Disposable implements IExt } } -registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService, true); +registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts index 54ad833ec8b..21033abfbe8 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts @@ -7,7 +7,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { ILocalExtension, IExtensionGalleryService, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { ExtensionManagementService as BaseExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionManagementServer, IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { Schemas } from 'vs/base/common/network'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -53,4 +53,4 @@ export class ExtensionManagementService extends BaseExtensionManagementService { } } -registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, true); +registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts index e99f8822f0a..fa12c6b9d13 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IExtensionTipsService, IExecutableBasedExtensionTip, IWorkspaceTips, IConfigBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -53,4 +53,4 @@ class NativeExtensionTipsService extends ExtensionTipsService implements IExtens } -registerSingleton(IExtensionTipsService, NativeExtensionTipsService, true); +registerSingleton(IExtensionTipsService, NativeExtensionTipsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts b/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts index bed9c346aee..1c4b365f2d2 100644 --- a/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts +++ b/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts @@ -6,7 +6,7 @@ import { distinct } from 'vs/base/common/arrays'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IExtensionIgnoredRecommendationsService, IgnoredRecommendationChangeNotification } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; import { IWorkspaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig'; @@ -108,4 +108,4 @@ export class ExtensionIgnoredRecommendationsService extends Disposable implement } -registerSingleton(IExtensionIgnoredRecommendationsService, ExtensionIgnoredRecommendationsService, true); +registerSingleton(IExtensionIgnoredRecommendationsService, ExtensionIgnoredRecommendationsService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts b/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts index e2495875344..4fe17405e22 100644 --- a/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts +++ b/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts @@ -9,7 +9,7 @@ import { parse } from 'vs/base/common/json'; import { Disposable } from 'vs/base/common/lifecycle'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import { FileKind, IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { isWorkspace, IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; @@ -266,4 +266,4 @@ export class WorkspaceExtensionsConfigService extends Disposable implements IWor } -registerSingleton(IWorkspaceExtensionsConfigService, WorkspaceExtensionsConfigService, true); +registerSingleton(IWorkspaceExtensionsConfigService, WorkspaceExtensionsConfigService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts index de8912cf33d..897d54766fb 100644 --- a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { FileAccess, Schemas } from 'vs/base/common/network'; @@ -52,4 +52,4 @@ class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderServ } } -registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService, true); +registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts index 3b30c2dc1f3..c3db91f3a38 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -39,4 +39,4 @@ export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoa } -registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService, true); +registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts index efaeb062e84..63c348cc399 100644 --- a/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts +++ b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts @@ -11,7 +11,7 @@ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/ex import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IProductService } from 'vs/platform/product/common/productService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionUntrustedWorkspaceSupport } from 'vs/base/common/product'; import { Disposable } from 'vs/base/common/lifecycle'; import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; @@ -371,4 +371,4 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE } } -registerSingleton(IExtensionManifestPropertiesService, ExtensionManifestPropertiesService, true); +registerSingleton(IExtensionManifestPropertiesService, ExtensionManifestPropertiesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/files/browser/elevatedFileService.ts b/src/vs/workbench/services/files/browser/elevatedFileService.ts index 7c2eef326fc..3e950a0f417 100644 --- a/src/vs/workbench/services/files/browser/elevatedFileService.ts +++ b/src/vs/workbench/services/files/browser/elevatedFileService.ts @@ -6,7 +6,7 @@ import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer'; import { URI } from 'vs/base/common/uri'; import { IFileStatWithMetadata, IWriteFileOptions } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService'; export class BrowserElevatedFileService implements IElevatedFileService { @@ -25,4 +25,4 @@ export class BrowserElevatedFileService implements IElevatedFileService { } } -registerSingleton(IElevatedFileService, BrowserElevatedFileService, true); +registerSingleton(IElevatedFileService, BrowserElevatedFileService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts b/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts index 3f2ff21e4aa..189612f7115 100644 --- a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts +++ b/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts @@ -8,7 +8,7 @@ import { randomPath } from 'vs/base/common/extpath'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { IFileService, IFileStatWithMetadata, IWriteFileOptions } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService'; @@ -49,4 +49,4 @@ export class NativeElevatedFileService implements IElevatedFileService { } } -registerSingleton(IElevatedFileService, NativeElevatedFileService, true); +registerSingleton(IElevatedFileService, NativeElevatedFileService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index 63ddc762602..f17e7a256a0 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -531,4 +531,4 @@ export class BrowserHostService extends Disposable implements IHostService { //#endregion } -registerSingleton(IHostService, BrowserHostService, true); +registerSingleton(IHostService, BrowserHostService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts b/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts index 6f3f1ab1a80..f9181a1a376 100644 --- a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts +++ b/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/window/common/window'; @@ -138,5 +138,5 @@ class WorkbenchHostService extends Disposable implements IHostService { //#endregion } -registerSingleton(IHostService, WorkbenchHostService, true); -registerSingleton(INativeHostService, WorkbenchNativeHostService, true); +registerSingleton(IHostService, WorkbenchHostService, InstantiationType.Delayed); +registerSingleton(INativeHostService, WorkbenchNativeHostService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/hover/browser/hoverService.ts b/src/vs/workbench/services/hover/browser/hoverService.ts index 69f7457daa6..3a33a5ed48e 100644 --- a/src/vs/workbench/services/hover/browser/hoverService.ts +++ b/src/vs/workbench/services/hover/browser/hoverService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/hover'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorHoverBackground, editorHoverBorder, textLinkForeground, editorHoverForeground, editorHoverStatusBarBackground, textCodeBlockBackground, widgetShadow, textLinkActiveForeground, focusBorder, toolbarHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IHoverService, IHoverOptions, IHoverWidget } from 'vs/workbench/services/hover/browser/hover'; @@ -156,7 +156,7 @@ class HoverContextViewDelegate implements IDelegate { } } -registerSingleton(IHoverService, HoverService, true); +registerSingleton(IHoverService, HoverService, InstantiationType.Delayed); registerThemingParticipant((theme, collector) => { const hoverBackground = theme.getColor(editorHoverBackground); diff --git a/src/vs/workbench/services/integrity/browser/integrityService.ts b/src/vs/workbench/services/integrity/browser/integrityService.ts index f29a3dfe552..e2285f53c04 100644 --- a/src/vs/workbench/services/integrity/browser/integrityService.ts +++ b/src/vs/workbench/services/integrity/browser/integrityService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IIntegrityService, IntegrityTestResult } from 'vs/workbench/services/integrity/common/integrity'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class IntegrityService implements IIntegrityService { @@ -15,4 +15,4 @@ export class IntegrityService implements IIntegrityService { } } -registerSingleton(IIntegrityService, IntegrityService, true); +registerSingleton(IIntegrityService, IntegrityService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts index 7125f82440e..ad51e6ef946 100644 --- a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts +++ b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts @@ -11,7 +11,7 @@ import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecyc import { IProductService } from 'vs/platform/product/common/productService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { FileAccess } from 'vs/base/common/network'; import { IChecksumService } from 'vs/platform/checksum/common/checksumService'; @@ -163,4 +163,4 @@ export class IntegrityService implements IIntegrityService { } } -registerSingleton(IIntegrityService, IntegrityService, true); +registerSingleton(IIntegrityService, IntegrityService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts index 0e630dc4ce8..c83b9e0a72c 100644 --- a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { KeymapInfo, IRawMixedKeyboardMapping, IKeymapInfo } from 'vs/workbench/services/keybinding/common/keymapInfo'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { DispatchConfig } from 'vs/platform/keyboardLayout/common/dispatchConfig'; import { IKeyboardMapper, CachedKeyboardMapper } from 'vs/platform/keyboardLayout/common/keyboardMapper'; import { OS, OperatingSystem, isMacintosh, isWindows } from 'vs/base/common/platform'; @@ -618,7 +618,7 @@ export class BrowserKeyboardLayoutService extends Disposable implements IKeyboar } } -registerSingleton(IKeyboardLayoutService, BrowserKeyboardLayoutService, true); +registerSingleton(IKeyboardLayoutService, BrowserKeyboardLayoutService, InstantiationType.Delayed); // Configuration const configurationRegistry = Registry.as(ConfigExtensions.Configuration); diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index a064d35bee6..4ddcceda908 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -22,7 +22,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; export const IKeybindingEditingService = createDecorator('keybindingEditingService'); @@ -293,4 +293,4 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding } } -registerSingleton(IKeybindingEditingService, KeybindingsEditingService, true); +registerSingleton(IKeybindingEditingService, KeybindingsEditingService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index e969fc50dce..5e3e0114503 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -18,7 +18,7 @@ import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting, IFormat import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { match } from 'vs/base/common/glob'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { OperatingSystem, OS } from 'vs/base/common/platform'; @@ -455,4 +455,4 @@ export class LabelService extends Disposable implements ILabelService { } } -registerSingleton(ILabelService, LabelService, true); +registerSingleton(ILabelService, LabelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/languageStatus/common/languageStatusService.ts b/src/vs/workbench/services/languageStatus/common/languageStatusService.ts index 7f8bbc8ae19..a7a49dad0be 100644 --- a/src/vs/workbench/services/languageStatus/common/languageStatusService.ts +++ b/src/vs/workbench/services/languageStatus/common/languageStatusService.ts @@ -13,7 +13,7 @@ import { Command } from 'vs/editor/common/languages'; import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry'; import { LanguageSelector } from 'vs/editor/common/languageSelector'; import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export interface ILanguageStatus { @@ -73,4 +73,4 @@ class LanguageStatusServiceImpl implements ILanguageStatusService { } } -registerSingleton(ILanguageStatusService, LanguageStatusServiceImpl, true); +registerSingleton(ILanguageStatusService, LanguageStatusServiceImpl, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/model/common/modelService.ts b/src/vs/workbench/services/model/common/modelService.ts index e72f0272a98..7765c84da55 100644 --- a/src/vs/workbench/services/model/common/modelService.ts +++ b/src/vs/workbench/services/model/common/modelService.ts @@ -10,7 +10,7 @@ import { ModelService } from 'vs/editor/common/services/modelService'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; @@ -42,4 +42,4 @@ export class WorkbenchModelService extends ModelService { } } -registerSingleton(IModelService, WorkbenchModelService, true); +registerSingleton(IModelService, WorkbenchModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 1a768532b79..545f9104c05 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -8,7 +8,7 @@ import { INotificationService, INotification, INotificationHandle, Severity, Not import { NotificationsModel, ChoiceAction, NotificationChangeType } from 'vs/workbench/common/notifications'; import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAction, Action } from 'vs/base/common/actions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -271,4 +271,4 @@ export class NotificationService extends Disposable implements INotificationServ } } -registerSingleton(INotificationService, NotificationService, true); +registerSingleton(INotificationService, NotificationService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/outline/browser/outlineService.ts b/src/vs/workbench/services/outline/browser/outlineService.ts index fac1d91dd08..f4707432371 100644 --- a/src/vs/workbench/services/outline/browser/outlineService.ts +++ b/src/vs/workbench/services/outline/browser/outlineService.ts @@ -6,7 +6,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IEditorPane } from 'vs/workbench/common/editor'; import { IOutline, IOutlineCreator, IOutlineService, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; import { Event, Emitter } from 'vs/base/common/event'; @@ -49,4 +49,4 @@ class OutlineService implements IOutlineService { } -registerSingleton(IOutlineService, OutlineService, true); +registerSingleton(IOutlineService, OutlineService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/path/browser/pathService.ts b/src/vs/workbench/services/path/browser/pathService.ts index 215f1ec36ad..664884d60ba 100644 --- a/src/vs/workbench/services/path/browser/pathService.ts +++ b/src/vs/workbench/services/path/browser/pathService.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IPathService, AbstractPathService } from 'vs/workbench/services/path/common/pathService'; import { URI } from 'vs/base/common/uri'; @@ -57,4 +57,4 @@ function guessLocalUserHome(environmentService: IWorkbenchEnvironmentService, co }); } -registerSingleton(IPathService, BrowserPathService, true); +registerSingleton(IPathService, BrowserPathService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/path/electron-sandbox/pathService.ts b/src/vs/workbench/services/path/electron-sandbox/pathService.ts index 07159a128c5..7888fc6ab71 100644 --- a/src/vs/workbench/services/path/electron-sandbox/pathService.ts +++ b/src/vs/workbench/services/path/electron-sandbox/pathService.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IPathService, AbstractPathService } from 'vs/workbench/services/path/common/pathService'; @@ -20,4 +20,4 @@ export class NativePathService extends AbstractPathService { } } -registerSingleton(IPathService, NativePathService, true); +registerSingleton(IPathService, NativePathService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 1759898bf46..473e718663b 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -20,7 +20,7 @@ import * as nls from 'vs/nls'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions, getDefaultValue, IConfigurationRegistry, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry'; import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -605,4 +605,4 @@ export class PreferencesService extends Disposable implements IPreferencesServic } } -registerSingleton(IPreferencesService, PreferencesService, true); +registerSingleton(IPreferencesService, PreferencesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 5d95e1984f7..c3a0416f735 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -14,7 +14,7 @@ import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/ import { INotificationService, Severity, INotificationHandle } from 'vs/platform/notification/common/notification'; import { Action } from 'vs/base/common/actions'; import { Event, Emitter } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; import { attachDialogStyler } from 'vs/platform/theme/common/styler'; @@ -622,4 +622,4 @@ export class ProgressService extends Disposable implements IProgressService { } } -registerSingleton(IProgressService, ProgressService, true); +registerSingleton(IProgressService, ProgressService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/quickinput/browser/quickInputService.ts b/src/vs/workbench/services/quickinput/browser/quickInputService.ts index 891e6b6fe1b..34572df63e0 100644 --- a/src/vs/workbench/services/quickinput/browser/quickInputService.ts +++ b/src/vs/workbench/services/quickinput/browser/quickInputService.ts @@ -12,7 +12,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { QuickInputController } from 'vs/base/parts/quickinput/browser/quickInput'; import { QuickInputService as BaseQuickInputService } from 'vs/platform/quickinput/browser/quickInput'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { InQuickPickContextKey } from 'vs/workbench/browser/quickaccess'; @@ -47,4 +47,4 @@ export class QuickInputService extends BaseQuickInputService { } } -registerSingleton(IQuickInputService, QuickInputService, true); +registerSingleton(IQuickInputService, QuickInputService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index ff29e0375ca..cbc2eef9ea9 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ALL_INTERFACES_ADDRESSES, isAllInterfaces, isLocalhost, ITunnelService, LOCALHOST_ADDRESSES, PortAttributesProvider, ProvidedOnAutoForward, ProvidedPortAttributes, RemoteTunnel, TunnelPrivacyId, TunnelProtocol } from 'vs/platform/tunnel/common/tunnel'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; @@ -1015,4 +1015,4 @@ class RemoteExplorerService implements IRemoteExplorerService { } } -registerSingleton(IRemoteExplorerService, RemoteExplorerService, true); +registerSingleton(IRemoteExplorerService, RemoteExplorerService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/request/electron-sandbox/requestService.ts b/src/vs/workbench/services/request/electron-sandbox/requestService.ts index 4fb44ec4e00..2ff418a52e1 100644 --- a/src/vs/workbench/services/request/electron-sandbox/requestService.ts +++ b/src/vs/workbench/services/request/electron-sandbox/requestService.ts @@ -6,7 +6,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { RequestService } from 'vs/platform/request/browser/requestService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRequestService } from 'vs/platform/request/common/request'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; @@ -25,4 +25,4 @@ export class NativeRequestService extends RequestService { } } -registerSingleton(IRequestService, NativeRequestService, true); +registerSingleton(IRequestService, NativeRequestService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/search/browser/searchService.ts b/src/vs/workbench/services/search/browser/searchService.ts index 21bb410c03e..bea85f71a43 100644 --- a/src/vs/workbench/services/search/browser/searchService.ts +++ b/src/vs/workbench/services/search/browser/searchService.ts @@ -17,7 +17,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { IWorkerClient, logOnceWebWorkerWarning, SimpleWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { DefaultWorkerFactory } from 'vs/base/browser/defaultWorkerFactory'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILocalFileSearchSimpleWorker, ILocalFileSearchSimpleWorkerHost } from 'vs/workbench/services/search/common/localFileSearchWorkerTypes'; import { memoize } from 'vs/base/common/decorators'; import { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider'; @@ -196,4 +196,4 @@ export class LocalFileSearchWorkerClient extends Disposable implements ISearchRe } } -registerSingleton(ISearchService, RemoteSearchService, true); +registerSingleton(ISearchService, RemoteSearchService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/search/electron-sandbox/searchService.ts b/src/vs/workbench/services/search/electron-sandbox/searchService.ts index 1bb5a83da06..cf9c6c6fd91 100644 --- a/src/vs/workbench/services/search/electron-sandbox/searchService.ts +++ b/src/vs/workbench/services/search/electron-sandbox/searchService.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ISearchService } from 'vs/workbench/services/search/common/search'; import { SearchService } from 'vs/workbench/services/search/common/searchService'; -registerSingleton(ISearchService, SearchService, true); +registerSingleton(ISearchService, SearchService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index eb5de68bbb9..6d5739aed97 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IObservableValue } from 'vs/base/common/observableValue'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILoggerService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -108,4 +108,4 @@ export class TelemetryService extends Disposable implements ITelemetryService { } } -registerSingleton(ITelemetryService, TelemetryService, true); +registerSingleton(ITelemetryService, TelemetryService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts index 51bb15c57b9..7a1e6498df9 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts @@ -14,7 +14,7 @@ import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryI import { IStorageService } from 'vs/platform/storage/common/storage'; import { resolveWorkbenchCommonProperties } from 'vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties'; import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ClassifiedEvent, StrictPropertyCheck, OmitMetadata, IGDPRProperty } from 'vs/platform/telemetry/common/gdprTypings'; import { IFileService } from 'vs/platform/files/common/files'; import { IObservableValue } from 'vs/base/common/observableValue'; @@ -84,4 +84,4 @@ export class TelemetryService extends Disposable implements ITelemetryService { } } -registerSingleton(ITelemetryService, TelemetryService, true); +registerSingleton(ITelemetryService, TelemetryService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index 1c0ba078d72..e9a8f68117e 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -14,7 +14,7 @@ import { Schemas } from 'vs/base/common/network'; import { ITextModelService, ITextModelContentProvider, ITextEditorModel, IResolvedTextEditorModel, isResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { ModelUndoRedoParticipant } from 'vs/editor/common/services/modelUndoRedoParticipant'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; @@ -246,4 +246,4 @@ export class TextModelResolverService extends Disposable implements ITextModelSe } } -registerSingleton(ITextModelService, TextModelResolverService, true); +registerSingleton(ITextModelService, TextModelResolverService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts b/src/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts index 3cdfdc486cf..0118d3d4e27 100644 --- a/src/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts @@ -10,7 +10,7 @@ import { OperatingSystem, OS } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -54,4 +54,4 @@ export class TextResourcePropertiesService implements ITextResourcePropertiesSer } } -registerSingleton(ITextResourcePropertiesService, TextResourcePropertiesService, true); +registerSingleton(ITextResourcePropertiesService, TextResourcePropertiesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts b/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts index 469ada1f878..09cabf53111 100644 --- a/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts +++ b/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { addMatchMediaChangeListener } from 'vs/base/browser/browser'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; import { IHostColorSchemeService } from 'vs/workbench/services/themes/common/hostColorSchemeService'; @@ -54,4 +54,4 @@ export class BrowserHostColorSchemeService extends Disposable implements IHostCo } -registerSingleton(IHostColorSchemeService, BrowserHostColorSchemeService, true); +registerSingleton(IHostColorSchemeService, BrowserHostColorSchemeService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts b/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts index f9578f6805a..10769a87465 100644 --- a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts +++ b/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts @@ -5,7 +5,7 @@ import { Emitter } from 'vs/base/common/event'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; import { IHostColorSchemeService } from 'vs/workbench/services/themes/common/hostColorSchemeService'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; @@ -70,4 +70,4 @@ export class NativeHostColorSchemeService extends Disposable implements IHostCol } -registerSingleton(IHostColorSchemeService, NativeHostColorSchemeService, true); +registerSingleton(IHostColorSchemeService, NativeHostColorSchemeService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts index 2a778a46ca8..7f54ca6ea75 100644 --- a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts +++ b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts @@ -14,7 +14,7 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib import { IStartupMetrics, AbstractTimerService, Writeable, ITimerService } from 'vs/workbench/services/timer/browser/timerService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -85,7 +85,7 @@ export class TimerService extends AbstractTimerService { } } -registerSingleton(ITimerService, TimerService, true); +registerSingleton(ITimerService, TimerService, InstantiationType.Delayed); //#region cached data logic diff --git a/src/vs/workbench/services/tunnel/browser/tunnelService.ts b/src/vs/workbench/services/tunnel/browser/tunnelService.ts index 622b9c7d62a..9bebab0ada4 100644 --- a/src/vs/workbench/services/tunnel/browser/tunnelService.ts +++ b/src/vs/workbench/services/tunnel/browser/tunnelService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnection'; import { AbstractTunnelService, ITunnelService, RemoteTunnel } from 'vs/platform/tunnel/common/tunnel'; @@ -36,4 +36,4 @@ export class TunnelService extends AbstractTunnelService { } } -registerSingleton(ITunnelService, TunnelService, true); +registerSingleton(ITunnelService, TunnelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts index 3b31b992f6f..919d45b23d1 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorService.ts @@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; export const IUntitledTextEditorService = createDecorator('untitledTextEditorService'); @@ -261,4 +261,4 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe } } -registerSingleton(IUntitledTextEditorService, UntitledTextEditorService, true); +registerSingleton(IUntitledTextEditorService, UntitledTextEditorService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/url/browser/urlService.ts b/src/vs/workbench/services/url/browser/urlService.ts index 7aec4c76552..602d6d32c6b 100644 --- a/src/vs/workbench/services/url/browser/urlService.ts +++ b/src/vs/workbench/services/url/browser/urlService.ts @@ -5,7 +5,7 @@ import { IURLService } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractURLService } from 'vs/platform/url/common/urlService'; import { Event } from 'vs/base/common/event'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -91,4 +91,4 @@ export class BrowserURLService extends AbstractURLService { } } -registerSingleton(IURLService, BrowserURLService, true); +registerSingleton(IURLService, BrowserURLService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts index 61da2875775..b9b95d027fd 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; @@ -93,4 +93,4 @@ export class UserDataProfileImportExportService implements IUserDataProfileImpor } -registerSingleton(IUserDataProfileImportExportService, UserDataProfileImportExportService, true); +registerSingleton(IUserDataProfileImportExportService, UserDataProfileImportExportService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts index c5eb692ab0a..a24838309e6 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncEnablementService.ts @@ -3,7 +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 { InstantiationType, 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'; @@ -18,4 +18,4 @@ export class UserDataSyncEnablementService extends BaseUserDataSyncEnablementSer } -registerSingleton(IUserDataSyncEnablementService, UserDataSyncEnablementService, true); +registerSingleton(IUserDataSyncEnablementService, UserDataSyncEnablementService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts b/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts index 896f506c826..a05ae03d23d 100644 --- a/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts +++ b/src/vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService.ts @@ -3,7 +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 { InstantiationType, 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'; @@ -51,4 +51,4 @@ export class WebUserDataSyncEnablementService extends UserDataSyncEnablementServ } -registerSingleton(IUserDataSyncEnablementService, WebUserDataSyncEnablementService, true); +registerSingleton(IUserDataSyncEnablementService, WebUserDataSyncEnablementService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts index aeafb075e5d..45329df40c4 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts @@ -6,7 +6,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IUserDataSyncUtilService, getDefaultIgnoredSettings } from 'vs/platform/userDataSync/common/userDataSync'; import { IStringDictionary } from 'vs/base/common/collections'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { FormattingOptions } from 'vs/base/common/jsonFormatter'; import { URI } from 'vs/base/common/uri'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -53,4 +53,4 @@ class UserDataSyncUtilService implements IUserDataSyncUtilService { } -registerSingleton(IUserDataSyncUtilService, UserDataSyncUtilService, true); +registerSingleton(IUserDataSyncUtilService, UserDataSyncUtilService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts index d373b910b87..62da5d44f2e 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts @@ -7,7 +7,7 @@ import { IUserDataAutoSyncService, UserDataSyncError } from 'vs/platform/userDat import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; class UserDataAutoSyncService implements IUserDataAutoSyncService { @@ -36,4 +36,4 @@ class UserDataAutoSyncService implements IUserDataAutoSyncService { } -registerSingleton(IUserDataAutoSyncService, UserDataAutoSyncService, true); +registerSingleton(IUserDataAutoSyncService, UserDataAutoSyncService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService.ts index c9806977001..134525e6d86 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService.ts @@ -5,7 +5,7 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { IUserDataSyncAccountService, IUserDataSyncAccount } from 'vs/platform/userDataSync/common/userDataSyncAccount'; @@ -44,4 +44,4 @@ export class UserDataSyncAccountService extends Disposable implements IUserDataS } -registerSingleton(IUserDataSyncAccountService, UserDataSyncAccountService, true); +registerSingleton(IUserDataSyncAccountService, UserDataSyncAccountService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService.ts index 059d4989d7d..766386ba6a9 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService.ts @@ -6,7 +6,7 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataSyncMachinesService, IUserDataSyncMachine } from 'vs/platform/userDataSync/common/userDataSyncMachines'; import { Event } from 'vs/base/common/event'; @@ -47,4 +47,4 @@ class UserDataSyncMachinesService extends Disposable implements IUserDataSyncMac } -registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, true); +registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts index 0ff3079372c..a85e432cd86 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts @@ -9,7 +9,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { AbstractUserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncStoreManagementServiceChannelClient } from 'vs/platform/userDataSync/common/userDataSyncIpc'; class UserDataSyncStoreManagementService extends AbstractUserDataSyncStoreManagementService implements IUserDataSyncStoreManagementService { @@ -37,4 +37,4 @@ class UserDataSyncStoreManagementService extends AbstractUserDataSyncStoreManage } -registerSingleton(IUserDataSyncStoreManagementService, UserDataSyncStoreManagementService, true); +registerSingleton(IUserDataSyncStoreManagementService, UserDataSyncStoreManagementService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/views/browser/viewDescriptorService.ts b/src/vs/workbench/services/views/browser/viewDescriptorService.ts index de843eacab8..12750975fc0 100644 --- a/src/vs/workbench/services/views/browser/viewDescriptorService.ts +++ b/src/vs/workbench/services/views/browser/viewDescriptorService.ts @@ -11,7 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { toDisposable, DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ViewPaneContainer, ViewPaneContainerAction, ViewsSubMenu } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Event, Emitter } from 'vs/base/common/event'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; @@ -924,4 +924,4 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor } } -registerSingleton(IViewDescriptorService, ViewDescriptorService, true); +registerSingleton(IViewDescriptorService, ViewDescriptorService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.ts index 5b620f0b1e8..8be2e38e3c5 100644 --- a/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.ts +++ b/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.ts @@ -11,7 +11,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkingCopyHistoryModelOptions, WorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistory'; export class BrowserWorkingCopyHistoryService extends WorkingCopyHistoryService { @@ -34,4 +34,4 @@ export class BrowserWorkingCopyHistoryService extends WorkingCopyHistoryService } // Register Service -registerSingleton(IWorkingCopyHistoryService, BrowserWorkingCopyHistoryService, true); +registerSingleton(IWorkingCopyHistoryService, BrowserWorkingCopyHistoryService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts index e4af0ad9baa..f95cb71ff84 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { EditorsOrder, IEditorIdentifier } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IWorkingCopy, IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; @@ -97,4 +97,4 @@ export class WorkingCopyEditorService extends Disposable implements IWorkingCopy } // Register Service -registerSingleton(IWorkingCopyEditorService, WorkingCopyEditorService, true); +registerSingleton(IWorkingCopyEditorService, WorkingCopyEditorService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts index 5e830f345ef..b70d40f4676 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Event, AsyncEmitter, IWaitUntil } from 'vs/base/common/event'; import { Promises } from 'vs/base/common/async'; import { insert } from 'vs/base/common/arrays'; @@ -525,4 +525,4 @@ export class WorkingCopyFileService extends Disposable implements IWorkingCopyFi //#endregion } -registerSingleton(IWorkingCopyFileService, WorkingCopyFileService, true); +registerSingleton(IWorkingCopyFileService, WorkingCopyFileService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index a7522cbcb77..e9a5927e310 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { Disposable, IDisposable, toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; @@ -290,4 +290,4 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic //#endregion } -registerSingleton(IWorkingCopyService, WorkingCopyService, true); +registerSingleton(IWorkingCopyService, WorkingCopyService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts index 55167103df8..173e036770e 100644 --- a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts +++ b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService.ts @@ -15,7 +15,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkingCopyHistoryModelOptions, WorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkingCopyHistoryService, MAX_PARALLEL_HISTORY_IO_OPS } from 'vs/workbench/services/workingCopy/common/workingCopyHistory'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; @@ -98,4 +98,4 @@ export class NativeWorkingCopyHistoryService extends WorkingCopyHistoryService { } // Register Service -registerSingleton(IWorkingCopyHistoryService, NativeWorkingCopyHistoryService, true); +registerSingleton(IWorkingCopyHistoryService, NativeWorkingCopyHistoryService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts index 637bf9d0a62..9a90505743f 100644 --- a/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts @@ -16,7 +16,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { IHostService } from 'vs/workbench/services/host/browser/host'; import { AbstractWorkspaceEditingService } from 'vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { URI } from 'vs/base/common/uri'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; @@ -57,4 +57,4 @@ export class BrowserWorkspaceEditingService extends AbstractWorkspaceEditingServ } } -registerSingleton(IWorkspaceEditingService, BrowserWorkspaceEditingService, true); +registerSingleton(IWorkspaceEditingService, BrowserWorkspaceEditingService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workspaces/browser/workspacesService.ts b/src/vs/workbench/services/workspaces/browser/workspacesService.ts index cddb23ae96a..08562f80207 100644 --- a/src/vs/workbench/services/workspaces/browser/workspacesService.ts +++ b/src/vs/workbench/services/workspaces/browser/workspacesService.ts @@ -3,7 +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 { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkspacesService, IWorkspaceFolderCreationData, IEnterWorkspaceResult, IRecentlyOpened, restoreRecentlyOpened, IRecent, isRecentFile, isRecentFolder, toStoreData, IStoredWorkspaceFolder, getStoredWorkspaceFolder, IStoredWorkspace, isRecentWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { Emitter } from 'vs/base/common/event'; @@ -215,4 +215,4 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS //#endregion } -registerSingleton(IWorkspacesService, BrowserWorkspacesService, true); +registerSingleton(IWorkspacesService, BrowserWorkspacesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workspaces/common/editSessionIdentityService.ts b/src/vs/workbench/services/workspaces/common/editSessionIdentityService.ts index a9b4a8cd98e..bf8d83d43ee 100644 --- a/src/vs/workbench/services/workspaces/common/editSessionIdentityService.ts +++ b/src/vs/workbench/services/workspaces/common/editSessionIdentityService.ts @@ -5,7 +5,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IEditSessionIdentityProvider, IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -54,4 +54,4 @@ export class EditSessionIdentityService implements IEditSessionIdentityService { } } -registerSingleton(IEditSessionIdentityService, EditSessionIdentityService, true); +registerSingleton(IEditSessionIdentityService, EditSessionIdentityService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts index 0cf6f3892c2..3d4f731f544 100644 --- a/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts @@ -20,7 +20,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { ILifecycleService, ShutdownReason } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; @@ -190,4 +190,4 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi } } -registerSingleton(IWorkspaceEditingService, NativeWorkspaceEditingService, true); +registerSingleton(IWorkspaceEditingService, NativeWorkspaceEditingService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts b/src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts index 48fbb4e5a1c..e5cb1078e35 100644 --- a/src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts +++ b/src/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts @@ -5,7 +5,7 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; @@ -22,4 +22,4 @@ export class NativeWorkspacesService implements IWorkspacesService { } } -registerSingleton(IWorkspacesService, NativeWorkspacesService, true); +registerSingleton(IWorkspacesService, NativeWorkspacesService, InstantiationType.Delayed); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 89d79d75b2e..bf9f350efe9 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -128,21 +128,21 @@ import { IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDat import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { IExtensionsProfileScannerService, ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; -registerSingleton(IUserDataSyncLogService, UserDataSyncLogService, true); -registerSingleton(IIgnoredExtensionsManagementService, IgnoredExtensionsManagementService, true); -registerSingleton(IGlobalExtensionEnablementService, GlobalExtensionEnablementService, true); -registerSingleton(IExtensionStorageService, ExtensionStorageService, true); -registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); -registerSingleton(IContextViewService, ContextViewService, true); -registerSingleton(IListService, ListService, true); +registerSingleton(IUserDataSyncLogService, UserDataSyncLogService, InstantiationType.Delayed); +registerSingleton(IIgnoredExtensionsManagementService, IgnoredExtensionsManagementService, InstantiationType.Delayed); +registerSingleton(IGlobalExtensionEnablementService, GlobalExtensionEnablementService, InstantiationType.Delayed); +registerSingleton(IExtensionStorageService, ExtensionStorageService, InstantiationType.Delayed); +registerSingleton(IExtensionGalleryService, ExtensionGalleryService, InstantiationType.Delayed); +registerSingleton(IContextViewService, ContextViewService, InstantiationType.Delayed); +registerSingleton(IListService, ListService, InstantiationType.Delayed); registerSingleton(IEditorWorkerService, EditorWorkerService, InstantiationType.Eager /* registers link detection and word based suggestions for any document */); -registerSingleton(IMarkerDecorationsService, MarkerDecorationsService, true); -registerSingleton(IMarkerService, MarkerService, true); -registerSingleton(IContextKeyService, ContextKeyService, true); -registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService, true); -registerSingleton(IDownloadService, DownloadService, true); -registerSingleton(IOpenerService, OpenerService, true); -registerSingleton(IExtensionsProfileScannerService, ExtensionsProfileScannerService, true); +registerSingleton(IMarkerDecorationsService, MarkerDecorationsService, InstantiationType.Delayed); +registerSingleton(IMarkerService, MarkerService, InstantiationType.Delayed); +registerSingleton(IContextKeyService, ContextKeyService, InstantiationType.Delayed); +registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService, InstantiationType.Delayed); +registerSingleton(IDownloadService, DownloadService, InstantiationType.Delayed); +registerSingleton(IOpenerService, OpenerService, InstantiationType.Delayed); +registerSingleton(IExtensionsProfileScannerService, ExtensionsProfileScannerService, InstantiationType.Delayed); //#endregion diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 187cb6c2a77..628a581d5a2 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -85,10 +85,10 @@ import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistorySer import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; import 'vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; -registerSingleton(IUserDataInitializationService, UserDataInitializationService, true); +registerSingleton(IUserDataInitializationService, UserDataInitializationService, InstantiationType.Delayed); //#endregion diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index ec48c866af4..c1dee216d10 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -92,22 +92,22 @@ import { IDiagnosticsService, NullDiagnosticsService } from 'vs/platform/diagnos import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/languagePacks'; -registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, true); -registerSingleton(IAccessibilityService, AccessibilityService, true); -registerSingleton(IContextMenuService, ContextMenuService, true); -registerSingleton(ILoggerService, FileLoggerService, true); -registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, true); -registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, true); -registerSingleton(IUserDataSyncBackupStoreService, UserDataSyncBackupStoreService, true); -registerSingleton(IUserDataSyncAccountService, UserDataSyncAccountService, true); -registerSingleton(IUserDataSyncService, UserDataSyncService, true); +registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); +registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed); +registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); +registerSingleton(ILoggerService, FileLoggerService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncBackupStoreService, UserDataSyncBackupStoreService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncAccountService, UserDataSyncAccountService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncService, UserDataSyncService, InstantiationType.Delayed); registerSingleton(IUserDataAutoSyncService, UserDataAutoSyncService, InstantiationType.Eager /* Eager to start auto sync */); registerSingleton(ITitleService, TitlebarPart, InstantiationType.Eager); -registerSingleton(IExtensionTipsService, ExtensionTipsService, true); -registerSingleton(ITimerService, TimerService, true); -registerSingleton(ICustomEndpointTelemetryService, NullEndpointTelemetryService, true); -registerSingleton(IDiagnosticsService, NullDiagnosticsService, true); -registerSingleton(ILanguagePackService, WebLanguagePacksService, true); +registerSingleton(IExtensionTipsService, ExtensionTipsService, InstantiationType.Delayed); +registerSingleton(ITimerService, TimerService, InstantiationType.Delayed); +registerSingleton(ICustomEndpointTelemetryService, NullEndpointTelemetryService, InstantiationType.Delayed); +registerSingleton(IDiagnosticsService, NullDiagnosticsService, InstantiationType.Delayed); +registerSingleton(ILanguagePackService, WebLanguagePacksService, InstantiationType.Delayed); //#endregion From 15b8f565742dd65bb9879ca4c67e3af498a6ab55 Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 4 Oct 2022 14:51:58 +0200 Subject: [PATCH 290/599] fix rendering/UI for `./scripts/test.sh --dev` --- test/unit/electron/renderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/electron/renderer.js b/test/unit/electron/renderer.js index 9b291fd0bd7..47f8fb0a53e 100644 --- a/test/unit/electron/renderer.js +++ b/test/unit/electron/renderer.js @@ -298,7 +298,7 @@ function runTests(opts) { mocha.grep(opts.grep); } - if (!opts.debug) { + if (!opts.dev) { mocha.reporter(IPCReporter); } @@ -308,7 +308,7 @@ function runTests(opts) { }); }); - if (opts.debug) { + if (opts.dev) { runner.on('fail', (test, err) => { console.error(test.fullTitle()); From 9038b736fd298daabd727de792aa7cd52cadd9e9 Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 4 Oct 2022 14:52:20 +0200 Subject: [PATCH 291/599] use fakeTimers for event tests, https://github.com/microsoft/vscode/issues/134972 --- src/vs/base/test/common/event.test.ts | 135 ++++++++++++++------------ 1 file changed, 72 insertions(+), 63 deletions(-) diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 79816c693e2..d87a96adda5 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -9,6 +9,7 @@ import { errorHandler, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { AsyncEmitter, DebounceEmitter, Emitter, Event, EventBufferer, EventMultiplexer, IWaitUntil, MicrotaskEmitter, PauseableEmitter, Relay } from 'vs/base/common/event'; import { DisposableStore, IDisposable, isDisposable, setDisposableTracker, toDisposable } from 'vs/base/common/lifecycle'; import { observableValue, transaction } from 'vs/base/common/observable'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { DisposableTracker, ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; namespace Samples { @@ -317,26 +318,29 @@ suite('Event', function () { }); test('DebounceEmitter', async function () { - let callCount = 0; - let sum = 0; - const emitter = new DebounceEmitter({ - merge: arr => { - callCount += 1; - return arr.reduce((p, c) => p + c); - } + return runWithFakedTimers({}, async function () { + + let callCount = 0; + let sum = 0; + const emitter = new DebounceEmitter({ + merge: arr => { + callCount += 1; + return arr.reduce((p, c) => p + c); + } + }); + + emitter.event(e => { sum = e; }); + + const p = Event.toPromise(emitter.event); + + emitter.fire(1); + emitter.fire(2); + + await p; + + assert.strictEqual(callCount, 1); + assert.strictEqual(sum, 3); }); - - emitter.event(e => { sum = e; }); - - const p = Event.toPromise(emitter.event); - - emitter.fire(1); - emitter.fire(2); - - await p; - - assert.strictEqual(callCount, 1); - assert.strictEqual(sum, 3); }); test('Microtask Emitter', (done) => { @@ -410,59 +414,64 @@ suite('AsyncEmitter', function () { }); test('sequential delivery', async function () { + return runWithFakedTimers({}, async function () { - interface E extends IWaitUntil { - foo: boolean; - } + interface E extends IWaitUntil { + foo: boolean; + } - let globalState = 0; - const emitter = new AsyncEmitter(); + let globalState = 0; + const emitter = new AsyncEmitter(); - emitter.event(e => { - e.waitUntil(timeout(10).then(_ => { - assert.strictEqual(globalState, 0); - globalState += 1; - })); + emitter.event(e => { + e.waitUntil(timeout(10).then(_ => { + assert.strictEqual(globalState, 0); + globalState += 1; + })); + }); + + emitter.event(e => { + e.waitUntil(timeout(1).then(_ => { + assert.strictEqual(globalState, 1); + globalState += 1; + })); + }); + + await emitter.fireAsync({ foo: true }, CancellationToken.None); + assert.strictEqual(globalState, 2); }); - - emitter.event(e => { - e.waitUntil(timeout(1).then(_ => { - assert.strictEqual(globalState, 1); - globalState += 1; - })); - }); - - await emitter.fireAsync({ foo: true }, CancellationToken.None); - assert.strictEqual(globalState, 2); }); test('sequential, in-order delivery', async function () { - interface E extends IWaitUntil { - foo: number; - } - const events: number[] = []; - let done = false; - const emitter = new AsyncEmitter(); + return runWithFakedTimers({}, async function () { - // e1 - emitter.event(e => { - e.waitUntil(timeout(10).then(async _ => { - if (e.foo === 1) { - await emitter.fireAsync({ foo: 2 }, CancellationToken.None); - assert.deepStrictEqual(events, [1, 2]); - done = true; - } - })); + interface E extends IWaitUntil { + foo: number; + } + const events: number[] = []; + let done = false; + const emitter = new AsyncEmitter(); + + // e1 + emitter.event(e => { + e.waitUntil(timeout(10).then(async _ => { + if (e.foo === 1) { + await emitter.fireAsync({ foo: 2 }, CancellationToken.None); + assert.deepStrictEqual(events, [1, 2]); + done = true; + } + })); + }); + + // e2 + emitter.event(e => { + events.push(e.foo); + e.waitUntil(timeout(7)); + }); + + await emitter.fireAsync({ foo: 1 }, CancellationToken.None); + assert.ok(done); }); - - // e2 - emitter.event(e => { - events.push(e.foo); - e.waitUntil(timeout(7)); - }); - - await emitter.fireAsync({ foo: 1 }, CancellationToken.None); - assert.ok(done); }); test('catch errors', async function () { From e380b6143b581414163c299a8cd34d9e8caae52a Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 4 Oct 2022 14:54:23 +0200 Subject: [PATCH 292/599] use fakeTimers for extHostDiag-tests, https://github.com/microsoft/vscode/issues/134972 --- .../test/browser/extHostDiagnostics.test.ts | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/api/test/browser/extHostDiagnostics.test.ts b/src/vs/workbench/api/test/browser/extHostDiagnostics.test.ts index 021725f35f0..f7d92af7f58 100644 --- a/src/vs/workbench/api/test/browser/extHostDiagnostics.test.ts +++ b/src/vs/workbench/api/test/browser/extHostDiagnostics.test.ts @@ -16,6 +16,7 @@ import type * as vscode from 'vscode'; import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ExtUri, extUri } from 'vs/base/common/resources'; import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; suite('ExtHostDiagnostics', () => { @@ -438,43 +439,46 @@ suite('ExtHostDiagnostics', () => { }); test('Diagnostics created by tasks aren\'t accessible to extensions #47292', async function () { - const diags = new ExtHostDiagnostics(new class implements IMainContext { - getProxy(id: any): any { - return {}; - } - set(): any { - return null; - } - dispose() { } - assertRegistered(): void { + return runWithFakedTimers({}, async function () { - } - drain() { - return undefined!; - } - }, new NullLogService(), fileSystemInfoService); + const diags = new ExtHostDiagnostics(new class implements IMainContext { + getProxy(id: any): any { + return {}; + } + set(): any { + return null; + } + dispose() { } + assertRegistered(): void { + + } + drain() { + return undefined!; + } + }, new NullLogService(), fileSystemInfoService); - // - const uri = URI.parse('foo:bar'); - const data: IMarkerData[] = [{ - message: 'message', - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 1, - severity: 3 - }]; + // + const uri = URI.parse('foo:bar'); + const data: IMarkerData[] = [{ + message: 'message', + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 1, + severity: 3 + }]; - const p1 = Event.toPromise(diags.onDidChangeDiagnostics); - diags.$acceptMarkersChange([[uri, data]]); - await p1; - assert.strictEqual(diags.getDiagnostics(uri).length, 1); + const p1 = Event.toPromise(diags.onDidChangeDiagnostics); + diags.$acceptMarkersChange([[uri, data]]); + await p1; + assert.strictEqual(diags.getDiagnostics(uri).length, 1); - const p2 = Event.toPromise(diags.onDidChangeDiagnostics); - diags.$acceptMarkersChange([[uri, []]]); - await p2; - assert.strictEqual(diags.getDiagnostics(uri).length, 0); + const p2 = Event.toPromise(diags.onDidChangeDiagnostics); + diags.$acceptMarkersChange([[uri, []]]); + await p2; + assert.strictEqual(diags.getDiagnostics(uri).length, 0); + }); }); test('languages.getDiagnostics doesn\'t handle case insensitivity correctly #128198', function () { From 9045cdc6872b6fb4076edc21dc1db76d8cb338e7 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Tue, 4 Oct 2022 15:26:09 +0100 Subject: [PATCH 293/599] Reference correct setting in property description (#162663) --- src/vs/platform/terminal/common/terminal.ts | 2 +- src/vscode-dts/vscode.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index d45df31b65a..692f8844b9c 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -486,7 +486,7 @@ export interface IShellLaunchConfig { * Whether the terminal process environment should be exactly as provided in * `TerminalOptions.env`. When this is false (default), the environment will be based on the * window's environment and also apply configured platform settings like - * `terminal.integrated.windows.env` on top. When this is true, the complete environment must be + * `terminal.integrated.env.windows` on top. When this is true, the complete environment must be * provided as nothing will be inherited from the process or any configuration. */ strictEnv?: boolean; diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index b6a65b4b93a..1a898cb7aed 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -10726,7 +10726,7 @@ declare module 'vscode' { * Whether the terminal process environment should be exactly as provided in * `TerminalOptions.env`. When this is false (default), the environment will be based on the * window's environment and also apply configured platform settings like - * `terminal.integrated.windows.env` on top. When this is true, the complete environment + * `terminal.integrated.env.windows` on top. When this is true, the complete environment * must be provided as nothing will be inherited from the process or any configuration. */ strictEnv?: boolean; From ddc22ef958273137daf7d404f32764fa202e16aa Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Tue, 4 Oct 2022 10:34:01 -0400 Subject: [PATCH 294/599] Use canonical URIs for tab IDs (#162661) --- src/vs/workbench/api/browser/mainThreadEditorTabs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts index bda93934177..09efeab8cde 100644 --- a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts +++ b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts @@ -194,7 +194,7 @@ export class MainThreadEditorTabs implements MainThreadEditorTabsShape { private _generateTabId(editor: EditorInput, groupId: number) { let resourceString: string | undefined; // Properly get the resource and account for side by side editors - const resource = EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.BOTH }); + const resource = EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.BOTH }); if (resource instanceof URI) { resourceString = resource.toString(); } else { From 2a0eb28cbc1b8654166d93502d4f5f99bb725b77 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 4 Oct 2022 16:52:04 +0200 Subject: [PATCH 295/599] Fix classifier comments (#162667) --- .github/classifier.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/classifier.json b/.github/classifier.json index 99bdbe96a29..179d8dafcdd 100644 --- a/.github/classifier.json +++ b/.github/classifier.json @@ -18,7 +18,7 @@ "callhierarchy": {"assign": ["jrieken"]}, "code-lens": {"assign": ["jrieken"]}, "color-palette": {"assign": []}, - "comments": {"assign": ["rebornix"]}, + "comments": {"assign": ["alexr00"]}, "config": {"assign": ["sandy081"]}, "context-keys": {"assign": []}, "css-less-scss": {"assign": ["aeschli"]}, From 1ba1c51712e6209f26014ac7c68cd633499f8ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 4 Oct 2022 18:17:10 +0300 Subject: [PATCH 296/599] cli: point docs to the new RA extension ns (#162500) --- cli/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/CONTRIBUTING.md b/cli/CONTRIBUTING.md index 88effa62a32..d119f1ac98a 100644 --- a/cli/CONTRIBUTING.md +++ b/cli/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Setup 0. Clone, and then run `git submodule update --init --recursive` -1. Get the extensions: [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer) and [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) +1. Get the extensions: [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) and [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) 2. Ensure your workspace is set to the `launcher` folder being the root. ## Building the CLI on Windows From 711c606e90673e26cbe95f4e0b091837a0ea40b1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2022 17:22:36 +0200 Subject: [PATCH 297/599] menu bar picks up toggle-title information (just like menu item actions) (#162672) --- src/vs/platform/action/common/action.ts | 34 ++++++++++++++++++- .../parts/editor/breadcrumbsControl.ts | 8 +++-- .../browser/controller/layoutActions.ts | 2 +- .../view/cellParts/cellEditorOptions.ts | 2 +- .../parts/titlebar/menubarControl.ts | 5 +++ 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/action/common/action.ts b/src/vs/platform/action/common/action.ts index d931781183b..146fb9f0035 100644 --- a/src/vs/platform/action/common/action.ts +++ b/src/vs/platform/action/common/action.ts @@ -30,6 +30,32 @@ export interface ICommandActionTitle extends ILocalizedString { export type Icon = { dark?: URI; light?: URI } | ThemeIcon; +export interface ICommandActionToggleInfo { + + /** + * The condition that marks the action as toggled. + */ + condition: ContextKeyExpression; + + icon?: Icon; + + tooltip?: string; + + /** + * The title that goes well with a a check mark, e.g "(check) Line Numbers" vs "Toggle Line Numbers" + */ + title?: string; + + /** + * Like title but with a mnemonic designation. + */ + mnemonicTitle?: string; +} + +export function isICommandActionToggleInfo(thing: ContextKeyExpression | ICommandActionToggleInfo | undefined): thing is ICommandActionToggleInfo { + return thing ? (thing).condition !== undefined : false; +} + export interface ICommandAction { id: string; title: string | ICommandActionTitle; @@ -39,7 +65,13 @@ export interface ICommandAction { icon?: Icon; source?: string; precondition?: ContextKeyExpression; - toggled?: ContextKeyExpression | { condition: ContextKeyExpression; icon?: Icon; tooltip?: string; title?: string | ILocalizedString }; + + /** + * The action is a toggle action. Define the context key expression that reflects its toggle-state + * or define toggle-info including an icon and a title that goes well with a checkmark. + */ + toggled?: ContextKeyExpression | ICommandActionToggleInfo; + /** @deprecated see https://github.com/microsoft/vscode/issues/162004 */ _isFakeAction?: true; } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 120b7c0343a..2a5a07c9c5d 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -504,11 +504,15 @@ registerAction2(class ToggleBreadcrumb extends Action2 { id: 'breadcrumbs.toggle', title: { value: localize('cmd.toggle', "Toggle Breadcrumbs"), - mnemonicTitle: localize('miBreadcrumbs', "&&Breadcrumbs"), + mnemonicTitle: localize('miBreadcrumbs', "Toggle &&Breadcrumbs"), original: 'Toggle Breadcrumbs', }, category: CATEGORIES.View, - toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true), + toggled: { + condition: ContextKeyExpr.equals('config.breadcrumbs.enabled', true), + title: localize('cmd.toggle2', "Breadcrumbs"), + mnemonicTitle: localize('miBreadcrumbs2', "&&Breadcrumbs") + }, menu: [ { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 3 }, diff --git a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts index 7f6ac0a645b..48ecba090de 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts @@ -133,7 +133,7 @@ registerAction2(class ToggleLineNumberFromEditorTitle extends Action2 { f1: true, toggled: { condition: ContextKeyExpr.notEquals('config.notebook.lineNumbers', 'off'), - title: { value: localize('notebook.showLineNumbers', "Show Notebook Line Numbers"), original: 'Show Notebook Line Numbers' }, + title: localize('notebook.showLineNumbers', "Notebook Line Numbers"), } }); } 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 3059080c7d5..f3751c8dbdf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts @@ -134,7 +134,7 @@ registerAction2(class ToggleLineNumberAction extends Action2 { f1: true, toggled: { condition: ContextKeyExpr.notEquals('config.notebook.lineNumbers', 'off'), - title: { value: localize('notebook.showLineNumbers', "Show Notebook Line Numbers"), original: 'Show Notebook Line Numbers' }, + title: localize('notebook.showLineNumbers', "Notebook Line Numbers"), } }); } diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts index b9aa17ff080..391bc05355c 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts @@ -25,6 +25,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions'; +import { isICommandActionToggleInfo } from 'vs/platform/action/common/action'; export class NativeMenubarControl extends MenubarControl { @@ -149,6 +150,10 @@ export class NativeMenubarControl extends MenubarControl { label: title }; + if (isICommandActionToggleInfo(menuItem.item.toggled)) { + menubarMenuItem.label = menuItem.item.toggled.mnemonicTitle ?? menuItem.item.toggled.title ?? title; + } + if (menuItem.checked) { menubarMenuItem.checked = true; } From 3b21a16362fb40acc4fd3f4e239e972449d585f3 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 4 Oct 2022 08:41:37 -0700 Subject: [PATCH 298/599] testing: fix breakage if item has same ID as test controller (#162620) Fixes #160671 --- src/vs/workbench/api/common/extHostTestItem.ts | 2 ++ .../api/test/browser/extHostTesting.test.ts | 13 +++++++++++++ src/vs/workbench/contrib/testing/common/testId.ts | 6 +++--- .../workbench/contrib/testing/common/testTypes.ts | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTestItem.ts b/src/vs/workbench/api/common/extHostTestItem.ts index 25fa2780a45..496cc12a035 100644 --- a/src/vs/workbench/api/common/extHostTestItem.ts +++ b/src/vs/workbench/api/common/extHostTestItem.ts @@ -175,6 +175,8 @@ export class TestItemImpl implements vscode.TestItem { } export class TestItemRootImpl extends TestItemImpl { + public readonly _isRoot = true; + constructor(controllerId: string, label: string) { super(controllerId, controllerId, label, undefined); } diff --git a/src/vs/workbench/api/test/browser/extHostTesting.test.ts b/src/vs/workbench/api/test/browser/extHostTesting.test.ts index fe0116c1b72..80645717880 100644 --- a/src/vs/workbench/api/test/browser/extHostTesting.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTesting.test.ts @@ -141,6 +141,19 @@ suite('ExtHost Testing', () => { assert.strictEqual(ab.parent, a); }); + test('can add an item with same ID as root', () => { + single.collectDiff(); + + const child = new TestItemImpl('ctrlId', 'ctrlId', 'c', undefined); + single.root.children.add(child); + assert.deepStrictEqual(single.collectDiff(), [ + { + op: TestDiffOpType.Add, + item: { controllerId: 'ctrlId', expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(child) }, + } + ]); + }); + test('no-ops if items not changed', () => { single.collectDiff(); assert.deepStrictEqual(single.collectDiff(), []); diff --git a/src/vs/workbench/contrib/testing/common/testId.ts b/src/vs/workbench/contrib/testing/common/testId.ts index 2f0965c9e5b..58b9af85589 100644 --- a/src/vs/workbench/contrib/testing/common/testId.ts +++ b/src/vs/workbench/contrib/testing/common/testId.ts @@ -23,7 +23,7 @@ export const enum TestPosition { IsParent, } -type TestItemLike = { id: string; parent?: TestItemLike }; +type TestItemLike = { id: string; parent?: TestItemLike; _isRoot?: boolean }; /** * The test ID is a stringifiable client that @@ -35,7 +35,7 @@ export class TestId { * Creates a test ID from an ext host test item. */ public static fromExtHostTestItem(item: TestItemLike, rootId: string, parent = item.parent) { - if (item.id === rootId) { + if (item._isRoot) { return new TestId([rootId]); } @@ -56,7 +56,7 @@ export class TestId { } /** - * Cheaply ets whether the ID refers to the root . + * Cheaply gets whether the ID refers to the root . */ public static root(idString: string) { const idx = idString.indexOf(TestIdPathParts.Delimiter); diff --git a/src/vs/workbench/contrib/testing/common/testTypes.ts b/src/vs/workbench/contrib/testing/common/testTypes.ts index cba30fb1288..b93713245cd 100644 --- a/src/vs/workbench/contrib/testing/common/testTypes.ts +++ b/src/vs/workbench/contrib/testing/common/testTypes.ts @@ -334,7 +334,7 @@ export const enum TestItemExpandState { } /** - * TestItem-like shape, butm with an ID and children as strings. + * TestItem-like shape, but with an ID and children as strings. */ export interface InternalTestItem { /** Controller ID from whence this test came */ From fd4346210f59135fad81a8b8c4cea7bf5a9ca6b4 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 4 Oct 2022 17:50:55 +0200 Subject: [PATCH 299/599] Update grammars (#162673) --- extensions/cpp/cgmanifest.json | 4 +- .../cpp.embedded.macro.tmLanguage.json | 113 +++++--- extensions/cpp/syntaxes/cpp.tmLanguage.json | 267 ++++++++++-------- .../syntaxes/JavaScript.tmLanguage.json | 20 +- .../syntaxes/JavaScriptReact.tmLanguage.json | 20 +- extensions/latex/cgmanifest.json | 4 +- .../latex/syntaxes/LaTeX.tmLanguage.json | 23 +- .../markdown-latex-combined.tmLanguage.json | 42 ++- extensions/scss/cgmanifest.json | 4 +- extensions/typescript-basics/cgmanifest.json | 2 +- .../syntaxes/TypeScript.tmLanguage.json | 20 +- .../syntaxes/TypeScriptReact.tmLanguage.json | 20 +- 12 files changed, 350 insertions(+), 189 deletions(-) diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index 79c46dad831..92d0016b0e6 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jeff-hykin/better-cpp-syntax", "repositoryUrl": "https://github.com/jeff-hykin/better-cpp-syntax", - "commitHash": "924295fc44bde1a00fab60da3a2caca4509adb25" + "commitHash": "32be139c7d3cdf07195af4b3a5c639ebf4e3b356" } }, "license": "MIT", - "version": "1.15.18", + "version": "1.15.23", "description": "The original JSON grammars were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." }, { diff --git a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json index b8a6aa53111..f109e7ea778 100644 --- a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json +++ b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/better-cpp-syntax/commit/924295fc44bde1a00fab60da3a2caca4509adb25", + "version": "https://github.com/jeff-hykin/better-cpp-syntax/commit/32be139c7d3cdf07195af4b3a5c639ebf4e3b356", "name": "C++", "scopeName": "source.cpp.embedded.macro", "patterns": [ @@ -519,7 +519,7 @@ "name": "comment.block.cpp" }, "builtin_storage_type_initilizer": { - "begin": "(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", "end": "\\}|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?(\\()", + "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?(\\()", "end": "\\)|(?=(?))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\()", + "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", + "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -4240,7 +4240,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -5334,15 +5334,23 @@ "name": "storage.modifier.lambda.$0.cpp" }, { - "match": "(->)((?:.+?(?=\\{|$))?)", - "captures": { - "1": { + "begin": "->", + "end": "(?=\\{)|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(?:(?:((?:(?:delete\\[\\])|(?:delete)|(?:new\\[\\])|(?:new)|(?:\\->\\*)|(?:<<=)|(?:>>=)|(?:<=>)|(?:\\+\\+)|(?:\\-\\-)|(?:\\(\\))|(?:\\[\\])|(?:\\->)|(?:\\+\\+)|(?:\\-\\-)|(?:<<)|(?:>>)|(?:<=)|(?:>=)|(?:==)|(?:!=)|(?:&&)|(?:\\|\\|)|(?:\\+=)|(?:\\-=)|(?:\\*=)|(?:\\/=)|(?:%=)|(?:&=)|(?:\\^=)|(?:\\|=)|(?:\\+)|(?:\\-)|!|~|(?:\\*)|&|(?:\\*)|(?:\\/)|%|(?:\\+)|(?:\\-)|<|>|&|(?:\\^)|(?:\\|)|=|,))|((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\<|\\()", + "begin": "(?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(?:(?:((?:(?:delete\\[\\])|(?:delete)|(?:new\\[\\])|(?:<=>)|(?:<<=)|(?:new)|(?:>>=)|(?:\\->\\*)|(?:\\/=)|(?:%=)|(?:&=)|(?:>=)|(?:\\|=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\(\\))|(?:\\[\\])|(?:\\->)|(?:\\+\\+)|(?:<<)|(?:>>)|(?:\\-\\-)|(?:<=)|(?:\\^=)|(?:==)|(?:!=)|(?:&&)|(?:\\|\\|)|(?:\\+=)|(?:\\-=)|(?:\\*=)|,|(?:\\+)|(?:\\-)|!|~|(?:\\*)|&|(?:\\*)|(?:\\/)|%|(?:\\+)|(?:\\-)|<|>|&|(?:\\^)|(?:\\|)|=))|((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "source.cpp#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.function.cpp" + }, + "7": { + "name": "keyword.other.delete.function.cpp" + } + } + }, { "include": "$self" } @@ -6971,7 +7018,7 @@ "include": "source.cpp#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -7351,7 +7398,7 @@ "include": "source.cpp#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -8827,7 +8874,7 @@ "name": "storage.type.template.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" } }, "endCaptures": { @@ -8847,7 +8894,7 @@ }, "endCaptures": { "0": { - "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + "name": "punctuation.section.angle-brackets.end.template.call.cpp" } }, "patterns": [ @@ -9428,7 +9475,7 @@ "endCaptures": {}, "patterns": [ { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()|(?=(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "\\s*+((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -2025,10 +2025,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp" } } }, @@ -2176,7 +2176,7 @@ ] }, "control_flow_keywords": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\{)", "end": "\\}", "beginCaptures": { "1": { @@ -3296,10 +3296,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp" } } }, @@ -3363,7 +3363,7 @@ ] }, "destructor_root": { - "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", + "begin": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)(((?>(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))::((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))~\\14((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\())", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -3587,10 +3587,10 @@ ] }, "6": { - "name": "keyword.other.default.constructor.cpp" + "name": "keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp" }, "7": { - "name": "keyword.other.delete.constructor.cpp" + "name": "keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp" } } }, @@ -3784,7 +3784,7 @@ "match": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?(::))?(?:(?:\\s)+)?((?|\\?\\?>)(?:(?:\\s)+)?(;)|(;))|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -4519,7 +4519,7 @@ ] }, "function_call": { - "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?(\\()", + "begin": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?(\\()", "end": "\\)", "beginCaptures": { "1": { @@ -4593,7 +4593,7 @@ ] }, "function_definition": { - "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\()", + "begin": "(?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<60>?)+>)(?:\\s)*+)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -5156,7 +5156,7 @@ ] }, { - "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", + "match": "(?<=^|\\))(?:(?:\\s)+)?(->)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<23>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "punctuation.definition.function.return-type.cpp" @@ -5404,7 +5404,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -5755,7 +5755,7 @@ ] }, "function_pointer_parameter": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -6510,7 +6510,7 @@ "name": "storage.type.modifier.virtual.cpp" }, { - "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)(?:(?:\\s)+)?(?!(?:(?:(?:protected)|(?:private)|(?:public))|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6708,7 +6708,7 @@ ] }, "inline_builtin_storage_type": { - "match": "(?:\\s)*+(?)((?:.+?(?=\\{|$))?)", - "captures": { - "1": { + "begin": "->", + "end": "(?=\\{)", + "beginCaptures": { + "0": { "name": "punctuation.definition.lambda.return-type.cpp" + } + }, + "endCaptures": {}, + "patterns": [ + { + "include": "#comments" }, - "2": { + { + "match": "\\S+", "name": "storage.type.return-type.lambda.cpp" } - } + ] }, { "begin": "\\{", @@ -7148,7 +7156,7 @@ "name": "entity.name.function.preprocessor.cpp" }, "member_access": { - "match": "(?:((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:(?:\\s)+)?(?:(?:\\.\\*|\\.)|(?:->\\*|->))(?:(?:\\s)+)?)*)(?:(?:\\s)+)?(\\b(?!uint_least16_t[^\\w]|uint_least32_t[^\\w]|uint_least64_t[^\\w]|int_least16_t[^\\w]|int_least32_t[^\\w]|int_least64_t[^\\w]|uint_least8_t[^\\w]|uint_fast16_t[^\\w]|uint_fast32_t[^\\w]|uint_fast64_t[^\\w]|int_least8_t[^\\w]|int_fast16_t[^\\w]|int_fast32_t[^\\w]|int_fast64_t[^\\w]|uint_fast8_t[^\\w]|suseconds_t[^\\w]|int_fast8_t[^\\w]|useconds_t[^\\w]|blksize_t[^\\w]|in_addr_t[^\\w]|in_port_t[^\\w]|uintptr_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|unsigned[^\\w]|u_quad_t[^\\w]|blkcnt_t[^\\w]|uint16_t[^\\w]|uint32_t[^\\w]|uint64_t[^\\w]|intptr_t[^\\w]|intmax_t[^\\w]|intmax_t[^\\w]|wchar_t[^\\w]|u_short[^\\w]|qaddr_t[^\\w]|caddr_t[^\\w]|daddr_t[^\\w]|fixpt_t[^\\w]|nlink_t[^\\w]|segsz_t[^\\w]|swblk_t[^\\w]|clock_t[^\\w]|ssize_t[^\\w]|int16_t[^\\w]|int32_t[^\\w]|int64_t[^\\w]|uint8_t[^\\w]|signed[^\\w]|double[^\\w]|u_char[^\\w]|u_long[^\\w]|ushort[^\\w]|quad_t[^\\w]|mode_t[^\\w]|size_t[^\\w]|time_t[^\\w]|int8_t[^\\w]|short[^\\w]|float[^\\w]|u_int[^\\w]|div_t[^\\w]|dev_t[^\\w]|gid_t[^\\w]|ino_t[^\\w]|key_t[^\\w]|pid_t[^\\w]|off_t[^\\w]|uid_t[^\\w]|auto[^\\w]|void[^\\w]|char[^\\w]|long[^\\w]|bool[^\\w]|uint[^\\w]|id_t[^\\w]|id_t[^\\w]|int[^\\w])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?!\\())", + "match": "(?:((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:(?:\\s)+)?(?:(?:\\.\\*|\\.)|(?:->\\*|->))(?:(?:\\s)+)?)*)(?:(?:\\s)+)?(\\b(?!uint_least32_t[^\\w]|uint_least16_t[^\\w]|uint_least64_t[^\\w]|int_least32_t[^\\w]|int_least64_t[^\\w]|uint_fast32_t[^\\w]|uint_fast64_t[^\\w]|uint_least8_t[^\\w]|uint_fast16_t[^\\w]|int_least16_t[^\\w]|int_fast16_t[^\\w]|int_least8_t[^\\w]|uint_fast8_t[^\\w]|int_fast64_t[^\\w]|int_fast32_t[^\\w]|int_fast8_t[^\\w]|suseconds_t[^\\w]|useconds_t[^\\w]|in_addr_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|uintmax_t[^\\w]|in_port_t[^\\w]|uintptr_t[^\\w]|blksize_t[^\\w]|uint32_t[^\\w]|uint64_t[^\\w]|u_quad_t[^\\w]|intmax_t[^\\w]|intmax_t[^\\w]|unsigned[^\\w]|blkcnt_t[^\\w]|uint16_t[^\\w]|intptr_t[^\\w]|swblk_t[^\\w]|wchar_t[^\\w]|u_short[^\\w]|qaddr_t[^\\w]|caddr_t[^\\w]|daddr_t[^\\w]|fixpt_t[^\\w]|nlink_t[^\\w]|segsz_t[^\\w]|clock_t[^\\w]|ssize_t[^\\w]|int16_t[^\\w]|int32_t[^\\w]|int64_t[^\\w]|uint8_t[^\\w]|int8_t[^\\w]|mode_t[^\\w]|quad_t[^\\w]|ushort[^\\w]|u_long[^\\w]|u_char[^\\w]|double[^\\w]|signed[^\\w]|time_t[^\\w]|size_t[^\\w]|key_t[^\\w]|div_t[^\\w]|ino_t[^\\w]|uid_t[^\\w]|gid_t[^\\w]|off_t[^\\w]|pid_t[^\\w]|float[^\\w]|dev_t[^\\w]|u_int[^\\w]|short[^\\w]|bool[^\\w]|id_t[^\\w]|uint[^\\w]|long[^\\w]|char[^\\w]|void[^\\w]|auto[^\\w]|id_t[^\\w]|int[^\\w])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?!\\())", "captures": { "1": { "patterns": [ @@ -7609,7 +7617,7 @@ ] }, "namespace_alias": { - "match": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<8>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<4>?)+>)(?:\\s)*+)?::)*\\s*+)(?:(?:\\s)+)?((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(?:(?:((?:(?:delete\\[\\])|(?:delete)|(?:new\\[\\])|(?:new)|(?:\\->\\*)|(?:<<=)|(?:>>=)|(?:<=>)|(?:\\+\\+)|(?:\\-\\-)|(?:\\(\\))|(?:\\[\\])|(?:\\->)|(?:\\+\\+)|(?:\\-\\-)|(?:<<)|(?:>>)|(?:<=)|(?:>=)|(?:==)|(?:!=)|(?:&&)|(?:\\|\\|)|(?:\\+=)|(?:\\-=)|(?:\\*=)|(?:\\/=)|(?:%=)|(?:&=)|(?:\\^=)|(?:\\|=)|(?:\\+)|(?:\\-)|!|~|(?:\\*)|&|(?:\\*)|(?:\\/)|%|(?:\\+)|(?:\\-)|<|>|&|(?:\\^)|(?:\\|)|=|,))|((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\<|\\()", + "begin": "(?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(operator)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<55>?)+>)(?:\\s)*+)?::)*+)(?:(?:((?:(?:delete\\[\\])|(?:delete)|(?:new\\[\\])|(?:<=>)|(?:<<=)|(?:new)|(?:>>=)|(?:\\->\\*)|(?:\\/=)|(?:%=)|(?:&=)|(?:>=)|(?:\\|=)|(?:\\+\\+)|(?:\\-\\-)|(?:\\(\\))|(?:\\[\\])|(?:\\->)|(?:\\+\\+)|(?:<<)|(?:>>)|(?:\\-\\-)|(?:<=)|(?:\\^=)|(?:==)|(?:!=)|(?:&&)|(?:\\|\\|)|(?:\\+=)|(?:\\-=)|(?:\\*=)|,|(?:\\+)|(?:\\-)|!|~|(?:\\*)|&|(?:\\*)|(?:\\/)|%|(?:\\+)|(?:\\-)|<|>|&|(?:\\^)|(?:\\|)|=))|((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=\\<|\\()", "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "beginCaptures": { "0": { @@ -8736,6 +8744,45 @@ { "include": "#qualifiers_and_specifiers_post_parameters" }, + { + "match": "(\\=)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.function.cpp" + }, + "7": { + "name": "keyword.other.delete.function.cpp" + } + } + }, { "include": "$self" } @@ -10475,7 +10522,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -11513,7 +11560,7 @@ "include": "#vararg_ellipses" }, { - "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", + "match": "((?:((?:(?:thread_local)|(?:volatile)|(?:register)|(?:restrict)|(?:static)|(?:extern)|(?:const)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))+)((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:\\s)*+(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=,|\\)|=)", "captures": { "1": { "patterns": [ @@ -12848,7 +12895,7 @@ ] }, "qualified_type": { - "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)?(?![\\w<:.])", + "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<11>?)+>)?(?![\\w<:.])", "captures": { "0": { "patterns": [ @@ -13042,27 +13089,27 @@ "name": "meta.qualified_type.cpp" }, "qualifiers_and_specifiers_post_parameters": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?:((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))(?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", + "match": "((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))((?(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))", - "captures": { - "1": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "2": { - "name": "comment.block.cpp" - }, - "3": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] + "5": { + "name": "storage.modifier.specifier.functional.post-parameters.$5.cpp" } } } @@ -13118,7 +13131,7 @@ } }, "scope_resolution": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13140,7 +13153,7 @@ } }, "scope_resolution_function_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13162,7 +13175,7 @@ } }, "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13200,7 +13213,7 @@ } }, "scope_resolution_function_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13222,7 +13235,7 @@ } }, "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13260,7 +13273,7 @@ } }, "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13282,7 +13295,7 @@ } }, "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13320,7 +13333,7 @@ } }, "scope_resolution_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13358,7 +13371,7 @@ } }, "scope_resolution_namespace_alias": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13380,7 +13393,7 @@ } }, "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13418,7 +13431,7 @@ } }, "scope_resolution_namespace_block": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13440,7 +13453,7 @@ } }, "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13478,7 +13491,7 @@ } }, "scope_resolution_namespace_using": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13500,7 +13513,7 @@ } }, "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13538,7 +13551,7 @@ } }, "scope_resolution_parameter": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13560,7 +13573,7 @@ } }, "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13598,7 +13611,7 @@ } }, "scope_resolution_template_call": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13620,7 +13633,7 @@ } }, "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13658,7 +13671,7 @@ } }, "scope_resolution_template_definition": { - "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", + "match": "(::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<3>?)+>)(?:\\s)*+)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -13680,7 +13693,7 @@ } }, "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", + "match": "((::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?::)*\\s*+)((?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<7>?)+>)(?:\\s)*+)?(::)", "captures": { "1": { "patterns": [ @@ -13722,7 +13735,7 @@ "name": "punctuation.terminator.statement.cpp" }, "simple_type": { - "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<12>?)+>)?(?![\\w<:.]))(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -16160,10 +16173,10 @@ ] }, "template_argument_defaulted": { - "match": "(?<=<|,)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:\\s)+)*)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:(?:\\s)+)?([=])", + "match": "(?<=<|,)(?:(?:\\s)+)?((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:\\s)+((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(\\=)", "captures": { "1": { - "name": "storage.type.template.cpp" + "name": "storage.type.template.argument.$1.cpp" }, "2": { "name": "entity.name.type.template.cpp" @@ -16248,7 +16261,7 @@ "name": "storage.type.template.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" } }, "endCaptures": { @@ -16268,7 +16281,7 @@ }, "endCaptures": { "0": { - "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + "name": "punctuation.section.angle-brackets.end.template.call.cpp" } }, "patterns": [ @@ -16283,7 +16296,7 @@ ] }, "template_definition_argument": { - "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)|((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:\\s)+)+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:(?:\\s)+)?(\\.\\.\\.)(?:(?:\\s)+)?((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))(?:(?:\\s)+)?(?:(,)|(?=>|$))", + "match": "((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)|((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?:\\s)+)+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)(?:(?:\\s)+)?(\\.\\.\\.)(?:(?:\\s)+)?((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|(?)(?:(?:\\s)+)?(class|typename)(?:(?:\\s)+((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))?)(?:(?:\\s)+)?(?:(\\=)(?:(?:\\s)+)?(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?(?:(,)|(?=>|$))", "captures": { "1": { "patterns": [ @@ -16334,7 +16347,7 @@ "name": "entity.name.type.template.cpp" }, "6": { - "name": "storage.type.template.cpp" + "name": "storage.type.template.argument.$6.cpp" }, "7": { "name": "punctuation.vararg-ellipses.template.definition.cpp" @@ -16343,6 +16356,30 @@ "name": "entity.name.type.template.cpp" }, "9": { + "name": "storage.type.template.cpp" + }, + "10": { + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" + }, + "11": { + "name": "storage.type.template.argument.$11.cpp" + }, + "12": { + "name": "entity.name.type.template.cpp" + }, + "13": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + }, + "14": { + "name": "storage.type.template.argument.$14.cpp" + }, + "15": { + "name": "entity.name.type.template.cpp" + }, + "16": { + "name": "keyword.operator.assignment.cpp" + }, + "17": { "name": "punctuation.separator.delimiter.comma.template.argument.cpp" } } @@ -16367,13 +16404,13 @@ ] }, "template_isolated_definition": { - "match": "(?(?:(?:\\s)+)?$)", + "match": "(?)(?:(?:\\s)+)?$", "captures": { "1": { "name": "storage.type.template.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "name": "punctuation.section.angle-brackets.begin.template.definition.cpp" }, "3": { "name": "meta.template.definition.cpp", @@ -16526,7 +16563,7 @@ } }, "type_alias": { - "match": "(using)(?:(?:\\s)+)?(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\w<:.]))(?:(?:\\s)+)?(\\=)(?:(?:\\s)+)?((?:typename)?)(?:(?:\\s)+)?((?:(?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\w<:.]))|(.*(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)?(?:(?:\\s)+)?(?:(;)|\\n)", + "match": "(using)(?:(?:\\s)+)?(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\w<:.]))(?:(?:\\s)+)?(\\=)(?:(?:\\s)+)?((?:typename)?)(?:(?:\\s)+)?((?:(?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<29>?)+>)?(?![\\w<:.]))|(.*(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)?(?:(?:\\s)+)?(?:(;)|\\n)", "captures": { "1": { "name": "keyword.other.using.directive.cpp" @@ -17616,7 +17653,7 @@ "endCaptures": {}, "patterns": [ { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)(?:\\s)*+)?::)*+)?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<18>?)+>)?(?![\\w<:.]))(((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))?(?:(?:&|(?:\\*))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*(?:&|(?:\\*)))?((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\()(\\*)(?:(?:\\s)+)?((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)(?:(?:\\s)+)?(?:(\\[)(\\w*)(\\])(?:(?:\\s)+)?)*(\\))(?:(?:\\s)+)?(\\()", "end": "(\\))((?:(?:(?:(?>(?:\\s)+)|(\\/\\*)((?:[^\\*]|(?:\\*)++[^\\/])*+((?:\\*)++\\/)))+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?=[{=,);>]|\\n)(?!\\()", "beginCaptures": { "1": { @@ -18901,7 +18938,7 @@ ] }, "typename": { - "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|__has_include|atomic_cancel|atomic_commit|dynamic_cast|thread_local|synchronized|static_cast|const_cast|co_return|constexpr|consteval|constexpr|constexpr|consteval|protected|namespace|constinit|co_return|noexcept|noexcept|continue|co_await|co_yield|volatile|register|restrict|explicit|volatile|noexcept|template|operator|decltype|typename|requires|co_await|co_yield|reflexpr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|compl|bitor|throw|or_eq|while|catch|break|class|union|const|const|endif|ifdef|undef|error|using|else|goto|case|enum|elif|else|line|this|not|new|xor|and|for|try|asm|or|do|if|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:__has_include)|(?:atomic_cancel)|(?:atomic_commit)|(?:dynamic_cast)|(?:thread_local)|(?:synchronized)|(?:static_cast)|(?:const_cast)|(?:co_return)|(?:constexpr)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:consteval)|(?:protected)|(?:namespace)|(?:constinit)|(?:co_return)|(?:noexcept)|(?:noexcept)|(?:continue)|(?:co_await)|(?:co_yield)|(?:volatile)|(?:register)|(?:restrict)|(?:explicit)|(?:override)|(?:volatile)|(?:noexcept)|(?:template)|(?:operator)|(?:decltype)|(?:typename)|(?:requires)|(?:co_await)|(?:co_yield)|(?:reflexpr)|(?:alignof)|(?:alignas)|(?:default)|(?:nullptr)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:sizeof)|(?:delete)|(?:not_eq)|(?:bitand)|(?:and_eq)|(?:xor_eq)|(?:typeid)|(?:switch)|(?:return)|(?:static)|(?:extern)|(?:inline)|(?:friend)|(?:public)|(?:ifndef)|(?:define)|(?:pragma)|(?:export)|(?:import)|(?:module)|(?:compl)|(?:bitor)|(?:throw)|(?:or_eq)|(?:while)|(?:catch)|(?:break)|(?:false)|(?:const)|(?:final)|(?:const)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:using)|(?:audit)|(?:axiom)|(?:else)|(?:goto)|(?:case)|(?:NULL)|(?:true)|(?:elif)|(?:else)|(?:line)|(?:this)|(?:not)|(?:new)|(?:xor)|(?:and)|(?:for)|(?:try)|(?:asm)|(?:or)|(?:do)|(?:if)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)?(?![\\w<:.]))", + "match": "(((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\s*\\(\\s*\\(.*?\\)\\s*\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?:(?:(?:(?:unsigned)|(?:signed)|(?:short)|(?:long))|(?:(?:struct)|(?:class)|(?:union)|(?:enum)))((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z))))*((?:::)?(?:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\b)(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)(?:\\s)*+)?::)*+)?((?:((?:(?>(?:\\s)+)|\\/\\*(?:[^\\*]|(?:\\*)++[^\\/])*+(?:\\*)++\\/)+)|(?:\\b)|(?=\\W)|(?<=\\W)|(?:\\A)|(?:\\Z)))(?!(?:(?:transaction_safe_dynamic)|(?:__has_cpp_attribute)|(?:reinterpret_cast)|(?:transaction_safe)|(?:atomic_noexcept)|(?:atomic_commit)|(?:__has_include)|(?:atomic_cancel)|(?:synchronized)|(?:thread_local)|(?:dynamic_cast)|(?:static_cast)|(?:const_cast)|(?:constexpr)|(?:co_return)|(?:constinit)|(?:namespace)|(?:protected)|(?:consteval)|(?:constexpr)|(?:constexpr)|(?:co_return)|(?:consteval)|(?:co_await)|(?:continue)|(?:template)|(?:reflexpr)|(?:volatile)|(?:register)|(?:co_await)|(?:co_yield)|(?:restrict)|(?:noexcept)|(?:volatile)|(?:override)|(?:explicit)|(?:decltype)|(?:operator)|(?:noexcept)|(?:noexcept)|(?:typename)|(?:requires)|(?:co_yield)|(?:nullptr)|(?:alignof)|(?:alignas)|(?:default)|(?:mutable)|(?:virtual)|(?:mutable)|(?:private)|(?:include)|(?:warning)|(?:_Pragma)|(?:defined)|(?:typedef)|(?:__asm__)|(?:concept)|(?:define)|(?:module)|(?:sizeof)|(?:switch)|(?:delete)|(?:pragma)|(?:and_eq)|(?:inline)|(?:xor_eq)|(?:typeid)|(?:import)|(?:extern)|(?:public)|(?:bitand)|(?:static)|(?:export)|(?:return)|(?:friend)|(?:ifndef)|(?:not_eq)|(?:false)|(?:final)|(?:break)|(?:const)|(?:catch)|(?:endif)|(?:ifdef)|(?:undef)|(?:error)|(?:audit)|(?:while)|(?:using)|(?:axiom)|(?:or_eq)|(?:compl)|(?:throw)|(?:bitor)|(?:const)|(?:line)|(?:case)|(?:else)|(?:this)|(?:true)|(?:goto)|(?:else)|(?:NULL)|(?:elif)|(?:new)|(?:asm)|(?:xor)|(?:and)|(?:try)|(?:not)|(?:for)|(?:do)|(?:if)|(?:or)|(?:if))\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<17>?)+>)?(?![\\w<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -19790,7 +19827,7 @@ } }, "using_namespace": { - "begin": "(?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]*+|\"(?:[^\"]*|\\\\\")\")|'(?:[^']*|\\\\')')\\g<6>?)+>)(?:\\s)*+)?::)*\\s*+)?((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|^|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((?]|\\|\\||\\&\\&|\\!\\=\\=|$|((? Date: Tue, 4 Oct 2022 18:14:10 +0200 Subject: [PATCH 300/599] Disable Privileged ports for OSX (#162662) Fixes #160266 --- src/vs/platform/tunnel/common/tunnel.ts | 21 ++++++++++++++++++- src/vs/platform/tunnel/node/tunnelService.ts | 6 ++++++ .../api/browser/mainThreadTunnelService.ts | 4 ++-- .../contrib/remote/browser/remoteExplorer.ts | 2 +- .../contrib/remote/browser/tunnelView.ts | 16 +++++++------- .../services/tunnel/browser/tunnelService.ts | 4 ++++ .../tunnel/electron-sandbox/tunnelService.ts | 7 +++++++ 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/tunnel/common/tunnel.ts b/src/vs/platform/tunnel/common/tunnel.ts index 29b07680481..1c0d70f63ff 100644 --- a/src/vs/platform/tunnel/common/tunnel.ts +++ b/src/vs/platform/tunnel/common/tunnel.ts @@ -129,6 +129,7 @@ export interface ITunnelService { closeTunnel(remoteHost: string, remotePort: number): Promise; setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable; setTunnelFeatures(features: TunnelProviderFeatures): void; + isPortPrivileged(port: number): boolean; } export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address: string; port: number } | undefined { @@ -402,6 +403,24 @@ export abstract class AbstractTunnelService implements ITunnelService { return !!extractLocalHostUriMetaDataForPortMapping(uri); } + public abstract isPortPrivileged(port: number): boolean; + + protected doIsPortPrivileged(port: number, isWindows: boolean, isMacintosh: boolean, osRelease: string): boolean { + if (isWindows) { + return false; + } else if (isMacintosh) { + const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(osRelease); + if (osVersion?.length === 4) { + const major = parseInt(osVersion[1]); + const minor = parseInt(osVersion[2]); + if (((major > 10) || (major === 10 && minor >= 14))) { + return false; + } + } + } + return port < 1024; + } + protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise | undefined; protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise | undefined { @@ -409,7 +428,7 @@ export abstract class AbstractTunnelService implements ITunnelService { const key = remotePort; this._factoryInProgress.add(key); const preferredLocalPort = localPort === undefined ? remotePort : localPort; - const creationInfo = { elevationRequired: elevateIfNeeded ? isPortPrivileged(preferredLocalPort) : false }; + const creationInfo = { elevationRequired: elevateIfNeeded ? this.isPortPrivileged(preferredLocalPort) : false }; const tunnelOptions: TunnelOptions = { remoteAddress: { host: remoteHost, port: remotePort }, localAddressPort: localPort, privacy, public: privacy ? (privacy !== TunnelPrivacyId.Private) : undefined, protocol }; const tunnel = tunnelProvider.forwardPort(tunnelOptions, creationInfo); if (tunnel) { diff --git a/src/vs/platform/tunnel/node/tunnelService.ts b/src/vs/platform/tunnel/node/tunnelService.ts index 7cdd91afd53..50a7cb920af 100644 --- a/src/vs/platform/tunnel/node/tunnelService.ts +++ b/src/vs/platform/tunnel/node/tunnelService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as net from 'net'; +import * as os from 'os'; import { BROWSER_RESTRICTED_PORTS, findFreePortFaster } from 'vs/base/node/ports'; import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; @@ -16,6 +17,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { connectRemoteAgentTunnel, IAddressProvider, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; import { AbstractTunnelService, isAllInterfaces, ISharedTunnelsService as ISharedTunnelsService, isLocalhost, ITunnelService, RemoteTunnel, TunnelPrivacyId } from 'vs/platform/tunnel/common/tunnel'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { isMacintosh, isWindows } from 'vs/base/common/platform'; async function createRemoteTunnel(options: IConnectionOptions, defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise { let readyTunnel: NodeRemoteTunnel | undefined; @@ -165,6 +167,10 @@ export class BaseTunnelService extends AbstractTunnelService { return (!settingValue || settingValue === 'localhost') ? '127.0.0.1' : '0.0.0.0'; } + public isPortPrivileged(port: number): boolean { + return this.doIsPortPrivileged(port, isWindows, isMacintosh, os.release()); + } + protected retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise | undefined { const existing = this.getTunnelFromMap(remoteHost, remotePort); if (existing) { diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index c43a9e82756..ea4f8198698 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -8,7 +8,7 @@ import { MainThreadTunnelServiceShape, MainContext, ExtHostContext, ExtHostTunne import { TunnelDtoConverter } from 'vs/workbench/api/common/extHostTunnelService'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { CandidatePort, IRemoteExplorerService, makeAddress, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT, PORT_AUTO_SOURCE_SETTING_PROCESS, TunnelSource } from 'vs/workbench/services/remote/common/remoteExplorerService'; -import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, isPortPrivileged, ProvidedPortAttributes, PortAttributesProvider, TunnelProtocol } from 'vs/platform/tunnel/common/tunnel'; +import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, ProvidedPortAttributes, PortAttributesProvider, TunnelProtocol } from 'vs/platform/tunnel/common/tunnel'; import { Disposable } from 'vs/base/common/lifecycle'; import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -111,7 +111,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun if (!this.elevateionRetry && (tunnelOptions.localAddressPort !== undefined) && (tunnel.tunnelLocalPort !== undefined) - && isPortPrivileged(tunnelOptions.localAddressPort) + && this.tunnelService.isPortPrivileged(tunnelOptions.localAddressPort) && (tunnel.tunnelLocalPort !== tunnelOptions.localAddressPort) && this.tunnelService.canElevate) { diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index e9f2f1ae804..15e4776d4a9 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -339,7 +339,7 @@ class OnAutoForwardedAction extends Disposable { choices.push(this.openPreviewChoice(tunnel)); } - if ((tunnel.tunnelLocalPort !== tunnel.tunnelRemotePort) && this.tunnelService.canElevate && isPortPrivileged(tunnel.tunnelRemotePort)) { + if ((tunnel.tunnelLocalPort !== tunnel.tunnelRemotePort) && this.tunnelService.canElevate && this.tunnelService.isPortPrivileged(tunnel.tunnelRemotePort)) { // Privileged ports are not on Windows, so it's safe to use "superuser" message += nls.localize('remote.tunnelsView.elevationMessage', "You'll need to run as superuser to use port {0} locally. ", tunnel.tunnelRemotePort); choices.unshift(this.elevateChoice(tunnel)); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 09222cf1888..d598e2d2ece 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -35,7 +35,7 @@ import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platfor import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { URI } from 'vs/base/common/uri'; -import { isAllInterfaces, isLocalhost, isPortPrivileged, ITunnelService, RemoteTunnel, TunnelPrivacyId, TunnelProtocol } from 'vs/platform/tunnel/common/tunnel'; +import { isAllInterfaces, isLocalhost, ITunnelService, RemoteTunnel, TunnelPrivacyId, TunnelProtocol } from 'vs/platform/tunnel/common/tunnel'; import { TunnelPrivacy } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -1138,13 +1138,13 @@ export namespace ForwardPortAction { export const TREEITEM_LABEL = nls.localize('remote.tunnel.forwardItem', "Forward Port"); const forwardPrompt = nls.localize('remote.tunnel.forwardPrompt', "Port number or address (eg. 3000 or 10.10.10.10:2000)."); - function validateInput(remoteExplorerService: IRemoteExplorerService, value: string, canElevate: boolean): { content: string; severity: Severity } | null { + function validateInput(remoteExplorerService: IRemoteExplorerService, tunnelService: ITunnelService, value: string, canElevate: boolean): { content: string; severity: Severity } | null { const parsed = parseAddress(value); if (!parsed) { return { content: invalidPortString, severity: Severity.Error }; } else if (parsed.port >= maxPortNumber) { return { content: invalidPortNumberString, severity: Severity.Error }; - } else if (canElevate && isPortPrivileged(parsed.port)) { + } else if (canElevate && tunnelService.isPortPrivileged(parsed.port)) { return { content: requiresSudoString, severity: Severity.Info }; } else if (mapHasAddressLocalhostOrAllInterfaces(remoteExplorerService.tunnelModel.forwarded, parsed.host, parsed.port)) { return { content: alreadyForwarded, severity: Severity.Error }; @@ -1174,7 +1174,7 @@ export namespace ForwardPortAction { }).then(tunnel => error(notificationService, tunnel, parsed!.host, parsed!.port)); } }, - validationMessage: (value) => validateInput(remoteExplorerService, value, tunnelService.canElevate), + validationMessage: (value) => validateInput(remoteExplorerService, tunnelService, value, tunnelService.canElevate), placeholder: forwardPrompt }); }; @@ -1190,7 +1190,7 @@ export namespace ForwardPortAction { await viewsService.openView(TunnelPanel.ID, true); const value = await quickInputService.input({ prompt: forwardPrompt, - validateInput: (value) => Promise.resolve(validateInput(remoteExplorerService, value, tunnelService.canElevate)) + validateInput: (value) => Promise.resolve(validateInput(remoteExplorerService, tunnelService, value, tunnelService.canElevate)) }); let parsed: { host: string; port: number } | undefined; if (value && (parsed = parseAddress(value))) { @@ -1436,12 +1436,12 @@ namespace ChangeLocalPortAction { export const ID = 'remote.tunnel.changeLocalPort'; export const LABEL = nls.localize('remote.tunnel.changeLocalPort', "Change Local Address Port"); - function validateInput(value: string, canElevate: boolean): { content: string; severity: Severity } | null { + function validateInput(tunnelService: ITunnelService, value: string, canElevate: boolean): { content: string; severity: Severity } | null { if (!value.match(/^[0-9]+$/)) { return { content: invalidPortString, severity: Severity.Error }; } else if (Number(value) >= maxPortNumber) { return { content: invalidPortNumberString, severity: Severity.Error }; - } else if (canElevate && isPortPrivileged(Number(value))) { + } else if (canElevate && tunnelService.isPortPrivileged(Number(value))) { return { content: requiresSudoString, severity: Severity.Info }; } return null; @@ -1484,7 +1484,7 @@ namespace ChangeLocalPortAction { } } }, - validationMessage: (value) => validateInput(value, tunnelService.canElevate), + validationMessage: (value) => validateInput(tunnelService, value, tunnelService.canElevate), placeholder: nls.localize('remote.tunnelsView.changePort', "New local port") }); } diff --git a/src/vs/workbench/services/tunnel/browser/tunnelService.ts b/src/vs/workbench/services/tunnel/browser/tunnelService.ts index 9bebab0ada4..179594037d5 100644 --- a/src/vs/workbench/services/tunnel/browser/tunnelService.ts +++ b/src/vs/workbench/services/tunnel/browser/tunnelService.ts @@ -18,6 +18,10 @@ export class TunnelService extends AbstractTunnelService { super(logService); } + public isPortPrivileged(_port: number): boolean { + return false; + } + protected retainOrCreateTunnel(_addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise | undefined { const existing = this.getTunnelFromMap(remoteHost, remotePort); if (existing) { diff --git a/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts b/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts index eb6835f334d..dcc855a7e9d 100644 --- a/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts +++ b/src/vs/workbench/services/tunnel/electron-sandbox/tunnelService.ts @@ -14,6 +14,8 @@ import { ISharedProcessTunnelService } from 'vs/platform/remote/common/sharedPro import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; +import { isMacintosh, isWindows } from 'vs/base/common/platform'; class SharedProcessTunnel extends Disposable implements RemoteTunnel { @@ -59,6 +61,7 @@ export class TunnelService extends AbstractTunnelService { @ISharedProcessTunnelService private readonly _sharedProcessTunnelService: ISharedProcessTunnelService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @ILifecycleService lifecycleService: ILifecycleService, + @INativeWorkbenchEnvironmentService private readonly _nativeWorkbenchEnvironmentService: INativeWorkbenchEnvironmentService ) { super(logService); @@ -70,6 +73,10 @@ export class TunnelService extends AbstractTunnelService { }); } + public isPortPrivileged(port: number): boolean { + return this.doIsPortPrivileged(port, isWindows, isMacintosh, this._nativeWorkbenchEnvironmentService.os.release); + } + protected retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise | undefined { const existing = this.getTunnelFromMap(remoteHost, remotePort); if (existing) { From 310c1f9a8e2e45314a4eda04cf6ad4e2776618d5 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 4 Oct 2022 16:35:49 +0000 Subject: [PATCH 301/599] Add vscode-dev-chrome-launcher repo to notebooks (#162680) Add vscode-dev-chrome-launcher to endgame notebooks Also sync list of our repos across notebooks --- .vscode/notebooks/endgame.github-issues | 2 +- .vscode/notebooks/my-endgame.github-issues | 2 +- .vscode/notebooks/my-work.github-issues | 2 +- .vscode/notebooks/verification.github-issues | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index bf214cf3c68..b4ed8ac99ba 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"September 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n$MILESTONE=milestone:\"September 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 4e86fcf6b63..441d0707c0a 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\n\n$MILESTONE=milestone:\"September 2022\"\n\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n$MILESTONE=milestone:\"September 2022\"\r\n\r\n$MINE=assignee:@me" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 376975e9dc3..b7811cf911c 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"October 2022\"" + "value": "// list of repos we work in\r\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n// current milestone name\r\n$milestone=milestone:\"October 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues index d34a821f2f9..7f03638ae2b 100644 --- a/.vscode/notebooks/verification.github-issues +++ b/.vscode/notebooks/verification.github-issues @@ -2,7 +2,7 @@ { "kind": 1, "language": "markdown", - "value": "### Bug Verification Queries\n\nBefore shipping we want to verify _all_ bugs. That means when a bug is fixed we check that the fix actually works. It's always best to start with bugs that you have filed and the proceed with bugs that have been filed from users outside the development team. " + "value": "### Bug Verification Queries\r\n\r\nBefore shipping we want to verify _all_ bugs. That means when a bug is fixed we check that the fix actually works. It's always best to start with bugs that you have filed and the proceed with bugs that have been filed from users outside the development team. " }, { "kind": 1, @@ -12,7 +12,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-jupyter repo:microsoft/vscode-python\n$milestone=milestone:\"May 2022\"" + "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n$milestone=milestone:\"May 2022\"" }, { "kind": 1, From 2e1f1a5d29ba7bab0592a89b4505c291a1dc3801 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 4 Oct 2022 09:51:35 -0700 Subject: [PATCH 302/599] Update codicons (#162679) --- .../browser/ui/codicons/codicon/codicon.ttf | Bin 72676 -> 72672 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index d8ac87cba86aaafb1e69d86cc4cd2591d01ce6c7..bab11139af89dcf8aed0b5e21cb9e33547cc4cb4 100644 GIT binary patch delta 541 zcmaE|o#nxHmI)3#uLRP&7#LJ)7#Qw3O!P5j)(X;^*rF`Bhk=3dM?rpZiE;3oZU#n{ zEfaSbu=L%Z_iy7Hex>?7X79{{%nQs9nZL7;u}HG$uvlSnz~YUikfoF5BFjBiLRL0b z6;>OpK3J<*hgr8+@3X#RqhRAju4(AsxGA_$pSzOaxXSlv_6LG6@Tjh4aU8COJ#XZP_$D_z& znx}wggy#t_J+CUSOWq9LX5JIL-}t!sJOK?(1KuA-_jF5ey9HAPaQK9p~^uhwdy24I{ zy$hELw+Szb;E1q^$cR`MS)Ud;Axa?1Cu&>Ny=aN(zUWgid@%trJu#PJIa7OXjxBPgx#WU0K(%zGVkw7i6!?zLjH=6O=2K+m@%1w;=BcQ@+CHDwW;Y zO2(qfqCjj4#cC^7Oq=%b;kk3oLTbV-!rsCR44cCz6fBPmn|vaK0KmAzN4Y;NAO U$Ku>M3t?fHhLxLtOnlP`0NroV4FCWD delta 545 zcmaE`o#n}PmI)3#CpymUV_;CJVPLrDGSSDB`Bl)Xi7m>42N)O_e-z{wmly}X>1JSL z*)eg40n3HF^IRL>@GI5tGy7m3VqRo^#QcMWoJER7m&GcJLl*BWMJ!z`msswz60x$g zsNfm`hfL48zmbrn+vvFwk@{j>^9lGvX`-MvR`KZ#UadLox>ML561&e zB2H;eHBM`sJ~?YSJ2_`LcR9auk#kw$%I2EkI?MHyo0waT+Zwk^?ppQkZtfu-d>$np zGdzVnqdZS}8Ff4W)Kz>))RIn z>_fOrxLtTj1XqMzL{`Lx$oh=PNl`*keo;H39z;t;Pl!GfBM=i5(-(6kRw1?`c24ZG zxVpG&3D=T(l6EBBNlr`dO5T=yE=3`wC{-ZUD>W)LE43=MEA>^HR$5ltmb72#S?N>K zA7x}@vSgZMwq@?f{F3FB)suB2>qmA_c2V|*>^nJTIU%_cxgB|0d5iL%G36_5u2R{Z ztz>E}s%|W*Y%Z#7D$8hWs`d~93WbEcg}sG^R|*Sn4xdoWsHX~4AdbMcj6h9{><`a1 eH&2^3O<4Ggu&{-&u%(a?kes%XVe^-XZ#n@cx6}&& From aab0bc821102eafb8b175e45b078e7c199609cd9 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 4 Oct 2022 10:39:44 -0700 Subject: [PATCH 303/599] remove unused PNGs (#162683) fixes #162682 --- .../workspace/browser/media/trusted-badge.png | Bin 4330 -> 0 bytes .../workspace/browser/media/untrusted-status.png | Bin 1361 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png delete mode 100644 src/vs/workbench/contrib/workspace/browser/media/untrusted-status.png diff --git a/src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png b/src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png deleted file mode 100644 index c53b0eea12ff26f5744503a94c74b23dd2191376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4330 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 TGZ_7v00000NkvXXu0mjf(=Cql From 3ee9749b359a4785784509ff4f596c7fdaa27029 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 4 Oct 2022 10:46:53 -0700 Subject: [PATCH 304/599] Remove extra enums (#162686) `showMessage` returns the selected item, so we don't need to create an enum here and can instead used the returned items directly --- .../src/languageFeatures/linkUpdater.ts | 61 ++++++-------- .../languageFeatures/updatePathsOnRename.ts | 84 ++++++++----------- 2 files changed, 60 insertions(+), 85 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts index cfe16893b39..32553783bfa 100644 --- a/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts +++ b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts @@ -123,50 +123,38 @@ class UpdateLinksOnFileRenameHandler extends Disposable { return false; } - const enum Choice { - None = 0, - Accept = 1, - Reject = 2, - Always = 3, - Never = 4, - } + const rejectItem: vscode.MessageItem = { + title: localize('reject.title', "No"), + isCloseAffordance: true, + }; - interface Item extends vscode.MessageItem { - readonly choice: Choice; - } + const acceptItem: vscode.MessageItem = { + title: localize('accept.title', "Yes"), + }; - const response = await vscode.window.showInformationMessage( + const alwaysItem: vscode.MessageItem = { + title: localize('always.title', "Always automatically update Markdown Links"), + }; + + const neverItem: vscode.MessageItem = { + title: localize('never.title', "Never automatically update Markdown Links"), + }; + + const choice = await vscode.window.showInformationMessage( newResources.length === 1 ? localize('prompt', "Update Markdown links for '{0}'?", path.basename(newResources[0].fsPath)) : this.getConfirmMessage(localize('promptMoreThanOne', "Update Markdown link for the following {0} files?", newResources.length), newResources), { modal: true, - }, { - title: localize('reject.title', "No"), - choice: Choice.Reject, - isCloseAffordance: true, - }, { - title: localize('accept.title', "Yes"), - choice: Choice.Accept, - }, { - title: localize('always.title', "Always automatically update Markdown Links"), - choice: Choice.Always, - }, { - title: localize('never.title', "Never automatically update Markdown Links"), - choice: Choice.Never, - }); + }, rejectItem, acceptItem, alwaysItem, neverItem); - if (!response) { - return false; - } - - switch (response.choice) { - case Choice.Accept: { + switch (choice) { + case acceptItem: { return true; } - case Choice.Reject: { + case rejectItem: { return false; } - case Choice.Always: { + case alwaysItem: { const config = vscode.workspace.getConfiguration('markdown', newResources[0]); config.update( settingNames.enabled, @@ -174,7 +162,7 @@ class UpdateLinksOnFileRenameHandler extends Disposable { this.getConfigTargetScope(config, settingNames.enabled)); return true; } - case Choice.Never: { + case neverItem: { const config = vscode.workspace.getConfiguration('markdown', newResources[0]); config.update( settingNames.enabled, @@ -182,9 +170,10 @@ class UpdateLinksOnFileRenameHandler extends Disposable { this.getConfigTargetScope(config, settingNames.enabled)); return false; } + default: { + return false; + } } - - return false; } private async getEditsForFileRename(renames: readonly RenameAction[], token: vscode.CancellationToken): Promise<{ edit: vscode.WorkspaceEdit; resourcesBeingRenamed: vscode.Uri[] } | undefined> { diff --git a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts index 4882ae3ca59..7c6995ec7d5 100644 --- a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts @@ -147,62 +147,47 @@ class UpdateImportsOnFileRenameHandler extends Disposable { return false; } - const enum Choice { - None = 0, - Accept = 1, - Reject = 2, - Always = 3, - Never = 4, - } + const rejectItem: vscode.MessageItem = { + title: localize('reject.title', "No"), + isCloseAffordance: true, + }; - interface Item extends vscode.MessageItem { - readonly choice: Choice; - } + const acceptItem: vscode.MessageItem = { + title: localize('accept.title', "Yes"), + }; + const alwaysItem: vscode.MessageItem = { + title: localize('always.title', "Always automatically update imports"), + }; - const response = await vscode.window.showInformationMessage( + const neverItem: vscode.MessageItem = { + title: localize('never.title', "Never automatically update imports"), + }; + + const response = await vscode.window.showInformationMessage( newResources.length === 1 ? localize('prompt', "Update imports for '{0}'?", path.basename(newResources[0].fsPath)) : this.getConfirmMessage(localize('promptMoreThanOne', "Update imports for the following {0} files?", newResources.length), newResources), { modal: true, - }, { - title: localize('reject.title', "No"), - choice: Choice.Reject, - isCloseAffordance: true, - }, { - title: localize('accept.title', "Yes"), - choice: Choice.Accept, - }, { - title: localize('always.title', "Always automatically update imports"), - choice: Choice.Always, - }, { - title: localize('never.title', "Never automatically update imports"), - choice: Choice.Never, - }); + }, rejectItem, acceptItem, alwaysItem, neverItem); - if (!response) { - return false; - } - switch (response.choice) { - case Choice.Accept: - { - return true; - } - case Choice.Reject: - { - return false; - } - case Choice.Always: - { - const config = this.getConfiguration(newResources[0]); - config.update( - updateImportsOnFileMoveName, - UpdateImportsOnFileMoveSetting.Always, - this.getConfigTargetScope(config, updateImportsOnFileMoveName)); - return true; - } - case Choice.Never: + switch (response) { + case acceptItem: { + return true; + } + case rejectItem: { + return false; + } + case alwaysItem: { + const config = this.getConfiguration(newResources[0]); + config.update( + updateImportsOnFileMoveName, + UpdateImportsOnFileMoveSetting.Always, + this.getConfigTargetScope(config, updateImportsOnFileMoveName)); + return true; + } + case neverItem: { const config = this.getConfiguration(newResources[0]); config.update( @@ -211,9 +196,10 @@ class UpdateImportsOnFileRenameHandler extends Disposable { this.getConfigTargetScope(config, updateImportsOnFileMoveName)); return false; } + default: { + return false; + } } - - return false; } private async getJsTsFileBeingMoved(resource: vscode.Uri): Promise { From d507e3d7df07362ac70f204b64b06754732b2b52 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Tue, 4 Oct 2022 10:47:00 -0700 Subject: [PATCH 305/599] Polish code actions widget styling (#162685) * Polish code actions widget styling * Updates * Reduce icon gap --- .../codeAction/browser/codeActionWidget.css | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css index 0f0e9b3c299..c788bfe5d1e 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css +++ b/src/vs/editor/contrib/codeAction/browser/codeActionWidget.css @@ -12,10 +12,8 @@ display: block; width: 100%; border: 1px solid var(--vscode-editorWidget-border) !important; - border-color: none; background-color: var(--vscode-editorWidget-background); color: var(--vscode-editorWidget-foreground); - box-shadow: var(--vscode-widget-shadow) 0 2px 8px; } .codeActionWidget .monaco-list { @@ -42,7 +40,7 @@ width: 100%; } -.codeActionWidget .monaco-list .monaco-list-row.code-action.focused:not(.option-disabled) { +.codeActionWidget .monaco-list .monaco-list-row.code-action.focused:not(.option-disabled) { background-color: var(--vscode-quickInputList-focusBackground); color: var(--vscode-quickInputList-focusForeground); outline: 1px solid var(--vscode-menu-selectionBorder, transparent); @@ -51,7 +49,7 @@ .codeActionWidget .monaco-list-row.group-header { color: var(--vscode-pickerGroup-foreground); - font-weight: bold; + font-weight: 600; } .codeActionWidget .monaco-list .group-header, @@ -72,7 +70,7 @@ .codeActionWidget .monaco-list-row.code-action { display: flex; - gap: 10px; + gap: 6px; align-items: center; } @@ -98,28 +96,30 @@ .codeActionWidget .codeActionWidget-action-bar { margin-top: 4px; - margin-bottom: 4px; + background-color: var(--vscode-editorHoverWidget-statusBarBackground); + border-top: 1px solid var(--vscode-editorHoverWidget-border); } .codeActionWidget .codeActionWidget-action-bar::before { display: block; content: ""; width: 100%; - margin-bottom: 4px; - border-bottom: 1px solid var(--vscode-menu-separatorBackground); } .codeActionWidget .codeActionWidget-action-bar .actions-container { - padding: 0 10px; + padding: 0 8px; } .codeActionWidget-action-bar .action-label { color: var(--vscode-textLink-activeForeground); + font-size: 12px; + line-height: 22px; + padding: 0; pointer-events: all; } .codeActionWidget-action-bar .action-item { - margin-right: 10px; + margin-right: 16px; pointer-events: none; } From 6d55b5410ccd64d3d96ad8fa6431a49740f248a9 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 4 Oct 2022 11:13:04 -0700 Subject: [PATCH 306/599] support multiple actions for git similar command (#162668) --- .../commandDetectionCapability.ts | 2 +- .../browser/terminalQuickFixBuiltinActions.ts | 29 +++++++++-------- .../test/browser/quickFixAddon.test.ts | 32 ++++++++++++++++++- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 814d275ebfa..5ecd49bee30 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -655,7 +655,7 @@ export function getOutputMatchForCommand(executedMarker: IMarker | undefined, en const endLine = endMarker.line; const matcher = outputMatcher.lineMatcher; - const linesToCheck = typeof matcher === 'string' ? 1 : countNewLines(matcher); + const linesToCheck = typeof matcher === 'string' ? 1 : outputMatcher.length || countNewLines(matcher); const lines: string[] = []; if (outputMatcher.anchor === 'bottom') { for (let i = endLine - (outputMatcher.offset || 0); i >= startLine; i--) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index a8fa5ba8788..0db5a155216 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -13,10 +13,10 @@ export const GitCommandLineRegex = /git/; export const GitPushCommandLineRegex = /git\s+push/; export const GitTwoDashesRegex = /error: did you mean `--(.+)` \(with two dashes\)\?/; export const AnyCommandLineRegex = /.+/; -export const GitSimilarOutputRegex = /most similar command is\s*\n\s*([^\s]{3,})/m; +export const GitSimilarOutputRegex = /(?:(most similar (command|commands) (is|are)))((\n\s*[^\s]+)+)/m; export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; -// The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*", +// The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*" // it's safe to assume it's a github pull request if the URL includes `/pull/` export const GitCreatePrOutputRegex = /remote:\s*(https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/; @@ -27,23 +27,26 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { lineMatcher: GitSimilarOutputRegex, anchor: 'bottom', offset: 0, - length: 3 + length: 10 }, exitStatus: false, getQuickFixes: (matchResult: QuickFixMatchResult, command: ITerminalCommand) => { const actions: ITerminalQuickFixAction[] = []; - const fixedCommand = matchResult?.outputMatch?.[1]; - if (!fixedCommand) { + if (!matchResult?.outputMatch) { return; } - const commandToRunInTerminal = `git ${fixedCommand}`; - const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); - actions.push({ - class: undefined, tooltip: label, id: 'terminal.gitSimilarCommand', label, enabled: true, - commandToRunInTerminal, - addNewLine: true, - run: () => { } - }); + const results = matchResult.outputMatch[0].split('\n').map(r => r.trim()); + for (let i = 1; i < results.length; i++) { + const fixedCommand = results[i]; + const commandToRunInTerminal = `git ${fixedCommand}`; + const label = localize("terminal.runCommand", "Run: {0}", commandToRunInTerminal); + actions.push({ + class: undefined, tooltip: label, id: 'terminal.gitSimilarCommand', label, enabled: true, + commandToRunInTerminal, + addNewLine: true, + run: () => { } + }); + } return actions; } }; diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index c8d9062fb8e..40e15538459 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -48,7 +48,7 @@ suite('QuickFixAddon', () => { suite('gitSimilarCommand', async () => { const expectedMap = new Map(); const command = `git sttatus`; - const output = `git: 'sttatus' is not a git command. See 'git --help'. + let output = `git: 'sttatus' is not a git command. See 'git --help'. The most similar command is status`; @@ -83,6 +83,36 @@ suite('QuickFixAddon', () => { assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap), actions); }); }); + suite('returns match', () => { + test('returns match', () => { + assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex), expectedMap), actions); + }); + + test('returns multiple match', () => { + output = `git: 'pu' is not a git command. See 'git --help'. + + The most similar commands are + pull + push`; + const actions = [ + { + id: 'terminal.gitSimilarCommand', + label: 'Run: git pull', + run: true, + tooltip: 'Run: git pull', + enabled: true + }, + { + id: 'terminal.gitSimilarCommand', + label: 'Run: git push', + run: true, + tooltip: 'Run: git push', + enabled: true + } + ]; + assertMatchOptions(getQuickFixes(createCommand('git pu', output, GitSimilarOutputRegex), expectedMap), actions); + }); + }); }); suite('gitTwoDashes', async () => { const expectedMap = new Map(); From 9926342f194d51507241ac973306c301c209162f Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 4 Oct 2022 11:15:10 -0700 Subject: [PATCH 307/599] add completion/failure task audio cues (#162350) --- .../audioCues/browser/audioCueService.ts | 17 ++++++++++++----- .../browser/audioCues.contribution.ts | 8 ++++++-- .../audioCues/browser/media/taskCompleted.mp3 | Bin 0 -> 60521 bytes .../audioCues/browser/media/taskEnded.mp3 | Bin 41536 -> 0 bytes .../audioCues/browser/media/taskFailed.mp3 | Bin 0 -> 70552 bytes .../tasks/browser/taskTerminalStatus.ts | 11 ++++------- .../contrib/terminal/browser/terminal.ts | 1 - 7 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 src/vs/workbench/contrib/audioCues/browser/media/taskCompleted.mp3 delete mode 100644 src/vs/workbench/contrib/audioCues/browser/media/taskEnded.mp3 create mode 100644 src/vs/workbench/contrib/audioCues/browser/media/taskFailed.mp3 diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts b/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts index d8b25e74470..ce7a4d8a1b0 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCueService.ts @@ -152,7 +152,8 @@ export class Sound { public static readonly foldedArea = Sound.register({ fileName: 'foldedAreas.mp3' }); public static readonly break = Sound.register({ fileName: 'break.mp3' }); public static readonly quickFixes = Sound.register({ fileName: 'quickFixes.mp3' }); - public static readonly taskEnded = Sound.register({ fileName: 'taskEnded.mp3' }); + public static readonly taskCompleted = Sound.register({ fileName: 'taskCompleted.mp3' }); + public static readonly taskFailed = Sound.register({ fileName: 'taskFailed.mp3' }); public static readonly terminalBell = Sound.register({ fileName: 'terminalBell.mp3' }); private constructor(public readonly fileName: string) { } @@ -219,10 +220,16 @@ export class AudioCue { settingsKey: 'audioCues.noInlayHints' }); - public static readonly taskEnded = AudioCue.register({ - name: localize('audioCues.taskEnded', 'Task Ended'), - sound: Sound.taskEnded, - settingsKey: 'audioCues.taskEnded' + public static readonly taskCompleted = AudioCue.register({ + name: localize('audioCues.taskCompleted', 'Task Completed'), + sound: Sound.taskCompleted, + settingsKey: 'audioCues.taskCompleted' + }); + + public static readonly taskFailed = AudioCue.register({ + name: localize('audioCues.taskFailed', 'Task Failed'), + sound: Sound.taskFailed, + settingsKey: 'audioCues.taskFailed' }); public static readonly terminalBell = AudioCue.register({ diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 8626ff1630e..74b817d6c1a 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -72,8 +72,12 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'description': localize('audioCues.noInlayHints', "Plays a sound when trying to read a line with inlay hints that has no inlay hints."), ...audioCueFeatureBase, }, - 'audioCues.taskEnded': { - 'description': localize('audioCues.taskEnded', "Plays a sound when a task ends."), + 'audioCues.taskCompleted': { + 'description': localize('audioCues.taskCompleted', "Plays a sound when a task completed."), + ...audioCueFeatureBase, + }, + 'audioCues.taskFailed': { + 'description': localize('audioCues.taskFailed', "Plays a sound when a task fails (non-zero exit code)."), ...audioCueFeatureBase, }, 'audioCues.terminalQuickFix': { diff --git a/src/vs/workbench/contrib/audioCues/browser/media/taskCompleted.mp3 b/src/vs/workbench/contrib/audioCues/browser/media/taskCompleted.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..dd3fecbef571e2b4fa5b223bae6658a4feecb3ba GIT binary patch literal 60521 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 J|EIpd{{cfp=v4p! literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/audioCues/browser/media/taskEnded.mp3 b/src/vs/workbench/contrib/audioCues/browser/media/taskEnded.mp3 deleted file mode 100644 index 37b832b02b5bb0356d7c07792f9aee33b5b426cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41536 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 diff --git a/src/vs/workbench/contrib/audioCues/browser/media/taskFailed.mp3 b/src/vs/workbench/contrib/audioCues/browser/media/taskFailed.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..7a155fa67d32a67fa0dd2a386e5f2fe735dca072 GIT binary patch literal 70552 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

$Hu_1}Wi>Je`2}^)MD~Ml zwi#5$qWv06iVE3+mT=T;7c)mmz4D`()=Tn~7i`N&>jeTbQndXHV|Jz5_vEf=qu@Oh z>v?QZiOj6(6&FMvtMokb1m4o6dS2-1IJ=jDR1zje$y;YNg~9zWRZS2*Z!`mcHz(o-(;BpIg@mac0UN8mK;-8%DX#v z`9iq9>en5=B=RE;xO&fJcV?r(;RpGxG)&5nR#y{cHKP4QN|hSU>^v>pS}^S6o0AS^ zA;^j}!#RRNU=t>7v0Bp3oQ-4CE*1GxwZ zpaFy*JWk31IRLmQATcPWl*|z?UZMJ?9Imfw#1g0Rm5$>^*B945y2qdJy>9oZo+Q8f z+*-?mXd;mSmA&q*db#faFIc(pT*%W2hrY5;e3Hex7%?hUOS7823}(2Yy8gai z;_a`bS^Pm2LPd+TN{Rv$P3wfP<|Evb1zhw$PxVSW4Mdv> zigxQow+l8?Wq8DV;n%~5hU(M1O}*A%`}-T97oEDRtQF2^K8O7pcyjK2r0L7&FByI(-tW|15OVBUvIE+Kj%1?pzWLC) zZVA0d9h}i3j1+UvqoSftky;3tUX&ex0@~8BRFon`fz(!c2!+zXLP<0ygbfO{#!sVp z!T}Up#r}3u2ONuHqcPLkS|;&OSteAzr>L|*C=_wc8_35nLuk!Ylb5M-RAyQ27y=Rr zd1xpG2=I1K=Igp8LZuMG2q>B&#fDnDY1U8qJm@hA=Rj;@C!c8zmX*DHdsoWY6x26O zWWTxD-rr)Sg?sZz17k>?^ z(nvQr<%kh3UrF5wOK&?QN-_Tq!xA09wvT}&_=UR?3X~*M8a@5QiUfHAT&<__B9w;E=eutd~EQxZ7^ zUww2@Dd?5zDQ08TZOy&N8LoY_|0r(W`$s4HuRvX5>`m+!{z?14SPseGUh(byD5p-F z*Grj27t$1?+4o-iw=+4UBH^xGuGT4HP)cjViC!U+t3KBkphbmi3+JE)IS?oA$WfI^;?Q);`Wy_uRd$JRz2N)S5*Vp)!JN7#>?_fQi^V@t-o>TE$NzTrLrIFrJkpY+{1rrdbWuBYeH~jL|jx^L;$H;c=E6$_qrsI zw58j{$ChC&d4?$UFYxf%Ed`&Ymm+WHad6feBCR%G|7ztjyF~`l# z0c&6*VVAwtEpSw#vZi75VDb@xdbW21N#E6lEEor>@M|2_6Ep2JnioH7XSTXQP$dUe z7Ut!ArK_&}uU{6aU8M`=)D^|(1P`y=^2Sm}B614pelVjZW6w554yt;b_`kkD0liZg z-^3@?@zD`L3Y3Tw6rZpp-}O?f23d(7Q>T^fI5CEO-CzuVzm}n2{u_|vQks#X%2KE| zS}5PdGS@uff9#b#_5M|n>Bs>?E?b9rJAhX}QW@cZ>=ScO#!n5d6bBhj_K+H|ebAd} zGC&=S7FodUF6qqO0oMsOl0gIW29SU$0|o^kHk|0yJccX;iRe%06HM^&xe(kh#Yh-Z zqy#kmvJu6iAprS5Z=v~>!9b)`4B`ZWfV4r}y0jx!{CJ7K3Cu2-dc1Av@G;Ys+t)YW zI$xhFpZ(pyCrr(+GgZ8=Z&trI<5Qi8BmlwiU4PJXpo(h{$jLv09|z=ziFI=%x{OZU z`vTc|RZWkTbB^6$j1T-rCJJ3aPKQ>DuV#vo3uJ-ObpuH`j_Try?ILsTMa=4FTlJAJ z#>j}-jGf|~sGtZlA_%lpq+`g%-G4LSCBCfifN5N%lDvJ49TkOB2JJ7<43@_)%tctj zMxx#h<|V|x{khx5Ph+ky-Q6P~Z4G`d4M???Cf#G5214ve7tALn&Mo>xQYuzYth%L{ zh6$+2A{pd)6aNKa-;-@;6l6b%cZg@eMwi55`y$EkQgKEj+ElOgYpaRSdI78mqf(? z;lQAkA=;fMzL01JJcKj_AU2`u7MDg(F2q?qT-Stp@x=s<6alK9M!1+*VhJJcH@kK>ZUULin&i(oA#-eQ%) zaz-3d7vU|bbRo6}_;BLX^)lch5DTMvnp1)Lu;E2~eiOr?u)!lrQI}jQG5>WcdB-1# z5->6JLDKreTJG-RCq6z`NJ~S=$bZP$L*d8Yyh~5BJ?_8%Ir*pa<9J!4W8J-nTlf#T z-K|Aw^Viq5^Y8zqOb=(?Htt>JuwO*Suz4!J35-9==y*`Q2}~Ll1=d-07&)g+G{)S# zQi!U8F48111ihIQ2!O{6rezm(6-Fq4>q$faz{5kSAYKv_(171R-Zyfl4sr*_es`U{ zG5`IfB%*qRf77NL^NeWaN?~qsndMCn%L5hhP|p2$Y{z>gdh^4kI^6x0;PI$`R)0Nd zt9p0HS-UdFnF%-t$BI0IS)sz(Q3G>;=#WUGeGq0J3DcC;F(vmq9PB<6}|zi%!eY36pF zY`gs6(B{>NB$`abjP;RC&fu!VO3u&92Hu^tKz%Jxfpfr;K~qC7#YUXj#-ylZCA#N5 ztLZJhS(V(X5_xn-6_#x}+b*8k!Hl)R_?&qsq66dr*#Yu4B{DXEN3y&D*g@hEG|d0K zgW9Fzo3wd(CNZ0=JQsGOvb5DHIp9B!ST+nr=8 zT=y2+9jB+4?|E@VhwnFfPxAH9}aN@gMOi_VwP5uc*Z5%4E6A<>Q}vm#m>t!Z%^+W)j>w!2rm^^ zUGcb?O4t{nU$IK2p7_PFO2rN*3eRK*l%YnWLf%&owrs!j9jR^|T0QBIVwF$gG^5}E*b(8-n(Iq}%SqC9UIfIx1?_pNJDQxrru|R_MA{AK@ zNc@DESUR&_`882)dFAeO-a|Z7g@4#)s{gB5I$CRElu^Yk4ZS?>U8w;e8mDSpdkjshoq%S67`k}*R$PnG*_(EifhT6(hps@)4QMytm#78;b(f;NM5 zaDW-?1b+a=6wv`w0k*)(J!9a)z9+7a0DA6d^m%mWVK5^Z7d%*x0`9F>Mi@IdASBl^ z4Fmwk!8O)E;6VUCrI`W0CTCI)y({m%N?cTJPYm0Xx?xP?O(n=TMvH#(U*D=eJ-2_1 zeo&2{y;DuWpO+?>t$1mkz5UgB&@R-ml*o#j1kbr4CXS0OUjw2Hg{vt*BG;j1K=$Ga zRl^psfKlHXyKq?G!Ru+jLjdGyY*6FCEfr!VBpn?9ZZ(_&vJ@GB2Fq~QGcV;#AQ&9` zYn`{Tqcw*3?j;eab_zGQD7E0wV={6Vwoa3QXlHY)Dz?$Isj69Yrg<_r7j|x-$t1j# zqNml#e5kaLtIGTza!~*T;kQr0FQYw)@NdYi@?$F~z9Ai)JUrO4KMGO*$qoNLCeR?t-%<>!rr5))LIqVh5>Z5}GoJqnb z8Jjg8*S0q6kC7oZ{-}4!*cpqhk;?uh>}t#mK{7Db*=d(<-{|#j?KbbnGir&X?P=^> zildd|>+(QY@pD`9{AShj;f=N0Ly}Ehj)t`q0=IE>=mx|Z?gi2nI$-iXFb=W|g_&g( zNca?_+4SRkatfQa5DIgrBQT{&F@$>T^chI#02KeI5VjbY_^uDU`pyn1k{iipN`7P4 zz(JJQnLt{(JeQM6c11MMxZh7|)tbT0R?BJXtWNVVNxpplE^=1zW1%vgk&M_!n_4vQ z50nSe=nXB4>Q)s$5z;3=UieNW#(g_cs08<0MuYQ^6v1_(XkZaIeK0G$3HUqo25b|2 z20mBY5w;%X2;SgY0CQ2{aVRK(sW9O1rDPcp;|T$}sGMmC_{4AW9}qYxVh@KI6ZGeX z&k8qakF>U(Y-)*O(fR@dE+m$Pp-9VGip-cpm)(_d4MC4sbXoYs%0)%=LcEc_xKdGr zTCghXbeA5RecpAQF4R8LfYfTd(k02@w@wi1K0g=AmOdUb3`6}bEzJdNATq@)1oZ=3 zIIge>Q07bGxkwa){6yg20p^iQ*?gxWqIl#m606}QcBrq$MTXDfkdG+4pNhlj06V@vE}Q*j4bP@ zoTkRo;yOnA|By?9B3%Ecax`&Jc%NpMLj--|B)iV?Wp%ve;^;A=W-b0Z}e<0EOJ9wm0}0TBc;Lok41CM-dx z5R1S*Gh7rq6Q_WDh-450gfFlfLIL%H04>DyOvQ&OGKfWl5m=CB;OJ~`3i0qHvwft8 zI)S{BN5{sYde0Y~`@CFw5AkhZQorQWCnW1NBuTEm^JttiGAsIFsA@Qg5JMXnNuWF< z967WYQRSy0oWHJ4Ij_VkKx(N`yI!Ey*gw=+sNWT!0$x~G0^0@HflYhpiQ!jzDiA<} z-3U%Sf>p>n$PLH@a~{#P#P;@BGt%cvDA5;Ndm)J)7uLQ^L5_`haY(qpDA2hCRyD*M>W7d zY%gCd6+5LUZ6BntYPh9P!)f+`|K5cHWy}~b4lx)I_}!%h@AbmIC6F4&*#;RWOXUIt zH28^e_{(IvkBD;=R={!H0ZDMZ!dOXpoRPa+G4J_qI_9&GFyqiWZ}=0ACF<9fxS!+i z3b`A>HEr*hTUc7Dohn&)Y3Z&RRcMCGO4eH!TU@kMV_Sar<3+PIr~9x$!Uu2H zeY^mPVvV|JDYs9~C{Bs^#h@vpE&}DuB2wk3mG}%+5)*`nbAVU_${{d#IS3XUrO6P2 z&$oyib3HYSfS(Ys6=VdJn+_yJOQUq#kjDHrb526U1@_?MME{Eut%)#zG4I|LC9jMn zel&LZo)Qvl>s5x^+ni>joL3n}nH+~hBA`y{PD1ptCdUGr539wMAwZ5TD|Zd!z3cR) zzFNzob`D#y50L&{d!n~@4za30H5hCeGW|TRVk*vHWZV(@8}be)fek2w3IdFSosduh z$KaVF?eJSC=}01XQ9?t~19Sg+j7U0*@DJ2sRU(cRq9diZgilf?aJfJ2p%eF>!u-UL z=&^q4g49zGwZHQ=871$=!lne+Wk^0I&!04Fd7EUe1vAO3Z<^=0JW7EwGYUF`BpsH; zOtBk6{zEPiibzB#8uZ-T6G}rY;@`rL6Zcm2b%6}T22sPEZEa=7aJb`Oa|%jCf~f+g zk>I=_YH*dt5rKpdihx^)9wxfm18jj~V@3u9P*CL;QS)~1bt1TeXQ`te$fx+zl=DP7 z;bY_6$|mr7E`0XWV}ub&rw$dz)cyUZL|6RS_|n<@qvCxmL%P~AJzllyHKSA`wMf<0 zQc3*vYYk8f_?Eq4mTDc9quQs!1(Q#yz;05G&z(1jqQ@WHi-3m!L;%;o&7*@gId+U_ z1@bw6Ct{JpaWKy_;)Cb$%-yUiQjq)<0QA$u1>0@fx7uS(+gtx6?M3Gt(3pHQ^bIa+ z-Fa`1fi<}#8<55FP;17Vg@o03Y7JAu*4s+8)Pk?xS#_(H(gdjJS8ipNO!6qzjBM#( z{@KK!$lM-q5aw@e2XHruI{IuAc%PwOYIf^W4Hh_$l#_`C94D{6PXNuO8ko;B(80D~ z=KxVb04kHgHpn;^UKIQ^E^1v#Z5MO4=~`v4v7XMAUF7%7-%iv&L#WSBJnOw_9)hn{ zUm0G#T3>y%y|nIp&+i`KK3DrMbFOEQ`sZoaiB(lRXd=JMtZ`jHc}@JzlYG`T4RMcl z-9K-3NNoA^Y|OxN%n}OTA{hekqglYEfr{Y)ABLzH5gAb9C@qM*G`CBRVB*dp2(#fL zx>PjAjEpnrBLrgrO;>x8V2BG0wkpOa`@w-Uyepac!)>AY87ei*`q$>1v=l%a;Pk27U0OsXz66m!BGkEguX$emK6aPHg@w}tlewboYD>4hZ5&{^t5*39%d^Z=fk+dHO zwo+1v4>&7L82Wg1MkM z?b?}8->+!pm+&t(gJJ&dZ9kKDhSP_YgGqUKUca|9-K`?JpGe|7SZlR9-kG1j8sF|U z1`7^;%ck+m>^mrnQL#+p3xNx%;UHFuJxVQ=B34QifCUDmMTU3>5|g9}1uz9*19)bk zj+k({-hv69O!Q|S5!|`_74rh@`Q0SsGk{NIKyVG)!pt+O`qDa|Y>n6o6OoO+PwW@H z1iJji$ow(2y)Nq*;alp*zzh8{5O;<_?GHZ5@s-dh?!ZlC(L(GfvM}-hvs)rz9ZqKd zD{d!y@B*+O_$LC4i?oB?GXd5E(vl6y2+$dT3+uUbO2C!m67XnHaU3yMl(1r2kj)45 z%-Fx$WK5S{i7tUFyeCMQAzM@;wL389TOg^tRba`CEG`Q30oXt(gfT>`Li0f-V`T;n z0?(kfW9*8-cxV*H<4IkRJ7AsI!fyt20)8%XUe_vX;U5`Mr)VC3eg3PN(~ zxyGHq1{nD}WO_-3t(<;TquMS80w0lI*w0$zl-Q|LBre9K9$epF76fnYac zPJLi}k+&+GL#%zKJ{w~d;^I=P1s7+KDO|AeHg=*3fT}l_D)$RVnz@Wr;Ylfg4%e># zRD@bAZpPBYFsaw#cZrxWA0y^LT)ImNU9G%a$d4?^5+h<)+!A_C6!La3u2v0C z-oIMTv9c|+?_U|>XjwL`?m`bg(`+@2iBBAoyX}zHL`Uk0iJi%Yj)Vk+R3rWk1S2y+ zZvlS;=zs!Yhe)b{TY%9JAFSFv7?K_biPKkuOBFD7lCjEm5UBER=DIoB<};d(D65R( zBsYT-?LY@X&v=u6(vIUUmYLS!?Y}FBqo?j;%cI-9hQ8vn@6pIVhu0_Te$KQD%(9QJ zKc_yDKPp~uOikWPypW{Gyt;Gs4d3Prh+;elz@=}_QFKp3zN?B8N|N4+Z28fhph%(<6#5{1=G zILsj2)0+*TL{OL-DoBhFq{C7rhl{#k!-U(oM_kO$7*G-NlP|raEpDHM!@cjsR(a{R zrzy4ebSTiAX8fa7)i`&^m#Rw44t}-_Ed*&*NrZlj6Rcps&}=E8B{2vIXX^=4h_R0( zdTK#MV1b-VY4Xj9;keB+eVBF_8{JeIE-HgSjW4=VO0!KQkEk(P@EE@C_;L#%@+hCz zm?=K*HA78AkEvS6NIKl)$JC;vwaj2x(5$9NW*37K88#V(?z}Y_7HGB*Qf8)6SjTSM zl3etkL-Q?d)BlFtdT&o;J~7x=nIEe~6@>XW45$st4LApHUtUR6yBON@8sAekvi^=D z;^re08i@yMq#z(Na4;c75$&gSA#-v=+XO;K_C>)^@yJ4AE@YrWIIafgYSKPVfK_V5 z4W#^ie?{n~m~j^d@a~ne_;>l4R)zjR~u-pYeu z39oRyl7nOcfEO{NM6D&9&ulqb+#GPbGamjU=3C8tN(+>LyGRvjVpe@}Qzo z!2d)p8GvxYCJMhsYLbtZM&(1}fLE9d#4?wa1H4W3H^E!EGR9&f$T1bF3kB}ljx_c` zBY99xhA#mYX6IN^ggrV0KrT2aFIX3E9!QM?U>FVGB7p+9XXAF!`M30~AaLH#{^re^ zImhNgL`U>0`$QC5GvCbG^X19ci9-cT#CfOW+GuH$zAf564XX}Yc9J_I?(aXiPPulll zO#iq)))x&YaEMIcI1K`H+)f4T034mh9FbpW(-Nf=_!(`Y;FF1J$f*ZY6bH0nuwe9z z@m2$!N~alYnqpjLzrYck&bj`aj(O=SkMgx3a|#Cxo+9ScNHkVp*?@NO?1ito+-R+3 zn02O1#6*O_w(q-7dC$dj*6KxS!yiObm@2bNy}+!RK}afkV0FNy2ncM4h=(Ui4z9(- zL+HW(bj?Me&%0Yg1q~+e8R!luDyufu#q&}pdI~;Sppe3JfV_4q#)ZtWA$c5N`zj!Py4?PO}D)Be9;CTgO z`GKVzhwpeZVS%@>xZ|%7-;2LT9?P%rj>p2@Z7~I0ahCpYlnD@=SI;$#f>7_j{y6Ok z2k}E;7}NlqjEf3Dh93mLsF2-+Qhqit9?F`{_T&;|8;35rD}T>!UNUFqw^#DTjjYv1tI?vYGTF%)l;DkupmxKPCyiv)X$6Yq4S`)^Go2q% z{zEPXfG|byKkrg_;G4)<@MD{aBVn3{0eyubqASs@$VH@)Ef31g<{z<%d*JXe(a~+< zxo`meOjoh5==Xs&Sh&Mt{o(qoH5pSKLO@}gTRR)L@>Ttu(T8lLh>)MNuD`2vUEQck zOXK@Rr!{AIQieMzSW!eM1+k1bPPs{A= ziV>LK74j(7UoBkkY)IP-ZeFRuI# zxkLaWmWoKw8tG+BA2F3L6Tcec83N{(d?XbzRlrZ-w0Jj853q6mT0!P)<6J-`EnFCo z1j5UahRO}e;~K#hNIC~Y;mARup%S5pwy!q<05mgBhyIz7I}ylvHEk2nBDm&n>Z=skr4=Xu<@9eahjRg z@4q#)xkdaiVdEKn0q-cdg?A{szQc<&6sIGVsZi9=o*!bPLh`X#!gG3(QkH0Q|VUd`^K98t>XXWFYG2U2-m z)6E~)mU-Z@HnBs&{5H(=sg7~dBK`DGhBS17x3b7`I;%I%N{cO93N>eDqZQ2sI4=BpDP&%O>*w zx3EGHaa=@#8pvFNX+Tt-3j8>KRS_^J&Dm=5XC6Awop261$E!SC8Z;6V5BE(0FXfj@lQ`Fj7+9uN-De@3~RrcGlT8yYZAcYcaRqRqi)2 zAtCKHcgE9BLy(<4@*}xGv}OSwK_^dUI|mV*yT=4R*O{VvtD;aa3m7etu+WOiNp$!R zxdbQz6Lv3r21j4i1&GQy-vPT)5dqWO5)}_=E8r(xy5E>(3^hfH68C;?pqv2u$E^1_ zChvcLAzWG%7&kWlopzUbp!=ZR3}^Cw_3R{P%Zsf>))poDXG|>U2NnDfKr6 zS}N-ehF@$y{oH*=({Gr)?Efj7>+#0F!{Kxa(n+Q@*?ohV*D;mhvH8#tN;|X9fO1%g z0uM9fnzVuwRhXBML>;zqLPAXhu8Y)g5cSNJ5JKcRP~#)9>BL@TDqfjR{dpyn9lI#* zA2A=BI@KP{a$NbI&W@f-`9&UTPm2~m47|R+Usmv>uy6ad$rU?2Ty^E>>DT_-oM%Ei zk>GEIt>Zo+pFdZ})``%VAzQ~=Ea3kOUvNeeF9OBkgD3D=uC9A(ctt#T2?bpW>)i63WPGh-b3t3ZQ)6Fc56hXV z5>{<>zq;-F^=Uc|r&xY#^X!C)#in=&8?S*V%F$1bcmd`tE1>Y1n>r>b7u{F+{0j_75`2}#c3Qa0a3AW&7Cmy zAs2MO$AK4t3+%ZH1Hl7E5P*O|>3I5ihFJBRY*~C|5>i2hYmHG(%o4Sx@^MYODfg7( z;E>`fow9_Eh#ZN)lj4Uy71smBDXYB-lGWiQ>PGF2?Qzhk?CrT@DQz1w4sFmgh=R8= z{=HsYQMJ6<8sA?E1l-q^F1m%{`cH`xBlf>moZ>t_slUw?64@+ttYZ-vUEuyh?k)O2 z<0%3kN9K}SVFhq6a8MNy0Af1tj!9SKiY`XC;=&l!Y05*A4lq!F8Au3l0Jx}tl$OyL z_=L`K!qLnR>KYAy^YWMj3a9kdJLla)Z2u7ndLBQpDhlXXehuacfj~g~;)yFR(#ElB zeyu)YF`Z*1C47xOH(#GP75jgkeXXDKKHVu^GIh{-iP7>*t5gHP0chYX@D+?!oEj+mx z6)OaWO$W;mP#~e1lnGFfMj8>tRw*V&cyFU$T=RAb%|1#o{`;CmPtT*vBPdlmuXe(r ze_=MOHZv=0qgKZG6r&rrYvC+^$Uf+Vxhvrq!BMmBcr z*>>v{l>~P45sBDgH52~!#M2JRZP|Q88Px#azy-*yLptti_g6x= zaf#5a4=BjJ;(;2oCE;%+v6TIXrYgBmHf)p%32Gz@@r}K7S3+{SrTj0%4Ud~w6&HL< zem8e8TfXkW#;eNysaji$no7nL0i1mK)r8$eo?4V6^ONNFxN70+6EX1?R1SRLG3Gzy zvZ06=jw0|?WG;C)Edb{o2Mw{008APCzKjtnxaH^;O6k{KC%J}|fEKeE)j;SD4G^MR zBsRoGn-OJY=A=?XC*#tdxX6e@jx)<3LVg6#h9?0>XK;Uw7M94V24elyIn$=4$?Z_i zQlbf*Xcjwi@WneI%SbXxw?tp4;I*CqzN%7n6~c6#&`zSr#4$BD9qGOh*~bJr#k^xS z?{d-Rb6C5P8KuEj3mshK<_rg*;qT3Pn1^U=I{TS7)nPXCk%Us?0+3k0f)Wlv6)wT69##VJ40U7n$|f63SqfJ>;y4ry4CcAy({mN8?w^Gx zV5=NGz%C?g!VZWm&jcGI5Y@lR+^QEs)xu+m--7WK@LNFiv@C#%&tm&{n3c8g$FMN7 z;ilSQ((}{iUG`mi2T7^3&q%Gu#p2#2?{#kq`H~LjAVa~%PH^!P z2k)tg@yBdIBtfEkB6@rNGChPe5`=S?46yjo2evAjll5ynbEc(Y$xZJ2N7=`hGRy?u zb4y;~O}winii~d&?^~;XI1GG0SKol`yFzu zV~K5^e%*_laPGph@j~I`F5B-70p!&G(;!GeKuu<}c){!!NMAmsm50{R8pD zWyzM|yECpv`lM@GZX7I|b@UaJUtL_ax?i!=h3?EQ%wVN}zCkH*^mP{cwCUx^Ok(i8 zKb`(BYFpJy=1Q`Zx$_}BXn5@;A@|o^_ogEs!)KoZYrHT%>hop)uS)}cCEZ)P#-FE4CVi7OrB1)k zA?d?HN@m1VL-NxOT?2nSAh(aerrFzulTkEhM=a z?UX#fZE6^z!2Bq{ada{O1SH}qDVuziJeCL~V=8y5Txt<>7FM#J@LLMnX8Yp;@98%K zWw|=xQoZ59&OA|f!`F+Qd9v#&_l|$om_>xcXcyLn4pk=l7?(*2@AVRWT@MO~j_>hp zP4af{qF&yGICEZpN7GI0x7pRKRC6g-uuxf`{3@wvZ<4Z}$b_Nam6`YxSSXsk1HuFdFQ~*eIw(o1>ji3IZoMs*1S8p}~1jCkRM| zr4J8%HvC?DuAv!m!8Vm7AuLeJ=zVGtEwDb+y4WI;F^v^T;WC}bN7K>9>b%%znu$Ag z`D@L^pobLOnn+N!eUw6iA$Re;88~f&{Du?up_#g6LFCJ{xixP&f7?+-o@m{6K2qBz zaY;%_WUxzwx3>keP-U-u6)q%%QX_Tg8uTI{vK&mnWUAV3NVTr9$0I4h+9%YqYeYmmqtVVqBCD3Y9~gELBZ!z$iGJu)VV>uM<&M6W(_AvpZnWS&bf_at;8|N=okF$ zLkWd7vxSw!fZ<3=6SfTpb7RROVQ5U!F)*by9oHy}i**ML{CgC0dAl3y%`9}$Xe^kU zlRkD@N7|~P{f>^0WVj;f#!y{onvw$~By~j)$mNBN16Ni{oQ9AlLiobV5Vr`;_TVbB z7)ZZX5k1i6HrTTgTqr6toOdrv8flB?mSxHh71CFms#VOPK&Z6XkjB)toeSfLEo+aFD?I0uM<5YEK8C?f!(A-pF{qRWsasy9S>G-t30-<{}ZM<$(D-JC| zd8s7x^S2- z2649sT?%H^AAFIgxZ0GbBDCzF$Ro1$p^ zR17yy2xQ6OJR)Ov1HlWbXv-KMKO$U1%mE@1d;=l0g)@n*;lV@oz?5iZ!p+MADf4E#?Zip(?eo?O8-j5YwpG8T3VroSd&U&;kN2~2F_hmd2$FFxI*a7(_u3_r zZmLTto=bf0$=T?cQ0AHMUyjJPGu*DqN-~M8rN+|JV%OhGakD@52oa=eQ;N_PO8~>-uMDCCUITE zyi0tru)5vXMGO_1n(N?TWB>=Zgd41NhuIiDsgq!D>O|}t(eK)p)ffqpyHZ`Zkt4^h zgQq16EkfVc*KWV`)7VY>E(ynv?xr;CQ^z*)%!!1O$~2%t=^EU!vJ7#+mFc&QNcA}w4Rpk9{adVi#<)cEQ=nN zP%*T=pSM>jP|0tvN?=OyIas}y!g=qS5QL?N&N3I*NA{}dcCk$lUK<|ivkoRSo* z)09gGi&EuNN|lUBT|&AGH=6Rk{zb$*mV=0F5FMX{Jn|ekB{2S;flo}bDNX2-uKk&UUWhD+2LnVCMLXG zq3yLb8F9%UGfXi0w@zpZ)(~`SoN!>I>3?K{2;RwwdDTf*E8CzM1r%A`6H>tcPEPgu zX|b2MlULz6P*|l%cehZGBll3D2Z>b^p1XfnPr%uskR;2^buA<_ic&K(x<4dyT}Qi- z)ry;4Lpf$&M}x(v8T@;o|9d!a+KuL>q=Z@cGnn}yYo|u#*{_Q>S&t5L`J5=!f;=z<2ajNb(yP*h=4jaF`Y4xa#&I`6w9Wp z!tkhqV+4U|a^Ahru1JunK#`6#Qp0Hc{3thQS?xMekJ&ITu3syKDVv<*ib zTf#lp%5AT8WY(RA%Em!9;n;v0FRs2q76Y~M880Uk?J7iT&{EdVmu}sA#O2uMm-O3qxT7?TQXXA&5pYYA7dX!_}Dd>;ID zHtTETbF{@q4& zA3sLEM8MR1@#p2O@#$|F-L>%c_pVI8BXWUnYW2mu8ZsAdx{xl?yT4ewfuFvNP$<(* zP&-i5tQqzY5)OC^sM`_79<*62|2ATzDNO`8C$jQ)Jj!S>$ozwavX0I&nj41l(FCSM z^8fBWGyaPouV!PxDT}|!XQrZ>!Kh;TMV;wHc4?>tW7=?DPnIFQyr9gQA<~^q?;1DI zo&dhw9R0i83NKH_eo2-6SyJY6G``V(xlyR-#?}|7urR)#&lwG|N*rcZwW?K|Ts9Q2 z;5K1?b}_ChT@U zE{vEt5ShZcqgN%tCr8$tcXRk3su=pEXwp~Gh3*9?M}O=)C_rE?9{d5frXMEGQndM| zJ>BQ4K=CX}{~;FxMc9w|9Q3xZX4W43u{L#3r{sUZ$h9A{?f>4}7~PscpdNyPjHR*B zA&GF%JEdg|qm-SqyZO?Y|Ib`x$rhcVR+Vld5N3sNma*AN)=rY1tc7Z|;I&V1Zkox< z9(LwxqTNcMM5G8ycuGCnm=8QD}EU@>KNsV z#8OE-@Frbfo??5?~0Yf~rox}x~}G#R&!4cjBshWy%wgY;{9!J5{)T3VRh z)-0?SA<~tb)vPu?n3zuiu-kG0HULabAnw8t<0e-$I#1(m`prY3H}9F4*mQN$iwBg| z@gEvWE>c&o>em>x9`$Ip%P|Iv_j#-v3oEVLtKE5MFq7f&a54hFcn=X@A;Fwd$q|&bh6UI$ilzk8>lp6kUM%={7C&Z$n`kO*>v25{D)JI$9!|nFF z7zLSY52L_)6@Rmy&*K1dwoTkR_;3=AV*b?%SgNA&amf#aA1aO9B2mcUOK$W<9WwhF z-V}JgjoPdg@soyiH?p#kBsjxJ?;GBER4Z7BhOwMl25Mvy$qN=a>+WNZeK=09xB8B# z(`ny3;BusAc1fM6uHToH5sQ&NMxHxHUYW*4vq&&65|vKJp#LHL#GZrWh=U_Jv$E(5 zo!XNA$`>s2E6AU+U@C4|W^4pTvtTOK_=du0&ozu{`QJUG>vxk%|FW|MDR7i+JL7S9 zD93Fr*X{P7et&LYpxNc^>@ue@AGQ}syS9`Ea5{Dh0elzYf>Da{W}> zz%jZ(oCLbW>Q8+GRM`;ynHLEE^c(n zDsXT6DLS$%`>O?XdO;Dnv1*pI`idk+9mj~A-*Ci2vMM;6*{nWWr|6+|MM|!Wsw{+P znoqn{WzDT03Y7`YnM>qF%Z!}b3?T>$I}xbN4!pYehlK>B$s=)~wiw1VVEA=g^bF$V zFgu0dVN1|XOS<7Ng#Hv4pqaD!X8r(saP{QZ-}@6jwN&Eo77wb7$fcET=#JawsG5YS zb_GmMO@^!5VYp5gnlET;B?=c1mJlW>fU;G#&UcmK(SAmj0J!;O=3q)v3NmD6p3st%6F*|Xz z`pq?ZyhADe)DJ7Zh|4sC8*r$8?%^%TjLWjQQd`|dlF52Kq}wZgPclya*?TBq`tRvT;@j8QDQWC9#*RIX1-+WaW<(9qcd2O!_-5v>o-8A>#21qne+f`SSF| z#F0^YKXi0)>??P%`G0mfKPUpei3mIrnNwo?`#;w34$2C%Ky*6WK=tA8y@eR9C~cB) zMu875gkt6KZMD@-r=hKz_yk6j7I36te>-W^0<;Tzp(C}-{`75RG$6*~l+Aiy*4ClR z)y;O;Tzh2e2ND*&6oE}wIXzv{c!NR<&A{r!Z!6Ieyrn9+Z*2ypWj9geT7h3F-)NnDJ5rT})mq1yS)=702X_4dH z2x--F#i^nV+p4}lEPEL#AeqAFJ^GW^^1(u*kkJQ8;U`fIR~7U+cSDIL7PS_ zuVO=x9Rh%N97e2KTKkxHv3<=jURh4fTTQLTn2?^h+wGvvkd)lZF5MA5GW%m+AjC z+iKfvx7oIh&9+^4wl~|hZFBQx+qUb@*3*7o-{&v5ewk~|nK|doTTE5`0P~Q}9$S>^ zFjOP5G2YeHho2+_^5jPV?Og!UY4M?~@e$;M*o2&;`*yfIK$2J}LBw;PEd(2ljJqtp zpKL|sJ@_~BPg(Hr{aG5DIo}aNCOpk?#rBPf>c_9R@zQt;-yLb$Y=^;qbX%3K9O_o z?e8G5C}4&mjXX}8ae~}kn2@{Cq@Hd?HEy(BDO$CkphvVH)U4J|QK}ZSigW50oS|#& zIMQu8?o&y0oO%1Ek9tC)`$BFG;p|MrAsr#_e~N!--#Zcf&aQ&Is3sSIH8bfT zjDiME5GT!70iHy*?+e+Q7koOnX>I~ueVo)7)cmYH-0p$!Ma zDjLMo%$}j37FA;u6#}~3I6c|It*FH%fOM{8%6I{TJT~*p-Envv2@A{kbJJfWJh4zv z)`Xdq$#gocPl;6!oko~#45zB@zul!k5b!8>{s1W)2cHp05Cbr6c|v>;SOUv%luCkc@lma#8jeV7^i$)F zl{T39E;x*q(~=$yN2Ipqmip^52u6py`DN|}_$sbVyV07LNfB{kL0Uq0)WXrvd@~}mqxO2>jWiFq2Od!$7zCJq8;UuUTb%(1aRwdkO z;xzH|k5J zKM@EqhBa~fMxr;M{~a?7o)mn%>N)|`fA|Ep%%#X~i67mhv6@lAPlasVNQw^)U4hP# z%)En5m_4rn^H$+7hdi)QQ|0F={xfd0S3gZ_r_>>z;B@dUUkOce^Z9FJX=`{4zw6{> zby_RC273~p?ZX9M&K$74y+=<>KSl(e{6jYx=d*IUdbHO!kOF`vu{_~M^0-k#&ess% zsztu=!`fK(+MkPT;p@=64AZ_%s>ogKThd_}iNeKnY#%ULM%jf3%{mBy5@LWk_B4J3 z)U`xCPsddDY2=CtO|Y?RA-Ib)&?#P#!p*d@ zB&`n`YqdZ?IrJaP<@kbsZ2|^BF*{_<{@DJitEe+~FR-Z-qx|guv79)P8;|esVazqV zriT_$=x~qSu85*Iy5tPd4?SB;EoD|BoFkUfGxF@`+%cD(Bo~blS;j?Y{eyNpwM~AV zA)R^{himVli8W-3bukQacvUC2=6RNd(hne@jFjbo3J{s>9LOXjELj#8<(V;C0HMFl1+_Ffz~FB@}vN)99@4Z_}-?KKF4!A*v_!F zU=j)($lL&5q{9*`*4ng0@VAK~To$QDBS=Lr^zG8-rbdYzYgJ@#q68j8?ZOE{+n=1s z5~&T5bbKKp3q7-JBa?+9p*_kAuqP;SvFc{bXEYJ;R{`Ejq;9Y)m`~vs4Xa0ZI7ncc zVrkhT#=kZUnsNVXbPpe11*4@AX%gZBYA>=(yAN4@zU#r&#wpLQ4$9T+ z7}7wO9*G7F5Q?#yLrC2UyLde^ug!m*>Wddv7^&yWnu?AsX?iryVsj(m^~KS!dEL`)+tChR z=kiQaHzc9~+Wom}O8YvoCi^Q1le^>6Z!u_N=N zpe$LGa2gK87!41h6&h(L!}`h~4H;@f<3hiy+b2q(uxkpA%xI}4B ztCmc>N4(TZ9mES0gZ)(lKC$akZ*93&&vPLyx+>jTwOdVvoAb6*q_vb%>eKulwZ36C z?(+Mx^Ofg((B+f=(qZAPLkD##^)bfz0bo$fZN<9Tz%6F;{F(mV()a$lk$%w~JmsU; zV$1dVlJhY6G!gyQoIdf;hlJS2VuYno06s!M`K!Iz2qgX0ty1iZk?0JNr&qPenp)l^VUN*sf2E3C}2jL4ZrH!582-fMW;&klJ_S)?>+ z6i-c+2#Tinyf#CdnSv6VxbDk;h1dh&*RvRLIy>9BVy9c%wm)rs26@pO{Hyih> zyV>u+p?@sr1p=O<%MV7z?2r^rzHLILD>wY~@zu-uOB3J=Cg$1GFNu#5xkg~|hEtz} zsB%{FG*wH=JM)x1~^G`+sf8ZP0*Wr9Sz<52x0Be8BTuM zn^4Nr>2F_o;ki{YmuiZ^H#f6=w~T+%#Y@T4 z)Xoq&V&r4L)gykD0y61+257Nsdj7b_?rc#X!shR!Z}srIo3{O=-qC94RH=y-DEeKJ zZU~R}H_sqCF+aS&w9Lt>UI9zhAj%Tk^F;(MBkVTylKDErvQi|C3m6(CkqM560du(XNJ6waHpSJk+;ko#ynZCHMMk+VpU| zPBCH5?@9>pZWx55ij-H@lAvz({FAU4d=z`&VXvjSEXF?XZ}EmS!vR%w&*Yv-`4nlX zIN5A)z(WM4u!f0d5_Wlm_N>o}Qz`_qdlVNV#goDvN!$ErGRHWLwMEKi;|pnA#fTs& z9Fk1@Ve`O@DYni+`^s8W3bm`xf!)c&Xj(-PcbDGv@Sm z=5)&;4}F^`<#G@yr3!A8U4-H58;nD2mB?pH3_5luq<3Q6X5ILYAFw-{fEYCzBy28#XYjvYYo6uCrKq?e&# z_FO)(sP%cRHDOKfNZb4fQ{H6h-Pv^m+b<1mQAi#NJgOi( zQ*Hu!4hwohu9M? zEUB_n(=FbQ{|>xDe8B}c`2wJrcGDFwroT)Q1<3IiSW=j9jdFa!z%=(MDTIUC%xLqn zH8}42?Ue(HKU0*I{870*eVtek@mk1}^?!5S4!*-&C>s{$CL+$j;s&CmOA~iQ1Yyqy zBM)<@va}3wisFO1Hg1=hyoQ#wHQ6Mq5E50eAwkNC1jeL0Z1Gv1m?lJ-BwTCzRUl4G zvxhe2TC8u>d2h$~mAZhj*DUD1Zf>1FWnDHZ@wV5{^d~$1aNQWfvwk&!$E266 zR9{agc~?jM1t% zgffUNjQwP}VO9=G8H%f-T%m2D=(vbXgL+7yI~@*h)%;#hSTu1g*r&;2oX2d~J{p#ZS5$nQ7kx7r(LvNCpNk z_S$A6w&hJzL?iIfi3P^v;)qq`XVKy?1%!MR*O=35*+vxIC(JD5o7N24C7klXF)2v6 zNd-2E;asyaX?>BxB)b{5jtOqyFT4>NJ$P?b~%( zsafBIVPqeTr9d4D+wNlVAwOKCDiEQtqat@ZxZcR;!;m;eC%_?7MNh;F#brd8w?x+C z%h%n-Z;*tuK;-9<^UOBW)NIf`d6w*xKKTu#ff%F%4?&n8VThhA&` zY#qvWx~xHy_PIRxmN^J&3an?*ape1#L^9xz=-QGCI6qbr2w;<` zTFE4FA;i*7=QrA`A5&1a1u56$!GqiomzOFEsjMs*#H_+PMae7%>+{f=Ec(5J;b)m; z=|`R+9)u6zhh{v}irJGUOOR>bPd7B)09#uz(C|?C#_nEN6%(fBV<^%QS-vGVn=A&` zIf(k{C-yO*8hkYZKYGi3a?*rHYfJMMzV{+}DlJC%OV*o&%l#}gS1bsUtG{9x9b9 z{(jEK&asYd4;gx#9sF(3=&G`Iy<8I4Tu7K!2vC-dJ0gRi}t@A*|Ivk$u0KK<@TKOZaJT56&`zurEezx;G6(YXBWwzcnId;3^s zqxkUD*{7l*LK0wznpjT}R8Ig)h>t{M96-RQPXnQZ2#rqVeyrZeVIF~9h*4SLrJhD4 zQPtE0dr}|utqJt!^1he?VsGfiba+9ZnweV&SAv-?R;27q+5|j`;=5A$qEiHMc{11C z?6Ams6guHEJ=I!X?1Vc9WXOr@?ecr(1bV(2=1hKdb5my{!)e@ zm$qeYx#~6vln{Z5pJA=}=%NNJg7Zq%zE%aHlqxf$d9}qlby??x=z6@7M-q)mpX%+R z0{#@9f2_c-O=3|Y{r<)}nFYzf)iPYku%v;i=YMO;`Mpd7#v=b3F@HLgOF&W68Zr&u zCVzT&njZpFN+_b-n&h;EP6(mxMk*_8K#Dknc|prZ9Tmh|RE;AfSHhw0w34#xY(Xn# zn&$#s9oNu5mM|GmD2_^q$WKUlZBedD(q=)meU-kqpX;cy<=={u{VN*_)pW@gKsu4i zfClv~93+Gx8Xc?-nM%H((oRuZqe2T(o;p%7eV>*V6|B6FMmwkrOmfmTGIK)@bJzkE4K`Cy2lzXrkDD3pa?kh318%=lutG<#_>v^Evv zz(TQI{Q?q6XkUuRGzY`w8A0(i%EAuvh#FF)0&_23v)R(T;Ql^DwtR4Air|0)aIh1I zTFM?o?rc+W(FjU+m{#?6Qgs8z$ptbI9O=t@Rcw;^%QPXA!>+LX=fVk^@$s;#j&Xc) z>(7^%IuvjAqve%v4T?V8->JMObGQ=JpG~&lZ5XaH(;*usG$*% zD89;T;009TfxpW8lo-N1gw6aiG&!ZEtuwfpZAs5MXNJt{;B;M>WUIn9avJtpR}h$- z0z97+oZcVOvm(hLf>O2cwHj?{e>xxxdH+y4l^HMe`W(^p;`JxR^o!p*3;3_}YsAF<4c}$TrTdvABf3HjV$`rJE?{PAYFC#qC8^(PIOpUEBqAr} z=stuo6aV- zWzu2r9Q{7ptK6~o>Wk;F?$W$E2VAFz>8Mqps0dBjjXB}>AQJE&5_9`hEGKg`f6fe@ ziK|tU$_NQ=vZ85EEu22>Z+1!pc{Ynybs~Q!ak~9!ccmsO>Dr=NV&6l*%9}lM8)$ERm{lnw6*@l&p3&rgLnnqvJxu z;fO$}ma@VwPC|G2mF(|7$Yq0opDJ~NeX(4WS;=1mGHs;D?FU$fv2e+Xe}%Pm=89m% zY(BH>yI~6gT#ocx4&TaQjmgWwLKbFH%B38|;H(5E>SN+Xku~}r`MC;vsOQ$LMl<(| zZbLJBWu|tTH?fKETc0T`nt(u+#mxmu_3B4Wz4m1qX5$+cGjM3nu~4LD;>PP^7xl%* z)WA9YGj-#=(fV2Sw&XZ+CxY$gE20Tx_^nPul2us}EHbUrSD&Fp6c~r~H3DAK&PyJS z5Oo{sr9jLO(=o+SnN)pO!O=N|GI(~?x8FP_K74qZbA$rC;X2fUgBWMpsJgCD1bR}e5F#Lo2 z<@)>RCon*iW%HVOJJWa^YIgzfFrR#0QZZC%<8%30V)g!M{A%b!%ztF7Bp|!S5eB_a zOuH%}ebtHl1W(F`4`sYt=TsiMKkugy7K805CMpS3;b8Y3O8^=-#_hMF)b8%HYjQ-J zFRwv?9I4lhj~b$yQ6&77q*D5+-_8_TfLMp7M7kmQ^|;fo&cOr)WlhaVpy;oxN;O9D z12HE@YbPzvWWzgi*cQ=(rWU5=UA4DTQ#qCLa@AKX)u?=mqRg{PhCfTSBW-=V@`^a2 zO{!gaWud2t1LBOK?brW38kg$}?#|2WcaFWATT_y25M-nLJbwerU_F{Zg(n!2=kBWK zx`_ue=BHj~ff8_oJj-;`RSj)z5)wSAO9cm^J66l*)XZ_4YdPPkSq!k#f;Rl&uV4cX z!C){z;qNJxdU|DQ5CpD}iVbDL83rv|O>U>VUs0dhhp%#b%oPsv9WgA6Jt+-_l}$}l zW@j>OwYi>^&Q>qbVgPo-_0Ldk@?aJd!S^3vfF2|W2 zo!3ssamG(NJO zS`epFE#_*f`twR`Wi4}L3|fd(el%*5S7Tx9F0n-KB~kR@Q`1*g#pHDfV!`0jP+h%Uos-YjT zEu0L|sl0fv>Cy2u{cgQXE73J)A`fXhy1*9i^peYGgD$M6A6_ZHqwF%6yrOJHPf-KI zV%dexzurCZWlYZJDzU$K9_5=5!L ziKL`e2$!7=&h;aCxqv8}vaBf$ck?##6V77j5@GeadyAiSR;HiyHxOF~>*-qU800D& z^d+T}tdlj-mE8jIm46n`>Awj6uiT{yFQ61_hYth##P_Whz=RL%$K_RmuuCRVTKi~q7z^y-xFOQIG6OXXP7C@U`>eWRrLty> z@j4u0A@_B|+B*LAjeT;*-sITb0Tfdz$Jk#iL?Lv#$iK2fDK^rEIHxpfv{v?tS5A)D z29}dPR#|!r1##)pFv=lyr_J;G2&>;_PzxcB)XDdpjc(;r-i$zeT-n# z(cvNh3|5r%#(@SjXfbvYHs#8S9P;pD`n|L)m#7>k1yt;5AC(@|Pu=x%nxn6Ihz){{Uq8G~Vy1kUBlaF+LUe_{ippCo$tmqC~%Llk)-I}+oZ%b1u zFT0Z=!9ytWQ6r~91;p#~Cvnq*w>I|M-FD?(vOUm0T~iCahWtoc(>*dH1DQN0BkI|K6oB za9=-icSCIgwNlRduI&|L;BW_Gfn^m2e&7b{Fo~eze*RXH`RZ6RS3 zwlkB0)x2spv!_*$oo9Sr^w|X^ENO$hXG>Q_Z3CD9caF7R-J-U*F@;7OCGryMeQ!qH zth7=e zhjMHdqXpSh9RyMh+$<)UQ)!J;s~_i>RFKhrvoKl7$igE$2%(0iq?GPRx?P-` z&cG%WQ&)&v>r_h=?Qep5-ufv7K-!%A)lJ3S)q8{&o{{7ivyOD%-f@|LELL=`U0Tg zp=`|iwWG{#PP6Tq8rAj8AG<&C=T_iCg7vHyugtyAuFa_N<-ON$+V`~X`SypJ2Kl2o zeBfRU3FG%x>o8cTaXW!5en5q@1vfwkXYD?FLAlYL0>gzCM)Sr#k~EH*osJ>(HFv;X3FfCrjBI&exA>uEZ*7~n ze8GX52w$?v{_n!Y&#q~cPqV!rANIXzHse37d3lYLZl}tV`5~u-$3I&~kyVR%G^KzE zC)_x$#|XkbDI!sEX#sRAdyF~vjz-4ThOQMAHd}Df)A+o0_Tx48E<^421<^(w>(abb zoKv9;{tpSSX-eN&PTcLI6mO|BT>}RcSe=`dC5zQT>=Ouz7v9>d@ zkDgA#h(T`yI6h68(wO3tNPG??NH9lDafLkBSY|1;v)RRD22uUin|=sJ<`wZxlKItx zCmQbn9ipO==RET=B+3m_$bc1|DH@czw?|o>8}vu$1oRXv#*;2#O%c*QgbwoQ-!%Nz zE$y522B{5(?u6MJwD3^=io)0bVPN{s)P0HOy2x=b@ z1};BcRvoLh_W1Q)kG3`t?*0o3j`al}65#!I$+R0Xq*iMXpsh6HeFMv5JxY(N+Y?Mm ziOcK+7)Hc-v2Nh>YROK!3gZK>+}5K*Ef`s{BTB^OG%FwHRTGk3gS}4AXX6V(W>w$P zRL97!pV%MgXtuS7SVZ(A4nwr6+!u-~RRFhz{iW#i+d};iy3%ugqB01Z38#*hQ_-U* zdyx}1_K@n#kwa86=b5{5xHZ-XjozRqvt|z5jjb-06#y^s@=I|8+5_f!X1S=SC76DD z(}!5D{UX{t8wtrgc~M|dnOB+kMw=KFB$dlq+F3&-G%{ZV2AxO6s7`V*z(J@3q6Ayl z(Fxa{lcEdjM%rx>=&XgFlZ!kpq&y!T5e+go06-TCGh3d|-`!C|S$A2gx{`tE2d>zA zd3NJ?plyl>^K7ZwcA6f;J$0`!1G}3)*^Qjl+WdXSg`PJWwxoltSd$q-Mi7M%l@s8W zU5LPENj$y+FLMRC{4Awek>;Q^6pEDm-)o93kri%n6pq>Fa%RXVwh4y@Yfu~MDnuco zN{NFhp4|ZHl@=oF-5)j9Jbmyn*_~*7E%$Rq`vFGh$B z2bE65(+y`Ew1^VUfb1_fsMajNgLV90LP_7cbb)zz;MoGtnP1Z$qnk642}8zl$uyMO9|Jsr>Q%Oe>_ zi|_uU4Keu;NIbGZ!Pk{xigY0(-a|!NIRFxSzB{-jMeM(Zaj=!1F-L&a_3Y@NhKRRCS&oS9?DO!$otkwXT1?SPLJV{AL89(8 zD3S?Xe~P19m2sT7Sj17}fBB^HX(84_RU9u|YBW1No_7P`IYqH7N>vD4R z^!MZ75B`^B4(_>~@Oi9)+?8*5RG8JjIU4srFa_@I(zKb(NqP{;7vvKyJ2RFrj^b zc8hjA%ANM<`b?v8ea6&F( zS1eKOqYY&v#yFL1X2*dNemv?k>C1(svB8m;@K`@V&SRn;tb&r&>Dh1gU=Wg?;Sw;#nMni!*_iFig)@C^&*_?=Q4=j@2keC#Z*?A5H`oB z;-nw+x6`dTm8#_raf-Dr?0N}dTO7V!qigM+7?nJUG)l2|{IJo88Bl~*!{asVcmGi4DU|gp6AC9>rVgu-_)?ME1bYGNROEL9v|hvGw429_@E=j-a1*AhU$II>V6oZ77_`ah$PoRG|Q2th?a& z8ds*cnj(++#ajj&Dtc%R-wt#KNMtB3fh&m_C2PBdLRqJSgOSnQU-ZzZBGU&1py6fe z#Yv-zKhzu6TOZ`m6yUze(B%!Af}GZv$To4Ni1d|Kiz|0rQw@dJ7MNZ8OO177(7$)i zsYXR(Rp}#|7DNgO5i1C(zD-bS~|6VY~(7E4RxcCM_hC$Si3fHY6g*t6U zv?%}UFY7dxJuoS|dZmKeAS<=MY@lb+VpN&^(VXD`gK*SSPr|LOM2dygu5`>KsXT=J zdm^U-iRj|@(?2U!z0pX^B@HakUgC(am##QN?ng`Ed0^$WF3S3nIN#viYJ`o^4{>#- zlCo37U9l?#zb{Hc<}+fYXr>o+P3T~Dk66uMkVI89Sr<1yC&aIhpZvIfIgs2*f$CkA z!O!lqQw^_xwl9bgIIZ!YT`n8Js;Bho~nG7@;=>jBZv14cQO7sa0#k*0ghW5gW zEC+WKYmB|l8sdoFVo;Nco^$(U*-lEX&f1pbzgYMESa|37B*)rpKLxLwS#M5#Qm#zl zgKMW(Zo(>k)iBuH|3Li$U*jChe3e&jsWDhWdIT@-R@UtXV5#+`<~H5`GUR{RHtC$V zs@1JfHehKyv=gY+e9TErgd)kppp!%oOViITDVWKhV+Cu7NRFRlRnO4A5u03R2!hXW zO+OXtBRC~YkPap`cIq0&n;LCtEIhC|8TN8y9`iJ#ZLnRN@9gfpNRi#3|J@7_T6qL? zm6O#cas1G{+SQXeJ`njv^Z|uRJU4poMUCd!PE^10TX)p9ji|< zx({9}UcA?c*^a_kHltG$roHIVk_vS*&>xJ}00#5IkX zvBdhW^p2VQTfQ~$jNUrwZL;L?DK;`9=xmu?^X%Kg`{yj`+5Po^$LC%6ffxNB*?HM& zJpUI^%w`a1(sAkWBaz6$tnUUgBj$!&CU9D&Tr%E3%We%0L)J>hzifzMOY(o6C<65m zCI1@2E>9bD^ubJoA%w*KnH%x*v>!$X89kMHF$w>n^*|hbV1+YJmb}wTNlu?B8e0FE zdvt$pVY#)%Ty>TObkVy{wc*(KZ{Fn#K4JG|%i%bLksa0Ye#r;k(EoZlirnm;z$m*j zuZ*e}?&>YmcTpRXNy1QYJB<`SveDkFPWzKI7Eg|(np zpo&K%kV2tl!q}oiO)|d&i_fDlkz@PIxx$ordhERh&}Hn)1w%w@-3CY=EH&?(XXa>?`MWBT3j+JD`Yn^n-`a_U8~pRms+w8sp&68 zKrJ3yD8SQ=w(Jsmo$ei1GNpMBeNQ_Wgs%xn0`ug8e$jLs;rz6x^?En^@S^jf+%|Qp z!Fmd{+~HiR0M%=emDrYt%Zd9IcO7S4Py54iJ(r)5Zzi2x=BLZpyh3q=JTVetM8O!W z`K+ednxPkh9r&L?p>Vb+%Zg&l)n2oDiS%RZSGG&C2eRUomZ^l_QeGP_bFAN@wg(Y_ z25sDWNZ8sa#~BXWS>B=>)31~NAQ$8N9aNs@%OknTfNaVA@<mvbJgt$KlP{TZ_l+?gFe}LB1nabvtBIs}trx_7Y+C zA3N~-HH$RGl#da^g zRUE!ctWCDeyj193-k#{1myGFJVvs2>mj5PXzyZ&7UXENV-2DoG9lwQlW`^!9YC6ql zQt?N{2q!Uuw`^NUc)~QbF3+!Yt29S$h$4))A{5YGEX3O`mI4w+xD7lrtcJZ+UCk_K zGSU0+yQ+yjx*Ra?#9V*O8E@#8Gkb)BFjOkt*sa2@JQLuSzT1Nyc^M2&pZKj7`7Ld5 z17z3F68zM1=v-zrF{a2PxHppo+|nu>MW^9}u>%LZKn?gY_37gVUlmTx`O~@4Vux^= z8p|~B`J)euLrXo6)TOJD0f}fNaR=#DM8^ix8Y|Kqo>Zd=pgg%>)_^KYRrbLIuA0zj zo$DC6lU?+Aq}^YgzkkfC8*o5tib6J{Q3@C}#h=9?NjOGgGU&=#vCVXyJvCq$MOLO)ML1K1*3((D zRq7|REme)JqvmT9n^a4De(HkeKgjumfRAwU1Rx0Qra}R7c@K3Jje%b*Hx@2m{9j=` z{x*;H`^e=``|qrgceJBf#0&u5^>wdTuaX z1A??~Oolv$hBoR~?6i-#oqpzp;D!8P3qJBpb&JpolDB3=fu}FX91`T*?ez%{=hsSh zkAj_*#B?;hQhRIR7P|MmbW>-pLE^@l`Al~g`c(*vK#)fMEX&EaERRZ%ra(vc{*PA) zJFksQ-tMX!@-6N9c0CP}_E&G(iBD-28%wdVhqbg$OH1#r1ExcZPee%WQGHM{rcy4q ztI7PYWCJd@F7AkJMO=46l5RjaxeeAUZarBfGbuch5gTV02G0v%|p^tKIamZ)}?^nP(~wjpB9=+eaE+XMvAY4H#R->vEY$UBkIV{I)6U zl)t($-`P^tJ@mTDeX?~YNAWkDp8z?)WJey^U^ld`!xgREg>!+Jk2|gNQx` z)eL87;orS^W20_SKFtPaV@7yg-m6Q;5N(gK9U&sy=jdg3 zG}_?}P)an=J;YiU8gJ)xFtcI9dt}9$lZN%R8=AQ*UCSd73nm>V$z%`7=fd;pkqdwy z+)PFrPzmZ+4d%o5ia*S^9Kt#~=?!QDb&8H8Q!>(q>Q6VSv65oY8ef^7*Z3+-wx*_v z8@RXDT}&D<>d(8aKySGx7_@KLpSp?JWIwd#UCQJXByYvrEnJ&B+sf*5UPA8{FEvj^ zDbw$a^2-fU+lR*fM2?D8O##l$uPL#e6?EQ}aX$%CPB9W`rXxGE; zm1V55v{O0CE;|KlFRg$=bo>^J$BIp z=J5~yQ?Ev?$3{(>06s~H#qMu>+4%0Pi{W)a3de@MOz;Yf8^KEK{P)sBjPoRHFtjxs zO*dRBWeCTnPJtIHM&+D>x+`HfQU#z0!;Zr{tn*IO`z0`c&XYOi*BGg|*Ho%c51C2j zl;<6H$J$jfahk*zllt6x=74}2!x`3GO;z1~_dQ`rPTpCkqV-WXWuta?8obeTJT;eb(V%)H!q zZNsG}t}y2+D~ZyRh{r?}}FGc9XM zV6<3=HdxGT4{-pFF_tAWr@ZF2s^0t`NM1E-F6r901ip3(1c+$uSAxRH3H=VU*rUze z@rEzt*wP`<&1-QPL3{)Azr#j{-r6g|hBrFBDhK&F%u%~orcLJKnHn|l%TM`B{Mtpc zCzO3A203?0&LDM;US;lU91Nd)yx2CLUbZZ4Q(jdsJ{%ifKeu#(5mJtw6<)2fmKFV@ zF_Mt5<^tEcVa8~^VjU=B(s zjLC5cL{hL@4avBSt6db*WX8&-8M7!3F297Iy_Vhh3GfPHX=2`!8e}o@c-GuR(O0Xr z!-*Llg1Y7Um9+t5*nLz-2LE4S^#v!U`#0}0OgA6;=gY~1_y1$LaE`*S5o?nB-p`ec zJ0+&K4PO0pu?@?22uWPJZG4hL)YevOVhU9y2&e*D`VjigI2&&KTmC&5NG)@%LO7f1jZV> zW5CKrR>3-0dj7Tkiny9aj}oWT;@fhHX#-&u0SW0;lGHL~#VOc> zT7}8=mi?MQvEVllY!Wg6*BGjDINjlQt))zSj1Y&Yh@Z~d#N)}-qYoufQ)-$NOLmJ5 zrDyymDsp$o1DwaR`3nb9CqOWW$KyjleG^|#n*;g-?*OT#$I0nL_iRng)F7HIbTvsz z3wb8|viUs&x&tBx2gI2&5wAQdm5 zJozco!I0AcnIyuj8I^BkzxG&8PTuT-(k8S<`JA8-|ETlH2_t@=viQD5QAOyyNP!bC1;Tm^|Wxsygad=DiZD@rlBtlt5{ zyxab$x#91u2{yqEhplKGW?d+5vd1o`?^E%D`0R5Y?e1P*u&$AY=sS4lFf5aDN3sB7 zif0cdL}9-dYqvNT;4_EJ!*1IBV%@<^bBp)gd1@QT@fEojiPe|uMSb|ZnO**hoSqt; z{5gu?`%z@-7vy5UD&N~rX#ZS~MnWdzMU@j+)VGS+PSDj*jzYY0o;1g;&(=`diPA_r zBTS{8MIkg-8Hq~n1)pR}#z<{?bgm+xjJxNk9fBil;Wk2%P@<5ea;~o2g>79t zn6d3Js?fkO;sCcEMRS|~=KShe0E_;ihXz5Uthk_AeKq}NIGI4BPKw+I)* z43vvFg~s=dIxIp&1`cdP*To|(4xK;zblRs9tmLayYU2FyrovzOgJ3jK)WBsY3%wIX zUB65mlNiQvsH5FB96@m7Wa&2<7lnoR_1^JLBmdD9V>NbdrK6+yX>#5vMrS1@?cpL7 zSwaT^s~Fy+I8t$Tk?*_~e_fqCB| zmbMFbZy9H%DLdJXK7SMy)Lyu58d~-8D8Vdx3oxg&oqcnluGxw;2T@to=)I#xzxNjQ z;kJlKFq@dw$4M$@);Q0LOES8KL;lcj+ITu5bNL?s0Th@Pl}c0@=~u&35{}p*UFGM% z+RatzN@3nOeZpCnyi~sIRW;^Vv*~KVwQ{qQvMRX~nfTe0N2gNwe3TuLrPv4k_L2)i z_3b#-xpt>VCJRz+qTG}GNjR#?!LO?d%q`sVFtvX6X!W1SAs~tW+df2<-n^>%Dt9mH z1MAr6`%IF)FjOba3Ek_75!aZTDjU3rIEm{bs3>o(vkj4vmoY0coa)ujM?U-Sl;zPm z-{d^@aUred@qW}qjyCaD)^A*=t3{(!M#X>F&YAfx%h#lx1?)ENquj){6Q}%K2>8g~ zHg)`D@Vm)&=w{bK@V8Cgfr@4p-NRj_;52jBCg=x6g?x@lBXJqp*)>cAJO9lanbmMj zy|s?{rUAc4KC^2NHfg%Y{^4bY9{bDp@5+sIPL2ExF)-4}+7#VCmnm!LI(vsR;Igka z_=FU|A+ja#VkFiQQ<%x~hG0w&$4rKdX`hf#(YV4hXc19iyW}BCi$HMPutbdis*ssZ zHLBg#D-yZEi`!Kt8AQ4#`yE(QV|NVZZ6ja9y0gyG>a9dmxAvL`-fNqoo3C3_soI{v zb690`av)(7eSU|94@+r|f>hu~M5Ta}t{t`vm$n*_#q$fv^n>j+d)BDH`Bj;YhcQJ( z+>4i%qKj^~*ti;{Ah<=(7s?d5FZEQ2sMZ^185c*nsE1sy=(IfB{Zzoz;)O)Z@w_W~ za=sv{nE}ZU;RDI}+aGjO`1ROL_ptFwD{X|49pO zo{r}Sh2i{b>fBBhXvr8JTDDt3VP3HV9UmaFcWNr(6}j|4cx(Rd*B`v1hG^>rY4nua z?*9!1bL5e{%q}@k8%c)7f0${PmeVRU?P_K8B&4op90?Zk!~}UXGMiWlj^Sn+D6jb0 z@?pfJCHH(ao5O|gw2xQ51WtHc}Om*92v}s?$&f>EZ0V0r79MxQb=Iln9 zEOn2^((aBK*(_n<**o)pI*2li53fWUmBSeTm zMUIT38cy{9bjtMGnIt#ac)`^ODV7V)zOe;BJU^<0^RaI}ZtcQx$< z7xZJ{joDe#<$3xNY|vG2yaR_p;fA#vkIEmh-h#O6x(j|n=GO`f&(N`(8yDCI@B9@k z{QD=_k^G(+5Un{!#!PlpAow;p#xq zaBU@qVI9QRSI*1?yH~;W_Z|D>_SRr;%itQ_!i+h-BNK-As>09HU2y>kt?l`OaTQ~_ z4cKMnkMGkF@RLh}kxu_wyPM5{vzK8cAW-C{+<1R}WG`e5@n&JS2YF!KXO3TyzJ`wb zMa;J=a=Rba*?I8$8TVjlII6;oaU&%;7e6au2t>l*C^FRY3R5J#O_n|Y47gH0e4H!d zlXZjG;{bgUm|fH)ix>E%Dxa>%+?oMMl(MofF~35b!B(Fxia7{kLM$e}Emwg)7n5I| z`%V6!oeEz))XuEgG4y?0{LZi8s-NE}9B!q{eYa8AZL90QuH8t$kdaIG`7Ol&*I28Kv z^P312S{;<>3uJ}B&R=lN6wWNlxgj(2ec2hBlz@u%3rst{y1TCLv}G3dNa3lmo?vt( z@J2S>yuM>G4ZZ47OCHO3E8fQSMYOHi<+1CMp$Fs$M537U_q?m;K_l(=?efg8a4fqP zd-nvf^I?yNC|@9}z(*ecgsktr%yAC5x(z{CxW%azrX=n<;?4l2^6TS_^~Y{M8+XVF zO9Xx3-Jw?1XR%}&6xOrRanq8d>0%SQj)G% zmFnxF9P96XtWPhNMob>AVt~T$_9dRO`zOI>tcz!AAnBn8QwrbF) z5JNJ8As+~43ROi6<6aAo)F>}on(2p^Cm}z?X{tCtcad+b<ZHT zt1JDeGt`U+_a0*6ZJf3Cg50WPu-9+x<9tx7z@r~9r5^hH$mg>7*{Hf^ zxeoYI*~ym5?B?v=uT%O9YaWu#;_Q~o^fbTP=07o-x2cx&%3^1v1m}=F#I@+ zAKjJLj;2<6cg8%Cy-P&XBJh0P0#r_%mxa_m%vf8|Bdo}Yzl6`{zJRLDk%4JW3_^+UkRD^vV!hx;?RbY)kskI}Hn8xcCPzi)vc>yYltP27`%H^fuL<3!Oub@e zkiSr5hw$V=_K5}JG`P{GyLa~Q;Yu;6DOZ+c<8?wa1qNPA^goef3V%gT)i3YmTW(_1 zjrm1=h;7dif@svsQUB&g9cY}`ZHo-CDS!)fcm6ukslNCD8=HZjG+HLBrs4Xpsjiwc zOV5zBcH{FyH{8=OsZJul&wzolp*IvCs0$$*D#Q)ygz;K#1mJzbjxchYX2ku02T;RcP*s6Hmr09t9mv^R zb&G3P!WJ#m(Kvmil^TgcheqTI*gz_87@|URup|CbUi0ZgV2W)@{WL!r;D?1`4rbD> zX-nTOvMaj90KWDQ#^04=MZAxeTczx^KqyeP2JKO$+%vO-eZA(;HZrI0{sg~e=wikB zYJN2IxulMt&URMzGb z8Em6svKG$&`Gkg9zk$fjH_oAEQiP7FJ2wSuy=RyyrO7zn)I+E*aK5Isk==ALOYxEl zJr){3&a5<_?UbTT{xM1Q?<{PLfSc`{GG{|SQ}|1I^mwGPZ$VT5H#K~xeB2vZXREjz zRtNb~*yvvqKXF3)SwA98eH5~}OX5=Hva&WE_~yyN3Fjz9JVhW{#T$ullIqYPEa|e? znZ%J1SWELMZex&D{IXvhU}fWsGQ{fb-5D#9o4!=Y>r(1nOL1p;_`BzaSl#g#uTJ}y zr<{W#4Mz%q^zLrK4bQ$hJm4{}-CbK@rPm@C4Fj*K{_-hDaGHs_`;WN&z<#i z6jYY%ExV3I@*Q^)N9xVYFSDU^hE_`BJfRT1-8q8rR)WK`F0h<|`e2o*T>oiHO_ojd z!}iUmXLO4^UVGjO^n@%?c z<(6aHFMS$iF;sj8?kiwj;g#n$CLU8l5t92Ki0cKicCJULicyX?$MwJ~Q)9`r>d&r&68$m{BV#L%p<)oJG+#TFl?%rOVGFCJtF0!l zk=%8Ii_v*n3O}s#^3(g$YRd+0wu^`Q$>~zUla<)ov7-sVrY4B!{;3L@@jTHj{rq^G zEi$Qe3L2+=iC_KDAh@SJx53MnAdP_YZunh1X7Kmm6fW_I92_bfjEv0CN2wHTga$J+ zV1@eT4*&scHDRm0w1&=Ux2c+(u{@YfrfKyh!otx#kwZ4Q$|gQG;7+}Bs(kf|ROe-C z*+Frnh9$a{?mgFHggf+b5nT25jbJaV_Qj%!a?src7_SE(_ z+>WH{xSNohPq##8Y$0QPft=CrLTu;>;ZSKr0Yn!SHZtYJ%|S4?#kNdFKBggdBnmbw zL6=46qP`QRYmp!V{i@&5%i#;a|3Ys5OE=s*_H*yQQoVvS^4QKqmv0;1N7*&~D{`T* z!ktls6Jk=Hk%WI3o={oKrIH6~*bv^e0rlOVh$AShBn_y()2 z+-{Sx@)d{Cx`fSSQagnmkW9axD%a3tV}}BwQBm=3b5XZn$VHWlu!@aMzi-z*HzV6Y zL$lNWGQX@*V`o9_SlW)Wh913plVyGtsJUnT}G4Ui-wK-s|~bj($x*| zUs_`>Uf8h_86d0Y#4{kV+Q+~v%*4mWLY?TdVdKaTMzs8^>uqy{YtbGn;1P=IVxki1 zse92W5|{V>yJSm`%V&tIEANwWfcBu9DZ2L1Gsa$C{29=wc3*6$CGGjNdF9mo>cyE- znahaLt&*|OUk8#{g|-tDPQ0Dz5=viEi76>jRTf_szg}g;BB4HL?OR|I9<-@0;vn7D z@z(Pby>kC0D=SY+3!`cCuV5x%pZL~lGy98NZ9Wn_u+^h zu_fx064n^jrLK_bv79C3YX?lwUb2B^PxOb<>!IPO;pyCyAXCdpH2ETtIJfmGOFAM> z0S1FAXt=Wbu@8{nZkE66xhWld%)t?m6n1?(Hw#TogEcVL6#{&@VP-i}K~K+zXvOG{ z_SKz;oA!b|k!BCSR<8s=&R>y>fq}pLuO11K)W06d1ld3F!IGXND2&`I?jrv=tqx~* z>bQq_3;M9B=~q%foZMwyRNVWf%SmrF>f4o^IvOo192-oIgQ~VWW4)bonT78B79izp zdEQJ1QTaADNtA4&f}g}1WguBFPl4^ddwR}_8i>}gafjmM=lpTgrvC0-IduQ|iUb;v zN4Tu6PDx9`B+?G9`C_v`*9s;jva>U1LhbHM>e-9*p9p?pVS1l_7qVMw&#jqPE0q<% zZCN9OmnMO~87x9!5^jujkf}YBxirIH_y!=K)I(ywdEQT`A?9bIp45LOttoxa(yBkK zh$(|Lkz;j)5*b*&l_dkPuOUxhJTg^qOA}&8E-NLC%Ndr^=`dbfo09i9QOB6Sk4XPj^SEOswDKfNQryk;RbeKconeu^LHnhfux?pW4YmBPT4C~N*iMGU@0EbMn zVEylj!Qya)?D&ifwEe^-D)S9(fusi}PyXGJo^QFbl}iX>EmjRyCIs-4ShMm{vyi+2 zZb-PTY4vJnH7rM^p$F=OTgHEa4ex)@)O``GUwpV0!saIE>BvWFxql{Q`kgu?FqahO zQXU{hvrxM{iP$n2j=h_kXsfV+Wn8zojEnii6IwD z4q|^(hA?=73oUyZ<8u*b^6XRMZ~W$i+*2^RTTwp!g0ql zr2EDZre%Hb($ZCT{7>b!imNV<))C!fl$+Eva(Gi=!Q@G5!oZ8*W4f)Vw|S!&ZUVSy zl5c`#&dC034o)$WizrH1WJ@>v(1Wx~DkhqOe78_lO&dgH`P=1$Em9l88|<|^#%+|d zF6#IuP<*^^?{lEyCvLX9jy1rC0XDzvqn{-W7yG|zZ*hG%#e2xxw#KDO^REp* z)YbavH*@pZ^ZPJFvzin*S6JDHR#iGuR>w3;9&*jvIu zW3EcbPSL4LOOUneLvd~6G44ij1t}cN)E&_#;wvDUv}QFOW#xe zj(-kN^fm8`S$_1i&1t)1YF#15O-!>b= zU^MEjn3MABq^w-xN28_7laU_a%nl!4mN|)M*Y=AoF_-_uJMm!u#y|&As>48{I*}_6egyA~Vroz!NepMO~>6wdk2y|AH$t)#`jA-a7E?1iLC+ zf{Fj^==RPtefHe^r@H9ho-_(J)l}e`RW)vqGvAJGqzlh+iL)QSrfQXcL$``WIPYQq zIkrd98XrH0rNjk`0UKcb&R~7*QCDD1@@Z}P0HkoTX7RuWRkNPCe9LbT39iK|{$<<1#Ip08dNB-`hefG_Wq1}H~&RXep!#Z-El@A++?*!`n>KumC*}#^r z(Ns6yvJ1J4+WJO#{v--^Y}uJ-!~w0y%YUt;BBQ*)xAVj~6Ze*<;xhacagWJ)@!~F6 zrLkgFVd|$hpQi`yxX~YWaO2-5uyMphOhY)vE1NutJYY({YjkLm!0Wn;O_T?dZrtV8 z9SJUWJp3MPUB0L}X$C#`dOmlzPL1{cM(JYO+wGQ4`C$y6JkEAL0wUHm>10JgyPkT0 z0XIh=u(bfh@Cu|NZ)zn;PX4<=(a@Gj*Y`4sL*TMz9k@g0bbE&?Pxu9*n+%uHh@Bob zrnwK?bd|NY^}5v;WNT7)w45BWj9To;2Dh|DsTJ;mPO z?nm?iGpt^+KPVNfKI^q48e35Be6ZG`BNOlUj9#r*O~YtYo977uB#ntC)YF8^0fMtP z`rD}9dD3#Jx~tTRIik7q9hqntYIb{#uDLrJvGZbS>yaTuL&wfxO(x=wzeidoH1MU-9|w0ecV9Y zF6gB8_bF;GU@3vSJy82qXx}ORr>9c=)$Yh9OklGvEzULLUo zw&iwm!zw?f=%?!Bk9ASlG~-1&H{bPwko}EYuvr|Q51|Gz^50`RkT8!+S2&d6Qh*r~ zt2RCovg2bhRztIfE(X~ZeAX5bM|FT>P6(H#jmN~vIi)sW&o{DR;=WZZ@XM+kSG922 zGZ{@MUG<~SD{=`i2yYEusvMz9TE)wTHOxTeZ_*Abt9?HuAU7x__G^9Xj#=*KYv&1J zul3l%-FA|$TrdPG+?2!?Z`2}Bmf)183-Bx`?G~gDuhC12NTNu#b_^Wl(nuA>#JL7e z=p5%nQpj+%=wASnlVmPtxt?0bT$DsZszK7`3)_FoB`mIZqtska@;y zoPf$!JS62u3;V!OHh(a_<})Oq;Tb>P0;Q*k?ST4AUxm^lMN>ymIXyu{ka}=odCEbb z=I9)%GebeSV2Qc}9;SRk3M|GDtdF^Zo{Ai9r~>^6_OK{6C$&gkyf;pl|&k1a6uh~8t!$72zL8C4$D9vS5b=5 zZJA`i%RM+A|DPP||E-6w$VCUj(8IQdP{O=HFp@mAGJ+9FfM0(}s7JyI%j;4`Fo=QK Tz4iaoJOAHx|F;7F-xc@|f|I>3 literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts index 793e69845e9..c38cc7bcc09 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts @@ -48,17 +48,10 @@ export class TaskTerminalStatus extends Disposable { case TaskEventKind.Active: this.eventActive(event); break; case TaskEventKind.Inactive: this.eventInactive(event); break; case TaskEventKind.ProcessEnded: this.eventEnd(event); break; - case TaskEventKind.End: this._playEndSound(event.exitCode); break; } })); } - private _playEndSound(exitCode?: number): void { - //TODO: determine sound based on exit code - this._audioCueService.playAudioCue(AudioCue.taskEnded); - } - - addTerminal(task: Task, terminal: ITerminalInstance, problemMatcher: AbstractProblemCollector) { const status: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, severity: Severity.Info }; terminal.statusList.add(status); @@ -93,6 +86,7 @@ export class TaskTerminalStatus extends Disposable { terminalData.taskRunEnded = true; terminalData.terminal.statusList.remove(terminalData.status); if ((event.exitCode === 0) && (terminalData.problemMatcher.numberOfMatches === 0)) { + this._audioCueService.playAudioCue(AudioCue.taskCompleted); if (terminalData.task.configurationProperties.isBackground) { for (const status of terminalData.terminal.statusList.statuses) { terminalData.terminal.statusList.remove(status); @@ -101,6 +95,7 @@ export class TaskTerminalStatus extends Disposable { terminalData.terminal.statusList.add(SUCCEEDED_TASK_STATUS); } } else if (event.exitCode || terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Error) { + this._audioCueService.playAudioCue(AudioCue.taskFailed); terminalData.terminal.statusList.add(FAILED_TASK_STATUS); } else if (terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Warning) { terminalData.terminal.statusList.add(WARNING_TASK_STATUS); @@ -116,8 +111,10 @@ export class TaskTerminalStatus extends Disposable { } terminalData.terminal.statusList.remove(terminalData.status); if (terminalData.problemMatcher.numberOfMatches === 0) { + this._audioCueService.playAudioCue(AudioCue.taskCompleted); terminalData.terminal.statusList.add(SUCCEEDED_INACTIVE_TASK_STATUS); } else if (terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Error) { + this._audioCueService.playAudioCue(AudioCue.taskFailed); terminalData.terminal.statusList.add(FAILED_INACTIVE_TASK_STATUS); } else if (terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Warning) { terminalData.terminal.statusList.add(WARNING_INACTIVE_TASK_STATUS); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 94377a2a85b..f940b63e530 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -2,7 +2,6 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { IAction } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; From 7c4d0bad339558071d1e522421ad487c912e6529 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 4 Oct 2022 10:44:37 -0700 Subject: [PATCH 308/599] Use `productService.downloadUrl` --- src/vs/workbench/browser/window.ts | 46 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index 4e4de25cf52..2868bb1ccfe 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -204,34 +204,42 @@ export class BrowserWindow extends Disposable { invokeProtocolHandler(); const showProtocolUrlOpenedDialog = async () => { + const { downloadUrl } = this.productService; + let detail = localize( + 'openExternalDialogDetail.v2', + "We launched {0} on your computer.\n\nIf {1} did not launch, try again or install it below.", + this.productService.nameLong, + this.productService.nameLong + ); + const options = [ + localize('openExternalDialogButtonRetry', "Try again"), + localize('openExternalDialogButtonInstall.v2', "Install {0}", this.productService.nameLong), + localize('openExternalDialogButtonCancel', "Cancel") + ]; + if (downloadUrl === undefined) { + options.splice(1, 1); + detail = localize( + 'openExternalDialogDetailNoInstall', + "We launched {0} on your computer.\n\nIf {1} did not launch, try again below.", + this.productService.nameLong, + this.productService.nameLong + ); + } + const showResult = await this.dialogService.show( Severity.Info, localize('openExternalDialogTitle', "All done. You can close this tab now."), - [ - localize('openExternalDialogButtonRetry', "Try again"), - localize('openExternalDialogButtonInstall', "Install {0}", this.productService.nameLong), - localize('openExternalDialogButtonCancel', "Cancel") - ], + options, { - cancelId: 2, - detail: localize( - 'openExternalDialogDetail.v2', - "We launched {0} on your computer.\n\nIf {1} did not launch, try again or install it below.", - this.productService.nameLong, - this.productService.nameLong, - ) + cancelId: downloadUrl === undefined ? 1 : 2, + detail }, ); if (showResult.choice === 0) { invokeProtocolHandler(); - } else if (showResult.choice === 1) { - // Route the user to the appropriate install link - await this.openerService.open(URI.parse( - this.productService.quality === 'stable' - ? `http://aka.ms/vscode-install` - : `http://aka.ms/vscode-install-insiders` - )); + } else if (showResult.choice === 1 && downloadUrl !== undefined) { + await this.openerService.open(URI.parse(downloadUrl)); // Re-show the dialog so that the user can come back after installing and try again showProtocolUrlOpenedDialog(); From 9e0fe6a1e8e0d1efc33f323426026739f4f1a20e Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 4 Oct 2022 11:41:53 -0700 Subject: [PATCH 309/599] add l10n to notebooks (#162690) --- .vscode/notebooks/endgame.github-issues | 2 +- .vscode/notebooks/my-endgame.github-issues | 2 +- .vscode/notebooks/my-work.github-issues | 2 +- .vscode/notebooks/verification.github-issues | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index b4ed8ac99ba..e30128e3b7f 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n$MILESTONE=milestone:\"September 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n$MILESTONE=milestone:\"September 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 441d0707c0a..6464e61afa6 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n$MILESTONE=milestone:\"September 2022\"\r\n\r\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n$MILESTONE=milestone:\"September 2022\"\n\n$MINE=assignee:@me" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index b7811cf911c..69d50e05965 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\r\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n\r\n// current milestone name\r\n$milestone=milestone:\"October 2022\"" + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n// current milestone name\n$milestone=milestone:\"October 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues index 7f03638ae2b..5c6354a4e72 100644 --- a/.vscode/notebooks/verification.github-issues +++ b/.vscode/notebooks/verification.github-issues @@ -12,7 +12,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks\r\n$milestone=milestone:\"May 2022\"" + "value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n$milestone=milestone:\"May 2022\"" }, { "kind": 1, From 42aa9d3e999c2a205774a173b98ad4623a53f720 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 4 Oct 2022 11:46:44 -0700 Subject: [PATCH 310/599] Add Close tab action and make it default Fixes https://github.com/microsoft/vscode/issues/162440 --- src/vs/workbench/browser/window.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts index 2868bb1ccfe..724e130fcd0 100644 --- a/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -26,6 +26,7 @@ import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/envir import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { BrowserLifecycleService } from 'vs/workbench/services/lifecycle/browser/lifecycleService'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class BrowserWindow extends Disposable { @@ -36,7 +37,8 @@ export class BrowserWindow extends Disposable { @ILabelService private readonly labelService: ILabelService, @IProductService private readonly productService: IProductService, @IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IHostService private readonly hostService: IHostService ) { super(); @@ -212,12 +214,13 @@ export class BrowserWindow extends Disposable { this.productService.nameLong ); const options = [ + localize('openExternalDialogButtonClose', "Close tab"), localize('openExternalDialogButtonRetry', "Try again"), - localize('openExternalDialogButtonInstall.v2', "Install {0}", this.productService.nameLong), + localize('openExternalDialogButtonInstall.v3', "Install"), localize('openExternalDialogButtonCancel', "Cancel") ]; if (downloadUrl === undefined) { - options.splice(1, 1); + options.splice(2, 1); detail = localize( 'openExternalDialogDetailNoInstall', "We launched {0} on your computer.\n\nIf {1} did not launch, try again below.", @@ -231,14 +234,16 @@ export class BrowserWindow extends Disposable { localize('openExternalDialogTitle', "All done. You can close this tab now."), options, { - cancelId: downloadUrl === undefined ? 1 : 2, + cancelId: downloadUrl === undefined ? 2 : 3, detail }, ); if (showResult.choice === 0) { + this.hostService.close(); + } else if (showResult.choice === 1) { invokeProtocolHandler(); - } else if (showResult.choice === 1 && downloadUrl !== undefined) { + } else if (showResult.choice === 2 && downloadUrl !== undefined) { await this.openerService.open(URI.parse(downloadUrl)); // Re-show the dialog so that the user can come back after installing and try again From 96af4b80eb3f6d3d9afb7f2386d23616f58a6fd7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 4 Oct 2022 12:10:42 -0700 Subject: [PATCH 311/599] Fix race when loading notebook webviews (#162472) * Fix race when loading notebook webviews This tries to fix #161520 by doing the following: - Wait for basic initialization to finish before posting messages - `initializedMarkup` should wait for the correct response instead of the first response This fixes the issue in my testing, but causes the layout to shift around during load * wait for js preload to be initialized in webview * Removed pending message queue * Remove extra async Co-authored-by: rebornix --- .../view/renderers/backLayerWebView.ts | 57 +++++++++++-------- .../browser/view/renderers/webviewMessages.ts | 2 + .../browser/view/renderers/webviewPreloads.ts | 2 +- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 44447bf61f0..15ba313df2c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -45,6 +45,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { FromWebviewMessage, IAckOutputHeight, IClickedDataUrlMessage, ICodeBlockHighlightRequest, IContentWidgetTopRequest, IControllerPreload, ICreationContent, ICreationRequestMessage, IFindMatch, IMarkupCellInitialization, RendererMetadata, ToWebviewMessage } from './webviewMessages'; import { compressOutputItemStreams } from 'vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor'; +import { DeferredPromise } from 'vs/base/common/async'; export interface ICachedInset { outputId: string; @@ -108,10 +109,14 @@ export class BackLayerWebView extends Disposable { private readonly _onMessage = this._register(new Emitter()); private readonly _preloadsCache = new Set(); public readonly onMessage: Event = this._onMessage.event; - private _initialized?: Promise; private _disposed = false; private _currentKernel?: INotebookKernel; + private _initialized?: DeferredPromise; + private _webviewPreloadInitialized?: DeferredPromise; + private firstInit = true; + private initializeMarkupPromise?: { readonly requestId: string; readonly p: DeferredPromise; readonly isFirstInit: boolean }; + private readonly nonce = UUID.generateUuid(); constructor( @@ -449,11 +454,9 @@ export class BackLayerWebView extends Disposable { } let coreDependencies = ''; - let resolveFunc: () => void; - this._initialized = new Promise((resolve) => { - resolveFunc = resolve; - }); + this._initialized = new DeferredPromise(); + this._webviewPreloadInitialized = new DeferredPromise(); if (!isWeb) { const loaderUri = FileAccess.asFileUri('vs/loader.js', require); @@ -466,7 +469,7 @@ export class BackLayerWebView extends Disposable { `; const htmlContent = this.generateContent(coreDependencies, baseUrl.toString()); this._initialize(htmlContent); - resolveFunc!(); + this._initialized.complete(); } else { const loaderUri = FileAccess.asBrowserUri('vs/loader.js', require); @@ -490,16 +493,16 @@ var requirejs = (function() { const htmlContent = this.generateContent(coreDependencies, baseUrl.toString()); this._initialize(htmlContent); - resolveFunc!(); + this._initialized!.complete(); }, error => { // the fetch request is rejected const htmlContent = this.generateContent(coreDependencies, baseUrl.toString()); this._initialize(htmlContent); - resolveFunc!(); + this._initialized!.complete(); }); } - await this._initialized; + await this._initialized.p; } private getNotebookBaseUri() { @@ -587,9 +590,17 @@ var requirejs = (function() { switch (data.type) { case 'initialized': { + this._webviewPreloadInitialized?.complete(); this.initializeWebViewState(); break; } + case 'initializedMarkup': { + if (this.initializeMarkupPromise?.requestId === data.requestId) { + this.initializeMarkupPromise?.p.complete(); + this.initializeMarkupPromise = undefined; + } + break; + } case 'dimension': { for (const update of data.updates) { const height = update.height; @@ -924,8 +935,6 @@ var requirejs = (function() { ]; } - private firstInit = true; - private initializeWebViewState() { this._preloadsCache.clear(); if (this._currentKernel) { @@ -936,9 +945,9 @@ var requirejs = (function() { this._sendMessageToWebview({ ...inset.cachedCreation, initiallyHidden: this.hiddenInsetMapping.has(output) }); } - if (this.firstInit) { + if (this.initializeMarkupPromise?.isFirstInit) { // On first run the contents have already been initialized so we don't need to init them again - this.firstInit = false; + // no op } else { const mdCells = [...this.markupPreviewMapping.values()]; this.markupPreviewMapping.clear(); @@ -1152,15 +1161,16 @@ var requirejs = (function() { return; } - // TODO: use proper handler - const p = new Promise(resolve => { - const sub = this.webview?.onMessage(e => { - if (e.message.type === 'initializedMarkup') { - resolve(); - sub?.dispose(); - } - }); - }); + this.initializeMarkupPromise?.p.complete(); + const requestId = UUID.generateUuid(); + this.initializeMarkupPromise = { p: new DeferredPromise(), requestId, isFirstInit: this.firstInit }; + + if (this._webviewPreloadInitialized) { + // wait for webview preload script module to be loaded + await this._webviewPreloadInitialized.p; + } + + this.firstInit = false; for (const cell of cells) { this.markupPreviewMapping.set(cell.cellId, cell); @@ -1169,9 +1179,10 @@ var requirejs = (function() { this._sendMessageToWebview({ type: 'initializeMarkup', cells, + requestId, }); - await p; + return this.initializeMarkupPromise.p.p; } /** diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 79b1b1d3959..79adc52e51e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -138,6 +138,7 @@ export interface ICellDragEndMessage extends BaseToWebviewMessage { export interface IInitializedMarkupMessage extends BaseToWebviewMessage { readonly type: 'initializedMarkup'; + readonly requestId: string; } export interface ICodeBlockHighlightRequest { @@ -351,6 +352,7 @@ export interface IMarkupCellInitialization { export interface IInitializeMarkupCells { readonly type: 'initializeMarkup'; readonly cells: readonly IMarkupCellInitialization[]; + readonly requestId: string; } export interface INotebookStylesMessage { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 75881cc86d8..6062c79818c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1048,7 +1048,7 @@ async function webviewPreloads(ctx: PreloadContext) { await Promise.all(event.data.cells.map(info => viewModel.ensureMarkupCell(info))); } finally { dimensionUpdater.updateImmediately(); - postNotebookMessage('initializedMarkup', {}); + postNotebookMessage('initializedMarkup', { requestId: event.data.requestId }); } break; } From aa97a3b01286e7c29356c841fbbb479297124f4a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 4 Oct 2022 12:21:27 -0700 Subject: [PATCH 312/599] centralize decoration hover code, add hover to quick fix decorations (#162248) --- .../terminal/browser/xterm/decorationAddon.ts | 93 +++++-------------- .../browser/xterm/decorationStyles.ts | 68 +++++++++++++- .../terminal/browser/xterm/quickFixAddon.ts | 20 +++- .../test/browser/quickFixAddon.test.ts | 3 + 4 files changed, 111 insertions(+), 73 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index 22cc61d788b..3cf8a961eab 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -3,44 +3,40 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; -import { IDecoration, ITerminalAddon, Terminal } from 'xterm'; import * as dom from 'vs/base/browser/dom'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { CommandInvalidationReason, ICommandDetectionCapability, IMarkProperties, ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; -import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; import { IAction, Separator } from 'vs/base/common/actions'; -import { Emitter } from 'vs/base/common/event'; -import { MarkdownString } from 'vs/base/common/htmlContent'; -import { localize } from 'vs/nls'; -import { Delayer } from 'vs/base/common/async'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { fromNow } from 'vs/base/common/date'; -import { toolbarHoverBackground } from 'vs/platform/theme/common/colorRegistry'; -import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; -import { TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_SUCCESS_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { terminalDecorationError, terminalDecorationIncomplete, terminalDecorationMark, terminalDecorationSuccess } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; +import { CommandInvalidationReason, ICommandDetectionCapability, IMarkProperties, ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { toolbarHoverBackground } from 'vs/platform/theme/common/colorRegistry'; +import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; -import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; +import { terminalDecorationError, terminalDecorationIncomplete, terminalDecorationMark, terminalDecorationSuccess } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; +import { DecorationSelector, TerminalDecorationHoverManager, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; +import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_SUCCESS_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IDecoration, ITerminalAddon, Terminal } from 'xterm'; interface IDisposableDecoration { decoration: IDecoration; disposables: IDisposable[]; exitCode?: number; markProperties?: IMarkProperties } export class DecorationAddon extends Disposable implements ITerminalAddon { protected _terminal: Terminal | undefined; - private _hoverDelayer: Delayer; private _capabilityDisposables: Map = new Map(); - private _contextMenuVisible: boolean = false; private _decorations: Map = new Map(); private _placeholderDecoration: IDecoration | undefined; private _showGutterDecorations?: boolean; private _showOverviewRulerDecorations?: boolean; + private _terminalDecorationHoverService: TerminalDecorationHoverManager; private readonly _onDidRequestRunCommand = this._register(new Emitter<{ command: ITerminalCommand; copyAsHtml?: boolean }>()); readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event; @@ -49,19 +45,15 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { private readonly _capabilities: ITerminalCapabilityStore, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IHoverService private readonly _hoverService: IHoverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IThemeService private readonly _themeService: IThemeService, @IOpenerService private readonly _openerService: IOpenerService, @IQuickInputService private readonly _quickInputService: IQuickInputService, - @ILifecycleService lifecycleService: ILifecycleService + @ILifecycleService lifecycleService: ILifecycleService, + @IInstantiationService instantiationService: IInstantiationService ) { super(); this._register(toDisposable(() => this._dispose())); - this._register(this._contextMenuService.onDidShowContextMenu(() => this._contextMenuVisible = true)); - this._register(this._contextMenuService.onDidHideContextMenu(() => this._contextMenuVisible = false)); - this._hoverDelayer = this._register(new Delayer(this._configurationService.getValue('workbench.hover.delay'))); - this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TerminalSettingId.FontSize) || e.affectsConfiguration(TerminalSettingId.LineHeight)) { this.refreshLayouts(); @@ -79,6 +71,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { this._register(this._capabilities.onDidAddCapability(c => this._createCapabilityDisposables(c))); this._register(this._capabilities.onDidRemoveCapability(c => this._removeCapabilityDisposables(c))); this._register(lifecycleService.onWillShutdown(() => this._disposeAllDecorations())); + this._terminalDecorationHoverService = instantiationService.createInstance(TerminalDecorationHoverManager); } private _removeCapabilityDisposables(c: TerminalCapability): void { @@ -184,6 +177,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } private _dispose(): void { + this._terminalDecorationHoverService.dispose(); for (const disposable of this._capabilityDisposables.values()) { dispose(disposable); } @@ -309,9 +303,9 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { if (command?.exitCode === undefined && !command?.markProperties) { return []; } else if (command?.markProperties || markProperties) { - return [...this._createHover(element, command || markProperties?.hoverMessage)]; + return [this._terminalDecorationHoverService.createHover(element, command || markProperties, markProperties?.hoverMessage)]; } - return [this._createContextMenu(element, command), ...this._createHover(element, command)]; + return [this._createContextMenu(element, command), this._terminalDecorationHoverService.createHover(element, command)]; } private _updateClasses(element?: HTMLElement, exitCode?: number, markProperties?: IMarkProperties): void { @@ -348,49 +342,12 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { // When the xterm Decoration gets disposed of, its element gets removed from the dom // along with its listeners return dom.addDisposableListener(element, dom.EventType.CLICK, async () => { - this._hideHover(); + this._terminalDecorationHoverService.hideHover(); const actions = await this._getCommandActions(command); this._contextMenuService.showContextMenu({ getAnchor: () => element, getActions: () => actions }); }); } - private _createHover(element: HTMLElement, command: ITerminalCommand, markProperties?: IMarkProperties): IDisposable[] { - return [ - dom.addDisposableListener(element, dom.EventType.MOUSE_ENTER, () => { - if (this._contextMenuVisible) { - return; - } - this._hoverDelayer.trigger(() => { - let hoverContent = `${localize('terminalPromptContextMenu', "Show Command Actions")}`; - hoverContent += '\n\n---\n\n'; - if (command.markProperties || markProperties) { - if (command.markProperties?.hoverMessage || markProperties?.hoverMessage) { - hoverContent = command.markProperties?.hoverMessage || markProperties?.hoverMessage || ''; - } else { - return; - } - } else if (command.exitCode) { - if (command.exitCode === -1) { - hoverContent += localize('terminalPromptCommandFailed', 'Command executed {0} and failed', fromNow(command.timestamp, true)); - } else { - hoverContent += localize('terminalPromptCommandFailedWithExitCode', 'Command executed {0} and failed (Exit Code {1})', fromNow(command.timestamp, true), command.exitCode); - } - } else { - hoverContent += localize('terminalPromptCommandSuccess', 'Command executed {0}', fromNow(command.timestamp, true)); - } - this._hoverService.showHover({ content: new MarkdownString(hoverContent), target: element }); - }); - }), - dom.addDisposableListener(element, dom.EventType.MOUSE_LEAVE, () => this._hideHover()), - dom.addDisposableListener(element, dom.EventType.MOUSE_OUT, () => this._hideHover()) - ]; - } - - private _hideHover() { - this._hoverDelayer.cancel(); - this._hoverService.hideHover(); - } - private async _getCommandActions(command: ITerminalCommand): Promise { const actions: IAction[] = []; if (command.command !== '') { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts index 33d85f3ccc1..87b4d53b5db 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.ts @@ -3,8 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as dom from 'vs/base/browser/dom'; +import { Delayer } from 'vs/base/common/async'; +import { fromNow } from 'vs/base/common/date'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { combinedDisposable, Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; const enum DecorationStyles { DefaultDimension = 16, @@ -24,6 +33,64 @@ export const enum DecorationSelector { LightBulb = 'codicon-light-bulb' } +export class TerminalDecorationHoverManager extends Disposable { + private _hoverDelayer: Delayer; + private _contextMenuVisible: boolean = false; + + constructor(@IHoverService private readonly _hoverService: IHoverService, + @IConfigurationService configurationService: IConfigurationService, + @IContextMenuService contextMenuService: IContextMenuService) { + super(); + this._register(contextMenuService.onDidShowContextMenu(() => this._contextMenuVisible = true)); + this._register(contextMenuService.onDidHideContextMenu(() => this._contextMenuVisible = false)); + this._hoverDelayer = this._register(new Delayer(configurationService.getValue('workbench.hover.delay'))); + } + + public hideHover() { + this._hoverDelayer.cancel(); + this._hoverService.hideHover(); + } + + createHover(element: HTMLElement, command: ITerminalCommand | undefined, hoverMessage?: string): IDisposable { + return combinedDisposable( + dom.addDisposableListener(element, dom.EventType.MOUSE_ENTER, () => { + if (this._contextMenuVisible) { + return; + } + this._hoverDelayer.trigger(() => { + let hoverContent = `${localize('terminalPromptContextMenu', "Show Command Actions")}`; + hoverContent += '\n\n---\n\n'; + if (!command) { + if (hoverMessage) { + hoverContent = hoverMessage; + } else { + return; + } + } else if (command.markProperties || hoverMessage) { + if (command.markProperties?.hoverMessage || hoverMessage) { + hoverContent = command.markProperties?.hoverMessage || hoverMessage || ''; + } else { + return; + } + } else if (command.exitCode) { + if (command.exitCode === -1) { + hoverContent += localize('terminalPromptCommandFailed', 'Command executed {0} and failed', fromNow(command.timestamp, true)); + } else { + hoverContent += localize('terminalPromptCommandFailedWithExitCode', 'Command executed {0} and failed (Exit Code {1})', fromNow(command.timestamp, true), command.exitCode); + } + } else { + hoverContent += localize('terminalPromptCommandSuccess', 'Command executed {0}', fromNow(command.timestamp, true)); + } + this._hoverService.showHover({ content: new MarkdownString(hoverContent), target: element }); + }); + }), + dom.addDisposableListener(element, dom.EventType.MOUSE_LEAVE, () => this.hideHover()), + dom.addDisposableListener(element, dom.EventType.MOUSE_OUT, () => this.hideHover()) + ); + } + +} + export function updateLayout(configurationService: IConfigurationService, element?: HTMLElement): void { if (!element) { return; @@ -40,4 +107,3 @@ export function updateLayout(configurationService: IConfigurationService, elemen element.style.marginLeft = `${scalar * DecorationStyles.MarginLeft}px`; } } - diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index e9f2e91fe93..b8f988f3432 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -11,7 +11,7 @@ import type { ITerminalAddon } from 'xterm-headless'; import * as dom from 'vs/base/browser/dom'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ITerminalQuickFixAction, ITerminalQuickFixOptions } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { DecorationSelector, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; +import { DecorationSelector, TerminalDecorationHoverManager, updateLayout } from 'vs/workbench/contrib/terminal/browser/xterm/decorationStyles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Terminal, IDecoration } from 'xterm'; import { IAction } from 'vs/base/common/actions'; @@ -19,7 +19,11 @@ import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/ import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { localize } from 'vs/nls'; export interface ITerminalQuickFix { showMenu(): void; @@ -50,10 +54,14 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, private _decoration: IDecoration | undefined; + private readonly _terminalDecorationHoverService: TerminalDecorationHoverManager; + constructor(private readonly _capabilities: ITerminalCapabilityStore, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IAudioCueService private readonly _audioCueService: IAudioCueService) { + @IInstantiationService instantiationService: IInstantiationService, + @IAudioCueService private readonly _audioCueService: IAudioCueService, + @IKeybindingService private readonly _keybindingService: IKeybindingService) { super(); const commandDetectionCapability = this._capabilities.get(TerminalCapability.CommandDetection); if (commandDetectionCapability) { @@ -65,6 +73,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, } }); } + this._terminalDecorationHoverService = instantiationService.createInstance(TerminalDecorationHoverManager); } activate(terminal: Terminal): void { this._terminal = terminal; @@ -118,6 +127,8 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, const actions = this._quickFixes; const decoration = this._terminal.registerDecoration({ marker, layer: 'top' }); this._decoration = decoration; + const kb = this._keybindingService.lookupKeybinding(TerminalCommandId.QuickFix); + const hoverLabel = kb ? localize('terminalQuickFixWithKb', "Show Quick Fixes ({0})", kb.getLabel()) : ''; decoration?.onRender((e: HTMLElement) => { if (!this._decorationMarkerIds.has(decoration.marker.id)) { this._currentQuickFixElement = e; @@ -126,9 +137,10 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, this._audioCueService.playAudioCue(AudioCue.terminalQuickFix); if (actions) { this._decorationMarkerIds.add(decoration.marker.id); - dom.addDisposableListener(e, dom.EventType.CLICK, () => { + this._register(dom.addDisposableListener(e, dom.EventType.CLICK, () => { this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions, autoSelectFirstItem: true }); - }); + })); + this._register(this._terminalDecorationHoverService.createHover(e, undefined, hoverLabel)); } } }); diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 40e15538459..4cbfd71f49e 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -6,6 +6,8 @@ import { strictEqual } from 'assert'; import { isWindows } from 'vs/base/common/platform'; import { OpenerService } from 'vs/editor/browser/services/openerService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; @@ -31,6 +33,7 @@ suite('QuickFixAddon', () => { cols: 80, rows: 30 }); + instantiationService.stub(IConfigurationService, new TestConfigurationService()); const capabilities = new TerminalCapabilityStore(); instantiationService.stub(ILogService, new NullLogService()); commandDetection = instantiationService.createInstance(CommandDetectionCapability, xterm); From 409ffdcbeccc17509759bfbb3d7bf3eacf6f54b7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 4 Oct 2022 12:37:50 -0700 Subject: [PATCH 313/599] Bring new actions changes to recent quick fixes --- .../browser/terminalQuickFixBuiltinActions.ts | 12 ++--- .../test/browser/quickFixAddon.test.ts | 45 +++++++++---------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index c3eb80dcde8..24cd302cf34 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -41,11 +41,13 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { const results = matchResult.outputMatch[0].split('\n').map(r => r.trim()); for (let i = 1; i < results.length; i++) { const fixedCommand = results[i]; - return { - type: 'command', - command: `git ${fixedCommand}`, - addNewLine: true - }; + if (fixedCommand) { + actions.push({ + type: 'command', + command: `git ${fixedCommand}`, + addNewLine: true + }); + } } return actions; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 85182fdd4d2..2b6d1203265 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -97,22 +97,19 @@ suite('QuickFixAddon', () => { The most similar commands are pull push`; - const actions = [ - { - id: 'terminal.gitSimilarCommand', - label: 'Run: git pull', - run: true, - tooltip: 'Run: git pull', - enabled: true - }, - { - id: 'terminal.gitSimilarCommand', - label: 'Run: git push', - run: true, - tooltip: 'Run: git push', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git pull', + tooltip: 'Run: git pull', + command: 'git pull' + }, { + id: `quickFix.command`, + enabled: true, + label: 'Run: git push', + tooltip: 'Run: git push', + command: 'git push' + }]; assertMatchOptions(getQuickFixes(createCommand('git pu', output, GitSimilarOutputRegex), expectedMap, openerService), actions); }); }); @@ -122,15 +119,13 @@ suite('QuickFixAddon', () => { const command = `git add . -all`; const output = 'error: did you mean `--all` (with two dashes)?'; const exitCode = 1; - const actions = [ - { - id: 'terminal.gitTwoDashes', - label: 'Run: git add . --all', - run: true, - tooltip: 'Run: git add . --all', - enabled: true - } - ]; + const actions = [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git add . --all', + tooltip: 'Run: git add . --all', + command: 'git add . --all' + }]; setup(() => { const command = gitTwoDashes(); expectedMap.set(command.commandLineMatcher.toString(), [command]); From d19445483ef67e2f1019382ef026913a0e30b69d Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 4 Oct 2022 14:12:53 -0700 Subject: [PATCH 314/599] use timeoutsec and log between irm and ea (#162695) --- build/azure-pipelines/product-publish.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/product-publish.ps1 b/build/azure-pipelines/product-publish.ps1 index 05b2b2b3ae7..4e47d7d6cb2 100644 --- a/build/azure-pipelines/product-publish.ps1 +++ b/build/azure-pipelines/product-publish.ps1 @@ -62,12 +62,15 @@ do { if($set.Add($artifactName)) { Write-Host "Processing artifact: '$artifactName. Downloading from: $($_.resource.downloadUrl)" + $extractPath = "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" try { - Invoke-RestMethod $_.resource.downloadUrl -OutFile "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -Headers @{ + Invoke-RestMethod $_.resource.downloadUrl -OutFile $extractPath -Headers @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" - } -MaximumRetryCount 5 -RetryIntervalSec 1 | Out-Null + } -MaximumRetryCount 5 -RetryIntervalSec 1 -TimeoutSec 300 | Out-Null - Expand-Archive -Path "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -DestinationPath $env:AGENT_TEMPDIRECTORY | Out-Null + Write-Host "Extracting artifact: '$extractPath'" + + Expand-Archive -Path $extractPath -DestinationPath $env:AGENT_TEMPDIRECTORY | Out-Null } catch { Write-Warning $_ $set.Remove($artifactName) | Out-Null From d942736bf1760930edb06be385307786a9f1e9fa Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 4 Oct 2022 17:27:23 -0700 Subject: [PATCH 315/599] API feedback (#162704) * align bundle and uri value to be undefined together * Document everything --- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLocalizationService.ts | 4 +- .../vscode.proposed.localization.d.ts | 44 +++++++++++++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 5e21c84cd15..50ad7f3c9e3 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2199,7 +2199,7 @@ export interface ExtHostTestingShape { export interface ExtHostLocalizationShape { getMessage(extensionId: string, details: IStringDetails): string; - getBundle(extensionId: string): { [key: string]: string }; + getBundle(extensionId: string): { [key: string]: string } | undefined; getBundleUri(extensionId: string): URI | undefined; initializeLocalizedMessages(extension: IExtensionDescription): Promise; } diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index 5e91c2bef1f..335fdf88ac6 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -49,8 +49,8 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { return format(str ?? key, ...(args ?? [])); } - getBundle(extensionId: string): { [key: string]: string } { - return this.bundleCache.get(extensionId)?.contents ?? {}; + getBundle(extensionId: string): { [key: string]: string } | undefined { + return this.bundleCache.get(extensionId)?.contents; } getBundleUri(extensionId: string): URI | undefined { diff --git a/src/vscode-dts/vscode.proposed.localization.d.ts b/src/vscode-dts/vscode.proposed.localization.d.ts index e57d4477b74..40a3b83118e 100644 --- a/src/vscode-dts/vscode.proposed.localization.d.ts +++ b/src/vscode-dts/vscode.proposed.localization.d.ts @@ -4,21 +4,57 @@ *--------------------------------------------------------------------------------------------*/ declare module 'vscode' { + /** + * The namespace for localization-related functionality in the extension API. To use this properly, + * you must have `l10n` defined in your `package.json` and have bundle.l10n..json files. + * For more information on how to generate bundle.l10n..json files, check out the + * [vscode-l10n repo](https://github.com/microsoft/vscode-l10n). + */ export namespace l10n { /** - * A string that can be pulled out of a localization bundle if it exists. + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected {@link args} values for any templated values). + * @param message The message to localize. Supports index templating where strings like {0} and {1} are + * replaced by the item at that index in the {@link args} array. + * @param args The arguments to be used in the localized string. The index of the argument is used to + * match the template placeholder in the localized string. + * @returns localized string with injected arguments. */ export function t(message: string, ...args: any[]): string; /** - * A string that can be pulled out of a localization bundle if it exists. + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected args values for any templated values). + * @param options The options to use when localizing the message. + * @returns localized string with injected arguments. */ - export function t(options: { message: string; args?: any[]; comment: string[] }): string; + export function t(options: { + /** + * The message to localize. Supports index templating where strings like {0} and {1} are + * replaced by the item at that index in the {@link args} array. + */ + message: string; + /** + * The arguments to be used in the localized string. The index of the argument is used to + * match the template placeholder in the localized string. + */ + args?: any[]; + /** + * A comment to help translators understand the context of the message. + */ + comment: string[]; + }): string; /** * The bundle of localized strings that have been loaded for the extension. + * It's undefined if no bundle has been loaded. The bundle is typically not loaded if + * there was no bundle found or when we are running with the default language. */ - export const bundle: { [key: string]: string }; + export const bundle: { [key: string]: string } | undefined; /** * The URI of the localization bundle that has been loaded for the extension. + * It's undefined if no bundle has been loaded. The bundle is typically not loaded if + * there was no bundle found or when we are running with the default language. */ export const uri: Uri | undefined; } From 0c5f14ab367b3790ecf21faaa0ed7a85dfc89148 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 4 Oct 2022 22:43:40 -0700 Subject: [PATCH 316/599] Don't show unbound breakpoint indicator when breakpoints are deactivated (#162700) (#162708) Fix #162699 --- src/vs/workbench/contrib/debug/browser/breakpointsView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 414b1b2494e..42b8cbf0f94 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -294,7 +294,7 @@ export class BreakpointsView extends ViewPane { return langId && dbg.interestedInLanguage(langId); }); - if (message && debuggerHasUnverifiedBps?.length) { + if (message && debuggerHasUnverifiedBps?.length && this.debugService.getModel().areBreakpointsActivated()) { if (delayed) { const mdown = new MarkdownString(undefined, { isTrusted: true }).appendMarkdown(message); this.hintContainer.setLabel('$(warning)', undefined, { title: { markdown: mdown, markdownNotSupportedFallback: message } }); From 3e02b209de576d55f02af71d98b68a51b7833cc8 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 09:05:30 +0200 Subject: [PATCH 317/599] finalize `WorkspaceEditMetadata` api fixes https://github.com/microsoft/vscode/issues/112109 --- .../workbench/api/common/extHostBulkEdits.ts | 6 ----- .../common/extensionsApiProposals.ts | 1 - src/vscode-dts/vscode.d.ts | 13 ++++++++- ...e.proposed.workspaceEditIsRefactoring.d.ts | 27 ------------------- 4 files changed, 12 insertions(+), 35 deletions(-) delete mode 100644 src/vscode-dts/vscode.proposed.workspaceEditIsRefactoring.d.ts diff --git a/src/vs/workbench/api/common/extHostBulkEdits.ts b/src/vs/workbench/api/common/extHostBulkEdits.ts index 59e0bbc2426..bdbfe2e5ba8 100644 --- a/src/vs/workbench/api/common/extHostBulkEdits.ts +++ b/src/vs/workbench/api/common/extHostBulkEdits.ts @@ -8,7 +8,6 @@ import { MainContext, MainThreadBulkEditsShape } from 'vs/workbench/api/common/e import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { WorkspaceEdit } from 'vs/workbench/api/common/extHostTypeConverters'; -import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import type * as vscode from 'vscode'; export class ExtHostBulkEdits { @@ -29,11 +28,6 @@ export class ExtHostBulkEdits { } applyWorkspaceEdit(edit: vscode.WorkspaceEdit, extension: IExtensionDescription, metadata: vscode.WorkspaceEditMetadata | undefined): Promise { - const allowIsRefactoring = isProposedApiEnabled(extension, 'workspaceEditIsRefactoring'); - if (metadata && !allowIsRefactoring) { - console.warn(`Extension '${extension.identifier.value}' uses a proposed API 'workspaceEditIsRefactoring' which is NOT enabled for it`); - metadata = undefined; - } const dto = WorkspaceEdit.from(edit, this._versionInformationProvider); return this._proxy.$tryApplyWorkspaceEdit(dto, undefined, metadata?.isRefactoring ?? false); } diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 280b0f3fef6..d9a2af80b2c 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -70,7 +70,6 @@ export const allApiProposals = Object.freeze({ treeItemCheckbox: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeItemCheckbox.d.ts', treeViewReveal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeViewReveal.d.ts', tunnels: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tunnels.d.ts', - workspaceEditIsRefactoring: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.workspaceEditIsRefactoring.d.ts', workspaceTrust: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.workspaceTrust.d.ts' }); export type ApiProposalName = keyof typeof allApiProposals; diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 1a898cb7aed..9939daa9e5c 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -3579,6 +3579,16 @@ declare module 'vscode' { iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; } + /** + * Additional data about a workspace edit. + */ + export interface WorkspaceEditMetadata { + /** + * Signal to the editor that this edit is a refactoring. + */ + isRefactoring?: boolean; + } + /** * A workspace edit is a collection of textual and files changes for * multiple resources and documents. @@ -12165,9 +12175,10 @@ declare module 'vscode' { * not be attempted, when a single edit fails. * * @param edit A workspace edit. + * @param metadata Optional {@link WorkspaceEditMetadata metadata} for the edit. * @return A thenable that resolves when the edit could be applied. */ - export function applyEdit(edit: WorkspaceEdit): Thenable; + export function applyEdit(edit: WorkspaceEdit, metadata?: WorkspaceEditMetadata): Thenable; /** * All text documents currently known to the editor. diff --git a/src/vscode-dts/vscode.proposed.workspaceEditIsRefactoring.d.ts b/src/vscode-dts/vscode.proposed.workspaceEditIsRefactoring.d.ts deleted file mode 100644 index 2589a016e4c..00000000000 --- a/src/vscode-dts/vscode.proposed.workspaceEditIsRefactoring.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - // https://github.com/microsoft/vscode/issues/112109 - - /** - * Additional data about a workspace edit. - */ - export interface WorkspaceEditMetadata { - /** - * Signal to the editor that this edit is a refactoring. - */ - isRefactoring?: boolean; - } - - export namespace workspace { - - /** - * @param metadata Optional {@link WorkspaceEditMetadata metadata} for the edit. - */ - export function applyEdit(edit: WorkspaceEdit, metadata?: WorkspaceEditMetadata): Thenable; - } -} From dc04246b0ae4e05fe9a429915de75a9880e5db7b Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 09:07:35 +0200 Subject: [PATCH 318/599] respect auto-save setting even for single file edits --- src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts index 00b8fa73e16..00a833511b0 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts @@ -244,7 +244,7 @@ export class BulkEditService implements IBulkEditService { // when enabled (option AND setting) loop over all dirty working copies and trigger save // for those that were involved in this bulk edit operation. - if (options?.respectAutoSaveConfig && this._configService.getValue(autoSaveSetting) === true && resources.length > 1) { + if (options?.respectAutoSaveConfig && this._configService.getValue(autoSaveSetting) === true) { await this._saveAll(resources); } From a90f6a16799973fe414ea90308cd256ffcad8128 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 09:34:59 +0200 Subject: [PATCH 319/599] move common action categories into its own file for better re-use --- .../action/common/actionCommonCategories.ts | 14 ++ .../browser/actions/developerActions.ts | 10 +- .../workbench/browser/actions/helpActions.ts | 20 +- .../browser/actions/layoutActions.ts | 30 +-- .../browser/actions/navigationActions.ts | 15 +- .../browser/actions/windowActions.ts | 8 +- .../parts/activitybar/activitybarActions.ts | 8 +- .../parts/auxiliarybar/auxiliaryBarActions.ts | 7 +- .../browser/parts/banner/bannerPart.ts | 4 +- .../parts/editor/breadcrumbsControl.ts | 4 +- .../parts/editor/editor.contribution.ts | 197 +++++++++--------- .../browser/parts/editor/editorCommands.ts | 22 +- .../browser/parts/panel/panelActions.ts | 29 +-- .../browser/parts/sidebar/sidebarActions.ts | 4 +- .../parts/statusbar/statusbarActions.ts | 4 +- .../browser/parts/titlebar/titlebarPart.ts | 4 +- .../browser/parts/views/viewsService.ts | 8 +- src/vs/workbench/browser/web.main.ts | 4 +- src/vs/workbench/common/actions.ts | 9 - .../codeEditor/browser/inspectKeybindings.ts | 6 +- .../codeEditor/browser/toggleMinimap.ts | 4 +- .../browser/toggleRenderControlCharacter.ts | 4 +- .../browser/toggleRenderWhitespace.ts | 4 +- .../electron-sandbox/startDebugTextMate.ts | 4 +- .../abstractRuntimeExtensionsEditor.ts | 4 +- .../browser/extensions.contribution.ts | 6 +- .../feedback/browser/feedbackStatusbarItem.ts | 4 +- .../issue/browser/issue.web.contribution.ts | 4 +- .../electron-sandbox/issue.contribution.ts | 4 +- .../issue/electron-sandbox/issueActions.ts | 8 +- .../browser/keybindings.contribution.ts | 4 +- .../contrib/logs/browser/logs.contribution.ts | 5 +- .../contrib/logs/common/logs.contribution.ts | 7 +- .../electron-sandbox/logs.contribution.ts | 7 +- .../markers/browser/markers.contribution.ts | 4 +- .../contrib/clipboard/notebookClipboard.ts | 4 +- .../gettingStarted/notebookGettingStarted.ts | 4 +- .../browser/contrib/troubleshoot/layout.ts | 8 +- .../output/browser/output.contribution.ts | 8 +- .../browser/performance.contribution.ts | 10 +- .../quickaccess/browser/viewQuickAccess.ts | 6 +- .../remote/common/remote.contribution.ts | 6 +- .../test/browser/snippetsService.test.ts | 2 +- .../terminal/browser/terminalActions.ts | 4 +- .../testing/browser/testExplorerActions.ts | 4 +- .../testing/browser/testingOutputPeek.ts | 10 +- .../themes/browser/themes.contribution.ts | 12 +- .../update/browser/update.contribution.ts | 5 +- .../contrib/url/browser/url.contribution.ts | 4 +- .../browser/userDataProfileActions.ts | 6 +- .../userDataSync/browser/userDataSync.ts | 6 +- .../browser/userDataSyncTrigger.ts | 1 - .../electron-sandbox/webviewCommands.ts | 4 +- .../webviewPanel/browser/webviewCommands.ts | 4 +- .../welcomeOverlay/browser/welcomeOverlay.ts | 7 +- .../browser/walkThrough.contribution.ts | 5 +- .../actions/developerActions.ts | 10 +- .../electron-sandbox/actions/windowActions.ts | 8 +- .../browser/extensionBisect.ts | 4 +- .../browser/webExtensionsScannerService.ts | 4 +- .../extensions/common/extensionHostManager.ts | 4 +- .../electronExtensionService.ts | 4 +- 62 files changed, 324 insertions(+), 310 deletions(-) create mode 100644 src/vs/platform/action/common/actionCommonCategories.ts diff --git a/src/vs/platform/action/common/actionCommonCategories.ts b/src/vs/platform/action/common/actionCommonCategories.ts new file mode 100644 index 00000000000..5a62d7df897 --- /dev/null +++ b/src/vs/platform/action/common/actionCommonCategories.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; + +export const Categories = Object.freeze({ + View: { value: localize('view', "View"), original: 'View' }, + Help: { value: localize('help', "Help"), original: 'Help' }, + Test: { value: localize('test', "Test"), original: 'Test' }, + Preferences: { value: localize('preferences', "Preferences"), original: 'Preferences' }, + Developer: { value: localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"), original: 'Developer' } +}); diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts index 5a0d08a8623..9de0788c23f 100644 --- a/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -27,7 +27,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { ILogService } from 'vs/platform/log/common/log'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; class InspectContextKeysAction extends Action2 { @@ -36,7 +36,7 @@ class InspectContextKeysAction extends Action2 { super({ id: 'workbench.action.inspectContextKeys', title: { value: localize('inspect context keys', "Inspect Context Keys"), original: 'Inspect Context Keys' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -96,7 +96,7 @@ class ToggleScreencastModeAction extends Action2 { super({ id: 'workbench.action.toggleScreencastMode', title: { value: localize('toggle screencast mode', "Toggle Screencast Mode"), original: 'Toggle Screencast Mode' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -267,7 +267,7 @@ class LogStorageAction extends Action2 { super({ id: 'workbench.action.logStorage', title: { value: localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"), original: 'Log Storage Database Contents' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -283,7 +283,7 @@ class LogWorkingCopiesAction extends Action2 { super({ id: 'workbench.action.logWorkingCopies', title: { value: localize({ key: 'logWorkingCopies', comment: ['A developer only action to log the working copies that exist.'] }, "Log Working Copies"), original: 'Log Working Copies' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/browser/actions/helpActions.ts b/src/vs/workbench/browser/actions/helpActions.ts index 227492a8fce..d05f5a9e391 100644 --- a/src/vs/workbench/browser/actions/helpActions.ts +++ b/src/vs/workbench/browser/actions/helpActions.ts @@ -14,7 +14,7 @@ import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IProductService } from 'vs/platform/product/common/productService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; class KeybindingsReferenceAction extends Action2 { @@ -29,7 +29,7 @@ class KeybindingsReferenceAction extends Action2 { mnemonicTitle: localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -68,7 +68,7 @@ class OpenIntroductoryVideosUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miVideoTutorials', comment: ['&& denotes a mnemonic'] }, "&&Video Tutorials"), original: 'Video Tutorials' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -101,7 +101,7 @@ class OpenTipsAndTricksUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks"), original: 'Tips and Tricks' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -134,7 +134,7 @@ class OpenDocumentationUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation"), original: 'Documentation' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -163,7 +163,7 @@ class OpenNewsletterSignupUrlAction extends Action2 { super({ id: OpenNewsletterSignupUrlAction.ID, title: { value: localize('newsletterSignup', "Signup for the VS Code Newsletter"), original: 'Signup for the VS Code Newsletter' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true }); } @@ -192,7 +192,7 @@ class OpenTwitterUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter"), original: 'Join Us on Twitter' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -225,7 +225,7 @@ class OpenRequestFeatureUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests"), original: 'Search Feature Requests' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -258,7 +258,7 @@ class OpenLicenseUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License"), original: 'View License' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, @@ -296,7 +296,7 @@ class OpenPrivacyStatementUrlAction extends Action2 { mnemonicTitle: localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement"), original: 'Privacy Statement' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 89651caa991..61f8d64c69f 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import Severity from 'vs/base/common/severity'; import { MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService, Parts, Position, positionToString } from 'vs/workbench/services/layout/browser/layoutService'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -58,7 +58,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.closeSidebar', title: { value: localize('closeSidebar', "Close Primary Side Bar"), original: 'Close Primary Side Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -84,7 +84,7 @@ export class ToggleActivityBarVisibilityAction extends Action2 { mnemonicTitle: localize({ key: 'miActivityBar', comment: ['&& denotes a mnemonic'] }, "&&Activity Bar"), original: 'Toggle Activity Bar Visibility' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true), menu: [{ @@ -120,7 +120,7 @@ registerAction2(class extends Action2 { mnemonicTitle: localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"), original: 'Toggle Centered Layout' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: IsCenteredLayoutContext, menu: [{ @@ -201,7 +201,7 @@ export class ToggleSidebarPositionAction extends Action2 { super({ id: ToggleSidebarPositionAction.ID, title: { value: localize('toggleSidebarPosition', "Toggle Primary Side Bar Position"), original: 'Toggle Primary Side Bar Position' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -329,7 +329,7 @@ registerAction2(class extends Action2 { mnemonicTitle: localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), original: 'Toggle Editor Area Visibility' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: EditorAreaVisibleContext, // the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment @@ -359,7 +359,7 @@ class ToggleSidebarVisibilityAction extends Action2 { super({ id: ToggleSidebarVisibilityAction.ID, title: { value: localize('toggleSidebar', "Toggle Primary Side Bar Visibility"), original: 'Toggle Primary Side Bar Visibility' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -467,7 +467,7 @@ export class ToggleStatusbarVisibilityAction extends Action2 { mnemonicTitle: localize({ key: 'miStatusbar', comment: ['&& denotes a mnemonic'] }, "S&&tatus Bar"), original: 'Toggle Status Bar Visibility' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true), menu: [{ @@ -502,7 +502,7 @@ registerAction2(class extends Action2 { value: localize('toggleTabs', "Toggle Tab Visibility"), original: 'Toggle Tab Visibility' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -529,7 +529,7 @@ registerAction2(class extends Action2 { mnemonicTitle: localize('miToggleZenMode', "Zen Mode"), original: 'Toggle Zen Mode' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -576,7 +576,7 @@ if (isWindows || isLinux || isWeb) { mnemonicTitle: localize({ key: 'miMenuBar', comment: ['&& denotes a mnemonic'] }, "Menu &&Bar"), original: 'Toggle Menu Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')), menu: [{ @@ -614,7 +614,7 @@ registerAction2(class extends Action2 { value: localize('resetViewLocations', "Reset View Locations"), original: 'Reset View Locations' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -635,7 +635,7 @@ registerAction2(class extends Action2 { value: localize('moveView', "Move View"), original: 'Move View' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -780,7 +780,7 @@ class MoveFocusedViewAction extends Action2 { value: localize('moveFocusedView', "Move Focused View"), original: 'Move Focused View' }, - category: CATEGORIES.View, + category: Categories.View, precondition: FocusedViewContext.notEqualsTo(''), f1: true }); @@ -939,7 +939,7 @@ registerAction2(class extends Action2 { value: localize('resetFocusedViewLocation', "Reset Focused View Location"), original: 'Reset Focused View Location' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, precondition: FocusedViewContext.notEqualsTo('') }); diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index 86fca131e3f..9c3c8e0b1c1 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -9,7 +9,8 @@ import { Action } from 'vs/base/common/actions'; import { IEditorGroupsService, GroupDirection, GroupLocation, IFindGroupScope } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Direction } from 'vs/base/browser/ui/grid/grid'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -312,9 +313,9 @@ export class FocusPreviousPart extends Action { const actionsRegistry = Registry.as(Extensions.WorkbenchActions); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateUpAction, undefined), 'View: Navigate to the View Above', CATEGORIES.View.value); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateDownAction, undefined), 'View: Navigate to the View Below', CATEGORIES.View.value); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateLeftAction, undefined), 'View: Navigate to the View on the Left', CATEGORIES.View.value); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateRightAction, undefined), 'View: Navigate to the View on the Right', CATEGORIES.View.value); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextPart, { primary: KeyCode.F6 }), 'View: Focus Next Part', CATEGORIES.View.value); -actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousPart, { primary: KeyMod.Shift | KeyCode.F6 }), 'View: Focus Previous Part', CATEGORIES.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateUpAction, undefined), 'View: Navigate to the View Above', Categories.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateDownAction, undefined), 'View: Navigate to the View Below', Categories.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateLeftAction, undefined), 'View: Navigate to the View on the Left', Categories.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateRightAction, undefined), 'View: Navigate to the View on the Right', Categories.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextPart, { primary: KeyCode.F6 }), 'View: Focus Next Part', Categories.View.value); +actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousPart, { primary: KeyMod.Shift | KeyCode.F6 }), 'View: Focus Previous Part', Categories.View.value); diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 8858f514ec5..eaa2db307dd 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -10,7 +10,7 @@ import { MenuRegistry, MenuId, Action2, registerAction2, IAction2Options } from import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IsFullscreenContext } from 'vs/workbench/common/contextkeys'; import { IsMacNativeContext, IsDevelopmentContext, IsWebContext, IsIOSContext } from 'vs/platform/contextkey/common/contextkeys'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickInputButton, IQuickInputService, IQuickPickSeparator, IKeyMods, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { IWorkspaceContextService, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; @@ -289,7 +289,7 @@ class ToggleFullScreenAction extends Action2 { mnemonicTitle: localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), original: 'Toggle Full Screen' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -323,7 +323,7 @@ export class ReloadWindowAction extends Action2 { super({ id: ReloadWindowAction.ID, title: { value: localize('reloadWindow', "Reload Window"), original: 'Reload Window' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib + 50, @@ -350,7 +350,7 @@ class ShowAboutDialogAction extends Action2 { mnemonicTitle: localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About"), original: 'About' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 1f16d17aea9..d4db825ca72 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -17,7 +17,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IActivity } from 'vs/workbench/common/activity'; import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_SETTINGS_PROFILE_BACKGROUND, ACTIVITY_BAR_SETTINGS_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; @@ -454,7 +454,7 @@ registerAction2( super({ id: 'workbench.action.previousSideBarView', title: { value: localize('previousSideBarView', "Previous Primary Side Bar View"), original: 'Previous Primary Side Bar View' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }, -1); } @@ -467,7 +467,7 @@ registerAction2( super({ id: 'workbench.action.nextSideBarView', title: { value: localize('nextSideBarView', "Next Primary Side Bar View"), original: 'Next Primary Side Bar View' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }, 1); } @@ -480,7 +480,7 @@ registerAction2( super({ id: 'workbench.action.focusActivityBar', title: { value: localize('focusActivityBar', "Focus Activity Bar"), original: 'Focus Activity Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts index 4603210c471..0a8890728c3 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts @@ -10,7 +10,8 @@ import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { CATEGORIES, Extensions as WorkbenchExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { Extensions as WorkbenchExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { AuxiliaryBarVisibleContext } from 'vs/workbench/common/contextkeys'; import { ViewContainerLocation, ViewContainerLocationToString } from 'vs/workbench/common/views'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; @@ -134,5 +135,5 @@ MenuRegistry.appendMenuItems([ ]); const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleAuxiliaryBarAction), 'View: Toggle Secondary Side Bar Visibility', CATEGORIES.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusAuxiliaryBarAction), 'View: Focus into Secondary Side Bar', CATEGORIES.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleAuxiliaryBarAction), 'View: Toggle Secondary Side Bar Visibility', Categories.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusAuxiliaryBarAction), 'View: Focus into Secondary Side Bar', Categories.View.value); diff --git a/src/vs/workbench/browser/parts/banner/bannerPart.ts b/src/vs/workbench/browser/parts/banner/bannerPart.ts index 667296666ae..0bb128fd96e 100644 --- a/src/vs/workbench/browser/parts/banner/bannerPart.ts +++ b/src/vs/workbench/browser/parts/banner/bannerPart.ts @@ -22,7 +22,7 @@ import { IBannerItem, IBannerService } from 'vs/workbench/services/banner/browse import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer'; import { BANNER_BACKGROUND, BANNER_FOREGROUND, BANNER_ICON_FOREGROUND } from 'vs/workbench/common/theme'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -318,7 +318,7 @@ class FocusBannerAction extends Action2 { super({ id: FocusBannerAction.ID, title: { value: FocusBannerAction.LABEL, original: 'Focus Banner' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 9f994a9dd1b..657bea0cea4 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -36,7 +36,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { PixelRatio } from 'vs/base/browser/browser'; import { ILabelService } from 'vs/platform/label/common/label'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { IOutline } from 'vs/workbench/services/outline/browser/outline'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; @@ -507,7 +507,7 @@ registerAction2(class ToggleBreadcrumb extends Action2 { mnemonicTitle: localize('miBreadcrumbs', "Toggle &&Breadcrumbs"), original: 'Toggle Breadcrumbs', }, - category: CATEGORIES.View, + category: Categories.View, toggled: { condition: ContextKeyExpr.equals('config.breadcrumbs.enabled', true), title: localize('cmd.toggle2', "Breadcrumbs"), diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 919b490fd88..82ca36f22a6 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -22,7 +22,8 @@ import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResource import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { ChangeEncodingAction, ChangeEOLAction, ChangeLanguageAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem, registerAction2 } from 'vs/platform/actions/common/actions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; @@ -172,78 +173,78 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEOLAction), 'Ch registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEncodingAction), 'Change File Encoding'); // Editor Management -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketRight] } }), 'View: Open Next Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketLeft] } }), 'View: Open Previous Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditorInGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.PageDown), mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow) } }), 'View: Open Next Editor in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousEditorInGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.PageUp), mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow) } }), 'View: Open Previous Editor in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextRecentlyUsedEditorAction), 'View: Open Next Recently Used Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousRecentlyUsedEditorAction), 'View: Open Previous Recently Used Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextRecentlyUsedEditorInGroupAction), 'View: Open Next Recently Used Editor In Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousRecentlyUsedEditorInGroupAction), 'View: Open Previous Recently Used Editor In Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenFirstEditorInGroup), 'View: Open First Editor in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLastEditorInGroup, { primary: KeyMod.Alt | KeyCode.Digit0, secondary: [KeyMod.CtrlCmd | KeyCode.Digit9], mac: { primary: KeyMod.WinCtrl | KeyCode.Digit0, secondary: [KeyMod.CtrlCmd | KeyCode.Digit9] } }), 'View: Open Last Editor in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenClosedEditorAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyT }), 'View: Reopen Closed Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByAppearanceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyP), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors By Appearance', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByMostRecentlyUsedAction), 'View: Show All Editors By Most Recently Used', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowEditorsInActiveGroupByMostRecentlyUsedAction), 'View: Show Editors in Active Group By Most Recently Used', CATEGORIES.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketRight] } }), 'View: Open Next Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.BracketLeft] } }), 'View: Open Previous Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditorInGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.PageDown), mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow) } }), 'View: Open Next Editor in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousEditorInGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.PageUp), mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow) } }), 'View: Open Previous Editor in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextRecentlyUsedEditorAction), 'View: Open Next Recently Used Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousRecentlyUsedEditorAction), 'View: Open Previous Recently Used Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextRecentlyUsedEditorInGroupAction), 'View: Open Next Recently Used Editor In Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousRecentlyUsedEditorInGroupAction), 'View: Open Previous Recently Used Editor In Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenFirstEditorInGroup), 'View: Open First Editor in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLastEditorInGroup, { primary: KeyMod.Alt | KeyCode.Digit0, secondary: [KeyMod.CtrlCmd | KeyCode.Digit9], mac: { primary: KeyMod.WinCtrl | KeyCode.Digit0, secondary: [KeyMod.CtrlCmd | KeyCode.Digit9] } }), 'View: Open Last Editor in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenClosedEditorAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyT }), 'View: Reopen Closed Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByAppearanceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyP), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors By Appearance', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByMostRecentlyUsedAction), 'View: Show All Editors By Most Recently Used', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowEditorsInActiveGroupByMostRecentlyUsedAction), 'View: Show Editors in Active Group By Most Recently Used', Categories.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearRecentFilesAction), 'File: Clear Recently Opened', localize('file', "File")); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyW) }), 'View: Close All Editors', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorGroupsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyW) }), 'View: Close All Editor Groups', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseLeftEditorsInGroupAction), 'View: Close Editors to the Left in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseEditorsInOtherGroupsAction), 'View: Close Editors in Other Groups', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseEditorInAllGroupsAction), 'View: Close Editor in All Groups', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorAction, { primary: KeyMod.CtrlCmd | KeyCode.Backslash }), 'View: Split Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorOrthogonalAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Backslash) }), 'View: Split Editor Orthogonal', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorLeftAction), 'View: Split Editor Left', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorRightAction), 'View: Split Editor Right', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorUpAction), 'View: Split Editor Up', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorDownAction), 'View: Split Editor Down', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(JoinTwoGroupsAction), 'View: Join Editor Group with Next Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(JoinAllGroupsAction), 'View: Join All Editor Groups', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBetweenGroupsAction), 'View: Navigate Between Editor Groups', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetGroupSizesAction), 'View: Reset Editor Group Sizes', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleGroupSizesAction), 'View: Toggle Editor Group Sizes', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MaximizeGroupAction), 'View: Maximize Editor Group and Hide Side Bars', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MinimizeOtherGroupsAction), 'View: Maximize Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorLeftInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow) } }), 'View: Move Editor Left', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorRightInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow) } }), 'View: Move Editor Right', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupLeftAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.LeftArrow) }), 'View: Move Editor Group Left', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupRightAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.RightArrow) }), 'View: Move Editor Group Right', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupUpAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.UpArrow) }), 'View: Move Editor Group Up', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupDownAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.DownArrow) }), 'View: Move Editor Group Down', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupLeftAction), 'View: Duplicate Editor Group Left', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupRightAction), 'View: Duplicate Editor Group Right', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupUpAction), 'View: Duplicate Editor Group Up', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupDownAction), 'View: Duplicate Editor Group Down', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToPreviousGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } }), 'View: Move Editor into Previous Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToNextGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } }), 'View: Move Editor into Next Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToFirstGroupAction, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.Digit1, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Digit1 } }), 'View: Move Editor into First Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToLastGroupAction, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.Digit9, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Digit9 } }), 'View: Move Editor into Last Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToLeftGroupAction), 'View: Move Editor into Left Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToRightGroupAction), 'View: Move Editor into Right Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToAboveGroupAction), 'View: Move Editor into Group Above', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToBelowGroupAction), 'View: Move Editor into Group Below', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToPreviousGroupAction), 'View: Split Editor into Previous Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToNextGroupAction), 'View: Split Editor into Next Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToFirstGroupAction), 'View: Split Editor into First Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToLastGroupAction), 'View: Split Editor into Last Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToLeftGroupAction), 'View: Split Editor into Left Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToRightGroupAction), 'View: Split Editor into Right Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToAboveGroupAction), 'View: Split Editor into Group Above', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToBelowGroupAction), 'View: Split Editor into Group Below', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusActiveGroupAction), 'View: Focus Active Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusFirstGroupAction, { primary: KeyMod.CtrlCmd | KeyCode.Digit1 }), 'View: Focus First Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusLastGroupAction), 'View: Focus Last Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousGroup), 'View: Focus Previous Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextGroup), 'View: Focus Next Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusLeftGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.LeftArrow) }), 'View: Focus Left Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusRightGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Right Editor Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusAboveGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.UpArrow) }), 'View: Focus Editor Group Above', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusBelowGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.DownArrow) }), 'View: Focus Editor Group Below', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupLeftAction), 'View: New Editor Group to the Left', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupRightAction), 'View: New Editor Group to the Right', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupAboveAction), 'View: New Editor Group Above', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupBelowAction), 'View: New Editor Group Below', CATEGORIES.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyW) }), 'View: Close All Editors', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorGroupsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyW) }), 'View: Close All Editor Groups', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseLeftEditorsInGroupAction), 'View: Close Editors to the Left in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseEditorsInOtherGroupsAction), 'View: Close Editors in Other Groups', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseEditorInAllGroupsAction), 'View: Close Editor in All Groups', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorAction, { primary: KeyMod.CtrlCmd | KeyCode.Backslash }), 'View: Split Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorOrthogonalAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Backslash) }), 'View: Split Editor Orthogonal', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorLeftAction), 'View: Split Editor Left', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorRightAction), 'View: Split Editor Right', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorUpAction), 'View: Split Editor Up', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorDownAction), 'View: Split Editor Down', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(JoinTwoGroupsAction), 'View: Join Editor Group with Next Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(JoinAllGroupsAction), 'View: Join All Editor Groups', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBetweenGroupsAction), 'View: Navigate Between Editor Groups', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetGroupSizesAction), 'View: Reset Editor Group Sizes', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleGroupSizesAction), 'View: Toggle Editor Group Sizes', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MaximizeGroupAction), 'View: Maximize Editor Group and Hide Side Bars', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MinimizeOtherGroupsAction), 'View: Maximize Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorLeftInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow) } }), 'View: Move Editor Left', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorRightInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow) } }), 'View: Move Editor Right', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupLeftAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.LeftArrow) }), 'View: Move Editor Group Left', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupRightAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.RightArrow) }), 'View: Move Editor Group Right', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupUpAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.UpArrow) }), 'View: Move Editor Group Up', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveGroupDownAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.DownArrow) }), 'View: Move Editor Group Down', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupLeftAction), 'View: Duplicate Editor Group Left', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupRightAction), 'View: Duplicate Editor Group Right', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupUpAction), 'View: Duplicate Editor Group Up', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateGroupDownAction), 'View: Duplicate Editor Group Down', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToPreviousGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.LeftArrow } }), 'View: Move Editor into Previous Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToNextGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.RightArrow } }), 'View: Move Editor into Next Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToFirstGroupAction, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.Digit1, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Digit1 } }), 'View: Move Editor into First Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToLastGroupAction, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.Digit9, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Digit9 } }), 'View: Move Editor into Last Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToLeftGroupAction), 'View: Move Editor into Left Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToRightGroupAction), 'View: Move Editor into Right Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToAboveGroupAction), 'View: Move Editor into Group Above', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveEditorToBelowGroupAction), 'View: Move Editor into Group Below', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToPreviousGroupAction), 'View: Split Editor into Previous Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToNextGroupAction), 'View: Split Editor into Next Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToFirstGroupAction), 'View: Split Editor into First Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToLastGroupAction), 'View: Split Editor into Last Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToLeftGroupAction), 'View: Split Editor into Left Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToRightGroupAction), 'View: Split Editor into Right Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToAboveGroupAction), 'View: Split Editor into Group Above', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(SplitEditorToBelowGroupAction), 'View: Split Editor into Group Below', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusActiveGroupAction), 'View: Focus Active Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusFirstGroupAction, { primary: KeyMod.CtrlCmd | KeyCode.Digit1 }), 'View: Focus First Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusLastGroupAction), 'View: Focus Last Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousGroup), 'View: Focus Previous Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextGroup), 'View: Focus Next Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusLeftGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.LeftArrow) }), 'View: Focus Left Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusRightGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Right Editor Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusAboveGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.UpArrow) }), 'View: Focus Editor Group Above', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusBelowGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.DownArrow) }), 'View: Focus Editor Group Below', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupLeftAction), 'View: New Editor Group to the Left', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupRightAction), 'View: New Editor Group to the Right', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupAboveAction), 'View: New Editor Group Above', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupBelowAction), 'View: New Editor Group Below', Categories.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigatePreviousAction), 'Go Previous'); registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateForwardInEditsAction), 'Go Forward in Edit Locations'); registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsInEditsAction), 'Go Back in Edit Locations'); @@ -254,21 +255,21 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsInNa registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigatePreviousInNavigationsAction), 'Go Previous in Navigation Locations'); registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateToLastNavigationLocationAction), 'Go to Last Navigation Location'); registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearEditorHistoryAction), 'Clear Editor History'); -registry.registerWorkbenchAction(SyncActionDescriptor.from(RevertAndCloseEditorAction), 'View: Revert and Close Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutSingleAction), 'View: Single Column Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsAction), 'View: Two Columns Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutThreeColumnsAction), 'View: Three Columns Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsAction), 'View: Two Rows Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutThreeRowsAction), 'View: Three Rows Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoByTwoGridAction), 'View: Grid Editor Layout (2x2)', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsRightAction), 'View: Two Rows Right Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsBottomAction), 'View: Two Columns Bottom Editor Layout', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleEditorTypeAction), 'View: Toggle Editor Type', CATEGORIES.View.value, ActiveEditorAvailableEditorIdsContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ReOpenInTextEditorAction), 'View: Reopen Editor With Text Editor', CATEGORIES.View.value, ActiveEditorAvailableEditorIdsContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorAction), 'View: Quick Open Previous Recently Used Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorAction), 'View: Quick Open Least Recently Used Editor', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Previous Recently Used Editor in Group', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Least Recently Used Editor in Group', CATEGORIES.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(RevertAndCloseEditorAction), 'View: Revert and Close Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutSingleAction), 'View: Single Column Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsAction), 'View: Two Columns Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutThreeColumnsAction), 'View: Three Columns Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsAction), 'View: Two Rows Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutThreeRowsAction), 'View: Three Rows Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoByTwoGridAction), 'View: Grid Editor Layout (2x2)', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsRightAction), 'View: Two Rows Right Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsBottomAction), 'View: Two Columns Bottom Editor Layout', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleEditorTypeAction), 'View: Toggle Editor Type', Categories.View.value, ActiveEditorAvailableEditorIdsContext); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ReOpenInTextEditorAction), 'View: Reopen Editor With Text Editor', Categories.View.value, ActiveEditorAvailableEditorIdsContext); +registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorAction), 'View: Quick Open Previous Recently Used Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorAction), 'View: Quick Open Least Recently Used Editor', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Previous Recently Used Editor in Group', Categories.View.value); +registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Least Recently Used Editor in Group', Categories.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousEditorFromHistoryAction), 'Quick Open Previous Editor from History'); registerAction2(NavigateForwardAction); @@ -547,17 +548,17 @@ appendEditorToolItem( ); // Editor Commands for Command Palette -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: KEEP_EDITOR_COMMAND_ID, title: { value: localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: CATEGORIES.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: PIN_EDITOR_COMMAND_ID, title: { value: localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: { value: localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: { value: localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: CATEGORIES.View }, when: ActiveEditorLastInGroupContext.toNegated() }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: CATEGORIES.View }, when: MultipleEditorGroupsContext }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: REOPEN_WITH_COMMAND_ID, title: { value: localize('reopenWith', "Reopen Editor With..."), original: 'Reopen Editor With...' }, category: CATEGORIES.View }, when: ActiveEditorAvailableEditorIdsContext }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: KEEP_EDITOR_COMMAND_ID, title: { value: localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: Categories.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: PIN_EDITOR_COMMAND_ID, title: { value: localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: { value: localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: { value: localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: Categories.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: Categories.View }, when: ActiveEditorLastInGroupContext.toNegated() }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: Categories.View }, when: MultipleEditorGroupsContext }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: REOPEN_WITH_COMMAND_ID, title: { value: localize('reopenWith', "Reopen Editor With..."), original: 'Reopen Editor With...' }, category: Categories.View }, when: ActiveEditorAvailableEditorIdsContext }); // File menu MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 69f5e571700..31d6bb4bf3f 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -25,7 +25,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { EditorResolution, IEditorOptions, IResourceEditorInput, ITextEditorOptions } from 'vs/platform/editor/common/editor'; @@ -1058,7 +1058,7 @@ function registerSplitEditorInGroupCommands(): void { super({ id: SPLIT_EDITOR_IN_GROUP, title: { value: localize('splitEditorInGroup', "Split Editor in Group"), original: 'Split Editor in Group' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ActiveEditorCanSplitInGroupContext, f1: true, keybinding: { @@ -1104,7 +1104,7 @@ function registerSplitEditorInGroupCommands(): void { super({ id: JOIN_EDITOR_IN_GROUP, title: { value: localize('joinEditorInGroup', "Join Editor in Group"), original: 'Join Editor in Group' }, - category: CATEGORIES.View, + category: Categories.View, precondition: SideBySideEditorActiveContext, f1: true, keybinding: { @@ -1124,7 +1124,7 @@ function registerSplitEditorInGroupCommands(): void { super({ id: TOGGLE_SPLIT_EDITOR_IN_GROUP, title: { value: localize('toggleJoinEditorInGroup', "Toggle Split Editor in Group"), original: 'Toggle Split Editor in Group' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.or(ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext), f1: true }); @@ -1146,7 +1146,7 @@ function registerSplitEditorInGroupCommands(): void { super({ id: TOGGLE_SPLIT_EDITOR_IN_GROUP_LAYOUT, title: { value: localize('toggleSplitEditorInGroupLayout', "Toggle Layout of Split Editor in Group"), original: 'Toggle Layout of Split Editor in Group' }, - category: CATEGORIES.View, + category: Categories.View, precondition: SideBySideEditorActiveContext, f1: true }); @@ -1174,7 +1174,7 @@ function registerFocusSideEditorsCommands(): void { super({ id: FOCUS_FIRST_SIDE_EDITOR, title: { value: localize('focusLeftSideEditor', "Focus First Side in Active Editor"), original: 'Focus First Side in Active Editor' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.or(SideBySideEditorActiveContext, TextCompareEditorActiveContext), f1: true }); @@ -1197,7 +1197,7 @@ function registerFocusSideEditorsCommands(): void { super({ id: FOCUS_SECOND_SIDE_EDITOR, title: { value: localize('focusRightSideEditor', "Focus Second Side in Active Editor"), original: 'Focus Second Side in Active Editor' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.or(SideBySideEditorActiveContext, TextCompareEditorActiveContext), f1: true }); @@ -1220,7 +1220,7 @@ function registerFocusSideEditorsCommands(): void { super({ id: FOCUS_OTHER_SIDE_EDITOR, title: { value: localize('focusOtherSideEditor', "Focus Other Side in Active Editor"), original: 'Focus Other Side in Active Editor' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.or(SideBySideEditorActiveContext, TextCompareEditorActiveContext), f1: true }); @@ -1283,7 +1283,7 @@ function registerOtherEditorCommands(): void { super({ id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: { value: localize('toggleEditorGroupLock', "Toggle Editor Group Lock"), original: 'Toggle Editor Group Lock' }, - category: CATEGORIES.View, + category: Categories.View, precondition: MultipleEditorGroupsContext, f1: true }); @@ -1298,7 +1298,7 @@ function registerOtherEditorCommands(): void { super({ id: LOCK_GROUP_COMMAND_ID, title: { value: localize('lockEditorGroup', "Lock Editor Group"), original: 'Lock Editor Group' }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.and(MultipleEditorGroupsContext, ActiveEditorGroupLockedContext.toNegated()), f1: true }); @@ -1314,7 +1314,7 @@ function registerOtherEditorCommands(): void { id: UNLOCK_GROUP_COMMAND_ID, title: { value: localize('unlockEditorGroup', "Unlock Editor Group"), original: 'Unlock Editor Group' }, precondition: ContextKeyExpr.and(MultipleEditorGroupsContext, ActiveEditorGroupLockedContext), - category: CATEGORIES.View, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 074fafd9d61..f68ea5c90e3 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -9,7 +9,8 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Action } from 'vs/base/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWorkbenchLayoutService, PanelAlignment, Parts, Position, positionToString } from 'vs/workbench/services/layout/browser/layoutService'; import { ActivityAction, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions'; import { IActivity } from 'vs/workbench/common/activity'; @@ -159,7 +160,7 @@ PositionPanelActionConfigs.forEach(positionPanelAction => { super({ id, title, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -193,7 +194,7 @@ AlignPanelActionConfigs.forEach(alignPanelAction => { super({ id, title: title, - category: CATEGORIES.View, + category: Categories.View, toggled: when.negate(), f1: true }); @@ -322,10 +323,10 @@ export class NextPanelViewAction extends SwitchPanelViewAction { } const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(TogglePanelAction, { primary: KeyMod.CtrlCmd | KeyCode.KeyJ }), 'View: Toggle Panel Visibility', CATEGORIES.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPanelAction), 'View: Focus into Panel', CATEGORIES.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousPanelViewAction), 'View: Previous Panel View', CATEGORIES.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NextPanelViewAction), 'View: Next Panel View', CATEGORIES.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(TogglePanelAction, { primary: KeyMod.CtrlCmd | KeyCode.KeyJ }), 'View: Toggle Panel Visibility', Categories.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPanelAction), 'View: Focus into Panel', Categories.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousPanelViewAction), 'View: Previous Panel View', Categories.View.value); +actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NextPanelViewAction), 'View: Next Panel View', Categories.View.value); registerAction2(class extends Action2 { constructor() { @@ -333,7 +334,7 @@ registerAction2(class extends Action2 { id: 'workbench.action.toggleMaximizedPanel', title: { value: localize('toggleMaximizedPanel', "Toggle Maximized Panel"), original: 'Toggle Maximized Panel' }, tooltip: localize('maximizePanel', "Maximize Panel Size"), - category: CATEGORIES.View, + category: Categories.View, f1: true, icon: maximizeIcon, // the workbench grid currently prevents us from supporting panel maximization with non-center panel alignment @@ -374,7 +375,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.closePanel', title: { value: localize('closePanel', "Close Panel"), original: 'Close Panel' }, - category: CATEGORIES.View, + category: Categories.View, icon: closeIcon, menu: [{ id: MenuId.CommandPalette, @@ -396,7 +397,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.closeAuxiliaryBar', title: { value: localize('closeSecondarySideBar', "Close Secondary Side Bar"), original: 'Close Secondary Side Bar' }, - category: CATEGORIES.View, + category: Categories.View, icon: closeIcon, menu: [{ id: MenuId.CommandPalette, @@ -500,7 +501,7 @@ class MovePanelToSidePanelAction extends MoveViewsBetweenPanelsAction { value: localize('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"), original: 'Move Panel Views To Secondary Side Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: false }); } @@ -515,7 +516,7 @@ export class MovePanelToSecondarySideBarAction extends MoveViewsBetweenPanelsAct value: localize('movePanelToSecondarySideBar', "Move Panel Views To Secondary Side Bar"), original: 'Move Panel Views To Secondary Side Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -536,7 +537,7 @@ class MoveSidePanelToPanelAction extends MoveViewsBetweenPanelsAction { value: localize('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"), original: 'Move Secondary Side Bar Views To Panel' }, - category: CATEGORIES.View, + category: Categories.View, f1: false }); } @@ -552,7 +553,7 @@ export class MoveSecondarySideBarToPanelAction extends MoveViewsBetweenPanelsAct value: localize('moveSidePanelToPanel', "Move Secondary Side Bar Views To Panel"), original: 'Move Secondary Side Bar Views To Panel' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarActions.ts b/src/vs/workbench/browser/parts/sidebar/sidebarActions.ts index 9ebb1e99eb7..974349fe5b3 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarActions.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarActions.ts @@ -10,7 +10,7 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { ViewContainerLocation } from 'vs/workbench/common/views'; @@ -20,7 +20,7 @@ export class FocusSideBarAction extends Action2 { super({ id: 'workbench.action.focusSideBar', title: { value: localize('focusSideBar', "Focus into Primary Side Bar"), original: 'Focus into Primary Side Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarActions.ts b/src/vs/workbench/browser/parts/statusbar/statusbarActions.ts index 1af3a67ebc2..d484e5a0ad2 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarActions.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarActions.ts @@ -11,7 +11,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StatusbarViewModel } from 'vs/workbench/browser/parts/statusbar/statusbarModel'; import { StatusBarFocused } from 'vs/workbench/common/contextkeys'; @@ -114,7 +114,7 @@ class FocusStatusBarAction extends Action2 { super({ id: 'workbench.action.focusStatusBar', title: { value: localize('focusStatusBar', "Focus Status Bar"), original: 'Focus Status Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 3c3da926ab7..29b322622bd 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -34,7 +34,7 @@ import { WindowTitle } from 'vs/workbench/browser/parts/titlebar/windowTitle'; import { CommandCenterControl } from 'vs/workbench/browser/parts/titlebar/commandCenterControl'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; export class TitlebarPart extends Part implements ITitleService { @@ -320,7 +320,7 @@ export class TitlebarPart extends Part implements ITitleService { super({ id: `workbench.action.focusTitleBar`, title: { value: localize('focusTitleBar', "Focus Title Bar"), original: 'Focus Title Bar' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, }); } diff --git a/src/vs/workbench/browser/parts/views/viewsService.ts b/src/vs/workbench/browser/parts/views/viewsService.ts index 18670e883ad..4e2b8c64478 100644 --- a/src/vs/workbench/browser/parts/views/viewsService.ts +++ b/src/vs/workbench/browser/parts/views/viewsService.ts @@ -27,7 +27,7 @@ import { PaneCompositeDescriptor, PaneCompositeRegistry, Extensions as PaneCompo import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { URI } from 'vs/base/common/uri'; import { IProgressIndicator } from 'vs/platform/progress/common/progress'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { FilterViewPaneContainer } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; @@ -139,7 +139,7 @@ export class ViewsService extends Disposable implements IViewsService { for (const viewDescriptor of views) { const disposables = new DisposableStore(); disposables.add(this.registerOpenViewAction(viewDescriptor)); - disposables.add(this.registerFocusViewAction(viewDescriptor, composite?.name && composite.name !== composite.id ? composite.name : CATEGORIES.View)); + disposables.add(this.registerFocusViewAction(viewDescriptor, composite?.name && composite.name !== composite.id ? composite.name : Categories.View)); disposables.add(this.registerResetViewLocationAction(viewDescriptor)); this.viewDisposable.set(viewDescriptor, disposables); } @@ -354,7 +354,7 @@ export class ViewsService extends Disposable implements IViewsService { return { value: localize('toggle view', "Toggle {0}", localizedTitle), original: `Toggle ${originalTitle}` }; } }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.has(getEnabledViewContainerContextKey(viewContainer.id)), keybinding: keybindings ? { ...keybindings, weight: KeybindingWeight.WorkbenchContrib } : undefined, f1: true @@ -422,7 +422,7 @@ export class ViewsService extends Disposable implements IViewsService { return { value: localize('toggle view', "Toggle {0}", localizedTitle), original: `Toggle ${originalTitle}` }; } }, - category: CATEGORIES.View, + category: Categories.View, precondition: ContextKeyExpr.has(`${viewDescriptor.id}.active`), keybinding: viewDescriptor.openCommandActionDescriptor!.keybindings ? { ...viewDescriptor.openCommandActionDescriptor!.keybindings, weight: KeybindingWeight.WorkbenchContrib } : undefined, f1: true diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index e50d4867a52..11806254df3 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -52,7 +52,7 @@ import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecy import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { localize } from 'vs/nls'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; @@ -436,7 +436,7 @@ export class BrowserMain extends Disposable { super({ id: 'workbench.action.resetUserData', title: { original: 'Reset User Data', value: localize('reset', "Reset User Data") }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: { id: MenuId.CommandPalette } diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 64742f9555f..3b2148055a5 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -121,11 +120,3 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR } } }); - -export const CATEGORIES = { - View: { value: localize('view', "View"), original: 'View' }, - Help: { value: localize('help', "Help"), original: 'Help' }, - Test: { value: localize('test', "Test"), original: 'Test' }, - Preferences: { value: localize('preferences', "Preferences"), original: 'Preferences' }, - Developer: { value: localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"), original: 'Developer' } -}; diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts index 73808153cd7..dc493bf295c 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts @@ -8,7 +8,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; class InspectKeyMap extends Action2 { @@ -17,7 +17,7 @@ class InspectKeyMap extends Action2 { super({ id: 'workbench.action.inspectKeyMappings', title: { value: localize('workbench.action.inspectKeyMap', "Inspect Key Mappings"), original: 'Inspect Key Mappings' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -38,7 +38,7 @@ class InspectKeyMapJSON extends Action2 { super({ id: 'workbench.action.inspectKeyMappingsJSON', title: { value: localize('workbench.action.inspectKeyMapJSON', "Inspect Key Mappings (JSON)"), original: 'Inspect Key Mappings (JSON)' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts index f0ea2a89e33..33be24d8270 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export class ToggleMinimapAction extends Action2 { @@ -22,7 +22,7 @@ export class ToggleMinimapAction extends Action2 { original: 'Toggle Minimap', mnemonicTitle: localize({ key: 'miMinimap', comment: ['&& denotes a mnemonic'] }, "&&Minimap") }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true), menu: { diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts index 0990dd2f454..9bc7a2b18ed 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { CATEGORIES, } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export class ToggleRenderControlCharacterAction extends Action2 { @@ -22,7 +22,7 @@ export class ToggleRenderControlCharacterAction extends Action2 { mnemonicTitle: localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Render &&Control Characters"), original: 'Toggle Control Characters' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true), menu: { diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts index c8bab9f321f..297c10d0cbb 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { CATEGORIES, } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; class ToggleRenderWhitespaceAction extends Action2 { @@ -22,7 +22,7 @@ class ToggleRenderWhitespaceAction extends Action2 { mnemonicTitle: localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "&&Render Whitespace"), original: 'Toggle Render Whitespace' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none'), menu: { diff --git a/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts index 5d6f3d31359..032f263903d 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Range } from 'vs/editor/common/core/range'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ITextMateService } from 'vs/workbench/services/textMate/browser/textMate'; import { IModelService } from 'vs/editor/common/services/model'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -30,7 +30,7 @@ class StartDebugTextMate extends Action2 { super({ id: 'editor.action.startDebugTextMate', title: { value: nls.localize('startDebugTextMate', "Start Text Mate Syntax Grammar Logging"), original: 'Start Text Mate Syntax Grammar Logging' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts index e9d58bface0..6eb6663c74c 100644 --- a/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts @@ -35,7 +35,7 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { Action2, MenuId } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; interface IExtensionProfileInformation { @@ -491,7 +491,7 @@ export class ShowRuntimeExtensionsAction extends Action2 { super({ id: 'workbench.action.showRuntimeExtensions', title: { value: nls.localize('showRuntimeExtensions', "Show Running Extensions"), original: 'Show Running Extensions' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, menu: { id: MenuId.ViewContainerTitle, diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 51e70fe0f8b..1519416d891 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -46,7 +46,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { MultiCommand } from 'vs/editor/browser/editorExtensions'; import { IWebview } from 'vs/workbench/contrib/webview/browser/webview'; import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations'; import { ExtensionRecommendationNotificationService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService'; import { IExtensionService, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; @@ -838,7 +838,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi this.registerExtensionAction({ id: 'workbench.extensions.action.installWebExtensionFromLocation', title: { value: localize('installWebExtensionFromLocation', "Install Web Extension..."), original: 'Install Web Extension...' }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: [{ id: MenuId.CommandPalette, when: ContextKeyExpr.or(CONTEXT_HAS_WEB_SERVER) @@ -1190,7 +1190,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi this.registerExtensionAction({ id: ReinstallAction.ID, title: { value: ReinstallAction.LABEL, original: 'Reinstall Extension...' }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: { id: MenuId.CommandPalette, when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER)) diff --git a/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts index 1c3145bffc1..aaed0100585 100644 --- a/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts @@ -14,7 +14,7 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { HIDE_NOTIFICATIONS_CENTER, HIDE_NOTIFICATION_TOAST } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { isIOS } from 'vs/base/common/platform'; @@ -80,7 +80,7 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: FeedbackStatusbarConribution.TOGGLE_FEEDBACK_COMMAND, - category: CATEGORIES.Help, + category: Categories.Help, title: localize('status.feedback', "Tweet Feedback") } }); diff --git a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts index dd60e5122aa..d207b297844 100644 --- a/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts @@ -11,7 +11,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { WebIssueService } from 'vs/workbench/contrib/issue/browser/issueService'; import { OpenIssueReporterArgs, OpenIssueReporterActionId, OpenIssueReporterApiCommandId } from 'vs/workbench/contrib/issue/common/commands'; @@ -86,7 +86,7 @@ class RegisterIssueContribution implements IWorkbenchContribution { const command: ICommandAction = { id: OpenIssueReporterActionId, title: { value: OpenIssueReporterActionLabel, original: 'Report Issue' }, - category: CATEGORIES.Help + category: Categories.Help }; MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }); diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts index 10c981ce6c8..09a805b8e5c 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import product from 'vs/platform/product/common/product'; import { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandAction } from 'vs/platform/action/common/action'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer, StopTracing } from 'vs/workbench/contrib/issue/electron-sandbox/issueActions'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; @@ -78,7 +78,7 @@ if (!!product.reportIssueUrl) { value: localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue..."), original: 'Report Issue...' }, - category: CATEGORIES.Help + category: Categories.Help }; MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: reportIssue }); diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts index 68ff563a009..fb21da86476 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts @@ -13,7 +13,7 @@ import { IssueType } from 'vs/platform/issue/common/issue'; import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; export class OpenProcessExplorer extends Action2 { @@ -24,7 +24,7 @@ export class OpenProcessExplorer extends Action2 { super({ id: OpenProcessExplorer.ID, title: { value: localize('openProcessExplorer', "Open Process Explorer"), original: 'Open Process Explorer' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -44,7 +44,7 @@ export class ReportPerformanceIssueUsingReporterAction extends Action2 { super({ id: ReportPerformanceIssueUsingReporterAction.ID, title: { value: localize({ key: 'reportPerformanceIssue', comment: [`Here, 'issue' means problem or bug`] }, "Report Performance Issue..."), original: 'Report Performance Issue' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true }); } @@ -64,7 +64,7 @@ export class StopTracing extends Action2 { super({ id: StopTracing.ID, title: { value: localize('stopTracing', "Stop Tracing"), original: 'Stop Tracing' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts b/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts index 5f6cdfb3298..5e7443e410c 100644 --- a/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts +++ b/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { rendererLogChannelId } from 'vs/workbench/contrib/logs/common/logConstants'; import { IOutputService } from 'vs/workbench/services/output/common/output'; @@ -17,7 +17,7 @@ class ToggleKeybindingsLogAction extends Action2 { super({ id: 'workbench.action.toggleKeybindingsLog', title: { value: nls.localize('toggleKeybindingsLog', "Toggle Keyboard Shortcuts Troubleshooting"), original: 'Toggle Keyboard Shortcuts Troubleshooting' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts index d78954e856e..992093fe0b3 100644 --- a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -26,7 +27,7 @@ class WebLogOutputChannels extends Disposable implements IWorkbenchContribution this.instantiationService.createInstance(LogsDataCleaner); const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); - workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenWindowSessionLogFileAction), 'Developer: Open Window Log File (Session)...', CATEGORIES.Developer.value); + workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenWindowSessionLogFileAction), 'Developer: Open Window Log File (Session)...', Categories.Developer.value); } } diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 636c211ffcd..f8f07b98ad4 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -5,7 +5,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Action2, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; @@ -22,7 +23,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { URI } from 'vs/base/common/uri'; const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SetLogLevelAction), 'Developer: Set Log Level...', CATEGORIES.Developer.value); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SetLogLevelAction), 'Developer: Set Log Level...', Categories.Developer.value); class LogOutputChannels extends Disposable implements IWorkbenchContribution { @@ -62,7 +63,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { super({ id: Constants.showWindowLogActionId, title: { value: nls.localize('show window log', "Show Window Log"), original: 'Show Window Log' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts index 022c66402f2..26e63c77ca9 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts @@ -5,7 +5,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { OpenLogsFolderAction, OpenExtensionLogsFolderAction } from 'vs/workbench/contrib/logs/electron-sandbox/logsActions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -45,5 +46,5 @@ class NativeLogOutputChannels extends Disposable implements IWorkbenchContributi Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeLogOutputChannels, LifecyclePhase.Restored); const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLogsFolderAction), 'Developer: Open Logs Folder', CATEGORIES.Developer.value); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenExtensionLogsFolderAction), 'Developer: Open Extension Logs Folder', CATEGORIES.Developer.value); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLogsFolderAction), 'Developer: Open Logs Folder', Categories.Developer.value); +workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenExtensionLogsFolderAction), 'Developer: Open Extension Logs Folder', Categories.Developer.value); diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 3512616b8b8..d31a252577c 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -6,7 +6,7 @@ import 'vs/workbench/contrib/markers/browser/markersFileDecorations'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { localize } from 'vs/nls'; @@ -201,7 +201,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.problems.focus', title: { value: Messages.MARKERS_PANEL_SHOW_LABEL, original: 'Focus Problems (Errors, Warnings, Infos)' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, }); } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts index 712c2369044..b555b4709ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts @@ -26,7 +26,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; import { IWebview } from 'vs/workbench/contrib/webview/browser/webview'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IOutputService } from 'vs/workbench/services/output/common/output'; import { rendererLogChannelId } from 'vs/workbench/contrib/logs/common/logConstants'; import { ILogService } from 'vs/platform/log/common/log'; @@ -550,7 +550,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.toggleNotebookClipboardLog', title: { value: localize('toggleNotebookClipboardLog', "Toggle Notebook Clipboard Troubleshooting"), original: 'Toggle Notebook Clipboard Troubleshooting' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts index 2165fa94cc2..7c37a41ac75 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts @@ -12,7 +12,7 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Memento } from 'vs/workbench/common/memento'; import { HAS_OPENED_NOTEBOOK } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; @@ -87,7 +87,7 @@ registerAction2(class NotebookClearNotebookLayoutAction extends Action2 { }, f1: true, precondition: ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true), - category: CATEGORIES.Developer, + category: Categories.Developer, }); } run(accessor: ServicesAccessor): void { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts b/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts index 3644400d74b..ce2b9849c2a 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts @@ -7,7 +7,7 @@ import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/commo import { localize } from 'vs/nls'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { getNotebookEditorFromEditorPane, ICellViewModel, ICommonCellViewModelLayoutChangeInfo, INotebookDeltaCellStatusBarItems, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; @@ -126,7 +126,7 @@ registerAction2(class extends Action2 { value: localize('workbench.notebook.toggleLayoutTroubleshoot', "Toggle Layout Troubleshoot"), original: 'Toggle Notebook Layout Troubleshoot' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -152,7 +152,7 @@ registerAction2(class extends Action2 { value: localize('workbench.notebook.inspectLayout', "Inspect Notebook Layout"), original: 'Inspect Notebook Layout' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -180,7 +180,7 @@ registerAction2(class extends Action2 { value: localize('workbench.notebook.clearNotebookEdtitorTypeCache', "Clear Notebook Editor Type Cache"), original: 'Clear Notebook Editor Cache' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 96e1254736d..08aebc57bca 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -30,7 +30,7 @@ import { assertIsDefined } from 'vs/base/common/types'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { EditorExtensions } from 'vs/workbench/common/editor'; // Register Service @@ -130,7 +130,7 @@ registerAction2(class extends Action2 { super({ id: `workbench.output.action.clearOutput`, title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' }, - category: CATEGORIES.View, + category: Categories.View, menu: [{ id: MenuId.ViewTitle, when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), @@ -223,7 +223,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.showLogs', title: { value: nls.localize('showLogs', "Show Logs..."), original: 'Show Logs...' }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: { id: MenuId.CommandPalette, }, @@ -268,7 +268,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.openLogFile', title: { value: nls.localize('openLogFile', "Open Log File..."), original: 'Open Log File...' }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: { id: MenuId.CommandPalette, }, diff --git a/src/vs/workbench/contrib/performance/browser/performance.contribution.ts b/src/vs/workbench/contrib/performance/browser/performance.contribution.ts index de72a95db03..b7fbee24b67 100644 --- a/src/vs/workbench/contrib/performance/browser/performance.contribution.ts +++ b/src/vs/workbench/contrib/performance/browser/performance.contribution.ts @@ -8,7 +8,7 @@ import { registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { EditorExtensions, IEditorSerializer, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; import { PerfviewContrib, PerfviewInput } from 'vs/workbench/contrib/performance/browser/perfviewEditor'; @@ -45,7 +45,7 @@ registerAction2(class extends Action2 { super({ id: 'perfview.show', title: { value: localize('show.label', "Startup Performance"), original: 'Startup Performance' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -64,7 +64,7 @@ registerAction2(class PrintServiceCycles extends Action2 { super({ id: 'perf.insta.printAsyncCycles', title: { value: localize('cycles', "Print Service Cycles"), original: 'Print Service Cycles' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -88,7 +88,7 @@ registerAction2(class PrintServiceTraces extends Action2 { super({ id: 'perf.insta.printTraces', title: { value: localize('insta.trace', "Print Service Traces"), original: 'Print Service Traces' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -112,7 +112,7 @@ registerAction2(class PrintEventProfiling extends Action2 { super({ id: 'perf.event.profiling', title: { value: localize('emitter', "Print Emitter Profiles"), original: 'Print Emitter Profiles' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts index 1ee86f9e52c..c08156d9246 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts @@ -19,7 +19,7 @@ import { Action2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { IDebugService, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug'; @@ -235,7 +235,7 @@ export class OpenViewPickerAction extends Action2 { super({ id: OpenViewPickerAction.ID, title: { value: localize('openView', "Open View"), original: 'Open View' }, - category: CATEGORIES.View, + category: Categories.View, f1: true }); } @@ -258,7 +258,7 @@ export class QuickAccessViewPickerAction extends Action2 { super({ id: QuickAccessViewPickerAction.ID, title: { value: localize('quickOpenView', "Quick Open View"), original: 'Quick Open View' }, - category: CATEGORIES.View, + category: Categories.View, f1: false, // hide quick pickers from command palette to not confuse with the other entry that shows a input field keybinding: { weight: KeybindingWeight.WorkbenchContrib, diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 1bf27f3153c..a65fefa0da1 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -25,7 +25,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { firstOrDefault } from 'vs/base/common/arrays'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { PersistentConnection } from 'vs/platform/remote/common/remoteAgentConnection'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; @@ -281,7 +281,7 @@ if (enableDiagnostics) { super({ id: 'workbench.action.triggerReconnect', title: { value: localize('triggerReconnect', "Connection: Trigger Reconnect"), original: 'Connection: Trigger Reconnect' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, }); } @@ -296,7 +296,7 @@ if (enableDiagnostics) { super({ id: 'workbench.action.pauseSocketWriting', title: { value: localize('pauseSocketWriting', "Connection: Pause socket writing"), original: 'Connection: Pause socket writing' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, }); } diff --git a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts index a414f31246d..b4581ae1494 100644 --- a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { SnippetCompletion, SnippetCompletionProvider } from 'vs/workbench/contrib/snippets/browser/snippetCompletionProvider'; import { Position } from 'vs/editor/common/core/position'; import { createModelServices, instantiateTextModel } from 'vs/editor/test/common/testTextModel'; -import { ISnippetsService } from "vs/workbench/contrib/snippets/browser/snippets"; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets'; import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { CompletionContext, CompletionItemLabel, CompletionItemRanges, CompletionTriggerKind } from 'vs/editor/common/languages'; import { DisposableStore } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 8cfc44e4247..c6c85fe83bf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -52,7 +52,7 @@ import { ITerminalQuickPickItem } from 'vs/workbench/contrib/terminal/browser/te import { IThemeService } from 'vs/platform/theme/common/themeService'; import { getIconId, getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { clearShellFileHistory, getCommandHistory } from 'vs/workbench/contrib/terminal/common/history'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; @@ -2232,7 +2232,7 @@ export function registerTerminalActions() { id: TerminalCommandId.WriteDataToTerminal, title: { value: localize('workbench.action.terminal.writeDataToTerminal', "Write Data to Terminal"), original: 'Write Data to Terminal' }, f1: true, - category: CATEGORIES.Developer.value + category: Categories.Developer.value }); } async run(accessor: ServicesAccessor) { diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 53579678c41..8e02aecd2f5 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -21,7 +21,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { FocusedViewContext } from 'vs/workbench/common/contextkeys'; import { ViewContainerLocation } from 'vs/workbench/common/views'; import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; @@ -41,7 +41,7 @@ import { expandAndGetTestById, IMainThreadTestCollection, ITestService, testsInF import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; -const category = CATEGORIES.Test; +const category = Categories.Test; const enum ActionOrder { // Navigation: diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index d401d33c5da..fb9b48fd009 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -55,7 +55,7 @@ import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listSe import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { flatTestItemDelimiter } from 'vs/workbench/contrib/testing/browser/explorerProjections/display'; import { getTestItemContextOverlay } from 'vs/workbench/contrib/testing/browser/explorerProjections/testItemContextOverlay'; @@ -1686,7 +1686,7 @@ export class GoToNextMessageAction extends EditorAction2 { f1: true, title: { value: localize('testing.goToNextMessage', "Go to Next Test Failure"), original: 'Go to Next Test Failure' }, icon: Codicon.arrowDown, - category: CATEGORIES.Test, + category: Categories.Test, keybinding: { primary: KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib + 1, @@ -1716,7 +1716,7 @@ export class GoToPreviousMessageAction extends EditorAction2 { f1: true, title: { value: localize('testing.goToPreviousMessage', "Go to Previous Test Failure"), original: 'Go to Previous Test Failure' }, icon: Codicon.arrowUp, - category: CATEGORIES.Test, + category: Categories.Test, keybinding: { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib + 1, @@ -1746,7 +1746,7 @@ export class OpenMessageInEditorAction extends EditorAction2 { f1: false, title: { value: localize('testing.openMessageInEditor', "Open in Editor"), original: 'Open in Editor' }, icon: Codicon.linkExternal, - category: CATEGORIES.Test, + category: Categories.Test, menu: [{ id: MenuId.TestPeekTitle }], }); } @@ -1764,7 +1764,7 @@ export class ToggleTestingPeekHistory extends EditorAction2 { f1: true, title: { value: localize('testing.toggleTestingPeekHistory', "Toggle Test History in Peek"), original: 'Toggle Test History in Peek' }, icon: Codicon.history, - category: CATEGORIES.Test, + category: Categories.Test, menu: [{ id: MenuId.TestPeekTitle, group: 'navigation', diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index adb89a15354..8a094b654d6 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -8,7 +8,7 @@ import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { MenuRegistry, MenuId, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWorkbenchThemeService, IWorkbenchTheme, ThemeSettingTarget, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IWorkbenchProductIconTheme, ThemeSettings } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { VIEWLET_ID, IExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/common/extensions'; import { IExtensionGalleryService, IExtensionManagementService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -358,7 +358,7 @@ registerAction2(class extends Action2 { super({ id: SelectColorThemeCommandId, title: { value: localize('selectTheme.label', "Color Theme"), original: 'Color Theme' }, - category: CATEGORIES.Preferences, + category: Categories.Preferences, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -400,7 +400,7 @@ registerAction2(class extends Action2 { super({ id: SelectFileIconThemeCommandId, title: { value: localize('selectIconTheme.label', "File Icon Theme"), original: 'File Icon Theme' }, - category: CATEGORIES.Preferences, + category: Categories.Preferences, f1: true }); } @@ -435,7 +435,7 @@ registerAction2(class extends Action2 { super({ id: SelectProductIconThemeCommandId, title: { value: localize('selectProductIconTheme.label', "Product Icon Theme"), original: 'Product Icon Theme' }, - category: CATEGORIES.Preferences, + category: Categories.Preferences, f1: true }); } @@ -546,7 +546,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.generateColorTheme', title: { value: localize('generateColorTheme.label', "Generate Color Theme From Current Settings"), original: 'Generate Color Theme From Current Settings' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -600,7 +600,7 @@ registerAction2(class extends Action2 { super({ id: toggleLightDarkThemesCommandId, title: { value: localize('toggleLightDarkThemes.label', "Toggle between Light/Dark Themes"), original: 'Toggle between Light/Dark Themes' }, - category: CATEGORIES.Preferences, + category: Categories.Preferences, f1: true, }); } diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index 78296bf7b6e..cbf2d71d4ab 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -7,7 +7,8 @@ import 'vs/platform/update/common/update.config.contribution'; import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor, MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CheckForVSCodeUpdateAction, CONTEXT_UPDATE_STATE, SwitchProductQualityContribution } from 'vs/workbench/contrib/update/browser/update'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -103,7 +104,7 @@ if (isWindows) { super({ id: '_update.applyupdate', title: { value: localize('applyUpdate', "Apply Update..."), original: 'Apply Update...' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, precondition: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle) }); diff --git a/src/vs/workbench/contrib/url/browser/url.contribution.ts b/src/vs/workbench/contrib/url/browser/url.contribution.ts index 5ee80ca2ac1..994320e7863 100644 --- a/src/vs/workbench/contrib/url/browser/url.contribution.ts +++ b/src/vs/workbench/contrib/url/browser/url.contribution.ts @@ -17,7 +17,7 @@ import { manageTrustedDomainSettingsCommand } from 'vs/workbench/contrib/url/bro import { TrustedDomainsFileSystemProvider } from 'vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider'; import { OpenerValidatorContributions } from 'vs/workbench/contrib/url/browser/trustedDomainsValidator'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; @@ -27,7 +27,7 @@ class OpenUrlAction extends Action2 { super({ id: 'workbench.action.url.openUrl', title: { value: localize('openUrl', "Open URL"), original: 'Open URL' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts index 6c1d719b0bf..df6317f8117 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts @@ -15,7 +15,7 @@ import { QuickPickItem, IQuickInputService, IQuickPickItem } from 'vs/platform/q import { asJson, asText, IRequestService } from 'vs/platform/request/common/request'; import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileManagementService, IUserDataProfileImportExportService, PROFILES_CATEGORY, ManageProfilesSubMenu, IUserDataProfileService, PROFILES_ENABLEMENT_CONTEXT, HAS_PROFILES_CONTEXT, MANAGE_PROFILES_ACTION_ID, PROFILE_FILTER } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { compare } from 'vs/base/common/strings'; @@ -518,7 +518,7 @@ registerAction2(class CleanupProfilesAction extends Action2 { value: localize('cleanup profile', "Cleanup Settings Profiles"), original: 'Cleanup Profiles' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, precondition: PROFILES_ENABLEMENT_CONTEXT, }); @@ -537,7 +537,7 @@ registerAction2(class ResetWorkspacesAction extends Action2 { value: localize('reset workspaces', "Reset Workspace Settings Profiles Associations"), original: 'Reset Workspace Settings Profiles Associations' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, precondition: PROFILES_ENABLEMENT_CONTEXT, }); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index f1fbbfc5079..dda7b8167bd 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -49,7 +49,7 @@ import { UserDataSyncDataViews } from 'vs/workbench/contrib/userDataSync/browser import { IUserDataSyncWorkbenchService, getSyncAreaLabel, AccountStatus, CONTEXT_SYNC_STATE, CONTEXT_SYNC_ENABLEMENT, CONTEXT_ACCOUNT_STATE, CONFIGURE_SYNC_COMMAND_ID, SHOW_SYNC_LOG_COMMAND_ID, SYNC_VIEW_CONTAINER_ID, SYNC_TITLE, SYNC_VIEW_ICON, CONTEXT_HAS_CONFLICTS } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { Codicon } from 'vs/base/common/codicons'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { IHostService } from 'vs/workbench/services/host/browser/host'; @@ -1127,7 +1127,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo super({ id: 'workbench.userDataSync.actions.help', title: { value: SYNC_TITLE, original: 'Settings Sync' }, - category: CATEGORIES.Help, + category: Categories.Help, menu: [{ id: MenuId.CommandPalette, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized)), @@ -1139,7 +1139,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, { command: { id: 'workbench.userDataSync.actions.help', - title: CATEGORIES.Help.value + title: Categories.Help.value }, when: ContextKeyExpr.equals('viewContainer', SYNC_VIEW_CONTAINER_ID), group: '1_help', diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts index 210601cf0db..2fd68ddc29c 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts @@ -65,4 +65,3 @@ export class UserDataSyncTrigger extends Disposable implements IWorkbenchContrib return undefined; } } - diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts index 086853c99d9..222d6088bfc 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/webviewCommands.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Action2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; export class OpenWebviewDeveloperToolsAction extends Action2 { @@ -15,7 +15,7 @@ export class OpenWebviewDeveloperToolsAction extends Action2 { super({ id: 'workbench.action.webview.openDeveloperTools', title: { value: nls.localize('openToolsLabel', "Open Webview Developer Tools"), original: 'Open Webview Developer Tools' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts index 95a869f9ffa..a9f8728585c 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts @@ -10,7 +10,7 @@ import { Action2, MenuId } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWebviewService, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_ENABLED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, IWebview } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewEditor } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditor'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; @@ -110,7 +110,7 @@ export class ReloadWebviewAction extends Action2 { super({ id: ReloadWebviewAction.ID, title: { value: ReloadWebviewAction.LABEL, original: 'Reload Webviews' }, - category: CATEGORIES.Developer, + category: Categories.Developer, menu: [{ id: MenuId.CommandPalette }] diff --git a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts index 78cd06a4e0f..5ad26e2f482 100644 --- a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts @@ -12,7 +12,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -257,10 +258,10 @@ class WelcomeOverlay extends Disposable { } Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(SyncActionDescriptor.from(WelcomeOverlayAction), 'Help: User Interface Overview', CATEGORIES.Help.value); + .registerWorkbenchAction(SyncActionDescriptor.from(WelcomeOverlayAction), 'Help: User Interface Overview', Categories.Help.value); Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(SyncActionDescriptor.from(HideWelcomeOverlayAction, { primary: KeyCode.Escape }, OVERLAY_VISIBLE), 'Help: Hide Interface Overview', CATEGORIES.Help.value); + .registerWorkbenchAction(SyncActionDescriptor.from(HideWelcomeOverlayAction, { primary: KeyCode.Escape }, OVERLAY_VISIBLE), 'Help: Hide Interface Overview', Categories.Help.value); // theming diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts index 0c1668932d8..be550f72b66 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts @@ -12,7 +12,8 @@ import { EditorWalkThroughAction, EditorWalkThroughInputSerializer } from 'vs/wo import { Registry } from 'vs/platform/registry/common/platform'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; @@ -30,7 +31,7 @@ Registry.as(EditorExtensions.EditorPane) Registry.as(Extensions.WorkbenchActions) .registerWorkbenchAction( SyncActionDescriptor.from(EditorWalkThroughAction), - 'Help: Interactive Editor Playground', CATEGORIES.Help.value); + 'Help: Interactive Editor Playground', Categories.Help.value); Registry.as(EditorExtensions.EditorFactory).registerEditorSerializer(EditorWalkThroughInputSerializer.ID, EditorWalkThroughInputSerializer); diff --git a/src/vs/workbench/electron-sandbox/actions/developerActions.ts b/src/vs/workbench/electron-sandbox/actions/developerActions.ts index 618b5d37319..ab1d188313e 100644 --- a/src/vs/workbench/electron-sandbox/actions/developerActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/developerActions.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Action2, MenuId } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -20,7 +20,7 @@ export class ToggleDevToolsAction extends Action2 { super({ id: 'workbench.action.toggleDevTools', title: { value: localize('toggleDevTools', "Toggle Developer Tools"), original: 'Toggle Developer Tools' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib + 50, @@ -49,7 +49,7 @@ export class ConfigureRuntimeArgumentsAction extends Action2 { super({ id: 'workbench.action.configureRuntimeArguments', title: { value: localize('configureRuntimeArguments', "Configure Runtime Arguments"), original: 'Configure Runtime Arguments' }, - category: CATEGORIES.Preferences, + category: Categories.Preferences, f1: true }); } @@ -72,7 +72,7 @@ export class ToggleSharedProcessAction extends Action2 { super({ id: 'workbench.action.toggleSharedProcess', title: { value: localize('toggleSharedProcess', "Toggle Shared Process"), original: 'Toggle Shared Process' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } @@ -88,7 +88,7 @@ export class ReloadWindowWithExtensionsDisabledAction extends Action2 { super({ id: 'workbench.action.reloadWindowWithExtensionsDisabled', title: { value: localize('reloadWindowWithExtensionsDisabled', "Reload With Extensions Disabled"), original: 'Reload With Extensions Disabled' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts index 438925fd576..2c8e6d83bfc 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -21,7 +21,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { Codicon } from 'vs/base/common/codicons'; import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -95,7 +95,7 @@ export class ZoomInAction extends BaseZoomAction { mnemonicTitle: localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In"), original: 'Zoom In' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -125,7 +125,7 @@ export class ZoomOutAction extends BaseZoomAction { mnemonicTitle: localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out"), original: 'Zoom Out' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -159,7 +159,7 @@ export class ZoomResetAction extends BaseZoomAction { mnemonicTitle: localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom"), original: 'Reset Zoom' }, - category: CATEGORIES.View, + category: Categories.View, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index 3db527d7d97..b4a2c42c13d 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -23,7 +23,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; // --- bisect service @@ -219,7 +219,7 @@ registerAction2(class extends Action2 { super({ id: 'extension.bisect.start', title: { value: localize('title.start', "Start Extension Bisect"), original: 'Start Extension Bisect' }, - category: CATEGORIES.Help, + category: Categories.Help, f1: true, precondition: ExtensionBisectUi.ctxIsBisectActive.negate(), menu: { diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index bbe1bd7cb86..cfde0bbd984 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -27,7 +27,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -874,7 +874,7 @@ if (isWeb) { super({ id: 'workbench.extensions.action.openInstalledWebExtensionsResource', title: { value: localize('openInstalledWebExtensionsResource', "Open Installed Web Extensions Resource"), original: 'Open Installed Web Extensions Resource' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true, precondition: IsWebContext }); diff --git a/src/vs/workbench/services/extensions/common/extensionHostManager.ts b/src/vs/workbench/services/extensions/common/extensionHostManager.ts index 2aceff7689b..41e7ef11f1d 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostManager.ts @@ -20,7 +20,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { StopWatch } from 'vs/base/common/stopwatch'; import { VSBuffer } from 'vs/base/common/buffer'; import { IExtensionHost, ExtensionHostKind, ActivationKind, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService, ExtensionRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Barrier } from 'vs/base/common/async'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; @@ -708,7 +708,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 { value: nls.localize('measureExtHostLatency', "Measure Extension Host Latency"), original: 'Measure Extension Host Latency' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } diff --git a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts index 4077c1661e4..71edeaee506 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts @@ -34,7 +34,7 @@ import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEn import { IWebWorkerExtensionHostDataProvider, IWebWorkerExtensionHostInitData, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ILogService } from 'vs/platform/log/common/log'; -import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Schemas } from 'vs/base/common/network'; import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { updateProxyConfigurationsScope } from 'vs/platform/request/common/request'; @@ -704,7 +704,7 @@ class RestartExtensionHostAction extends Action2 { super({ id: 'workbench.action.restartExtensionHost', title: { value: nls.localize('restartExtensionHost', "Restart Extension Host"), original: 'Restart Extension Host' }, - category: CATEGORIES.Developer, + category: Categories.Developer, f1: true }); } From 6e80c4dafd7d44a4339eadd079ba94a7255567d0 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 09:47:53 +0200 Subject: [PATCH 320/599] use common action categories in a few more places --- .../contrib/stickyScroll/browser/stickyScrollActions.ts | 4 ++-- src/vs/platform/action/common/action.ts | 3 ++- src/vs/platform/actions/common/menuResetAction.ts | 3 ++- .../languageStatus/browser/languageStatus.contribution.ts | 6 ++---- .../browser/gettingStarted.contribution.ts | 3 ++- .../services/extensionManagement/browser/extensionBisect.ts | 4 ++-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts index 30e8e3d9363..4e3b93c0502 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts @@ -5,6 +5,7 @@ import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Action2, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -19,8 +20,7 @@ export class ToggleStickyScroll extends Action2 { mnemonicTitle: localize('miStickyScroll', "&&Sticky Scroll"), original: 'Toggle Sticky Scroll', }, - // Hardcoding due to import violation - category: { value: localize('view', "View"), original: 'View' }, + category: Categories.View, toggled: ContextKeyExpr.equals('config.editor.stickyScroll.enabled', true), menu: [ { id: MenuId.CommandPalette }, diff --git a/src/vs/platform/action/common/action.ts b/src/vs/platform/action/common/action.ts index 146fb9f0035..38d336ea603 100644 --- a/src/vs/platform/action/common/action.ts +++ b/src/vs/platform/action/common/action.ts @@ -6,6 +6,7 @@ import { URI, UriDto } from 'vs/base/common/uri'; import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { Categories } from './actionCommonCategories'; export interface ILocalizedString { @@ -60,7 +61,7 @@ export interface ICommandAction { id: string; title: string | ICommandActionTitle; shortTitle?: string | ICommandActionTitle; - category?: string | ILocalizedString; + category?: keyof typeof Categories | ILocalizedString | string; tooltip?: string | ILocalizedString; icon?: Icon; source?: string; diff --git a/src/vs/platform/actions/common/menuResetAction.ts b/src/vs/platform/actions/common/menuResetAction.ts index c482594103a..6cebce22257 100644 --- a/src/vs/platform/actions/common/menuResetAction.ts +++ b/src/vs/platform/actions/common/menuResetAction.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { Action2, IMenuService } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; @@ -17,7 +18,7 @@ export class MenuHiddenStatesReset extends Action2 { value: localize('title', 'Reset All Menus'), original: 'Reset All Menus' }, - category: localize('cat', 'View'), + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts b/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts index 63b120d3b3c..22af57bcfa3 100644 --- a/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts +++ b/src/vs/workbench/contrib/languageStatus/browser/languageStatus.contribution.ts @@ -30,6 +30,7 @@ import { equals } from 'vs/base/common/arrays'; import { URI } from 'vs/base/common/uri'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; class LanguageStatusViewModel { @@ -402,10 +403,7 @@ registerAction2(class extends Action2 { value: localize('reset', 'Reset Language Status Interaction Counter'), original: 'Reset Language Status Interaction Counter' }, - category: { - value: localize('cat', 'View'), - original: 'View' - }, + category: Categories.View, f1: true }); } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts index 7bdc86fa5bc..7b1282eed4e 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts @@ -30,6 +30,7 @@ import { IExtensionManagementServerService } from 'vs/workbench/services/extensi import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { StartupPageContribution, } from 'vs/workbench/contrib/welcomeGettingStarted/browser/startupPage'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; export * as icons from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedIcons'; @@ -39,7 +40,7 @@ registerAction2(class extends Action2 { super({ id: 'workbench.action.openWalkthrough', title: { value: localize('miGetStarted', "Get Started"), original: 'Get Started' }, - category: localize('help', "Help"), + category: Categories.Help, f1: true, menu: { id: MenuId.MenubarHelpMenu, diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index b4a2c42c13d..c9d26ad3b32 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -259,7 +259,7 @@ registerAction2(class extends Action2 { super({ id: 'extension.bisect.next', title: { value: localize('title.isBad', "Continue Extension Bisect"), original: 'Continue Extension Bisect' }, - category: localize('help', "Help"), + category: Categories.Help, f1: true, precondition: ExtensionBisectUi.ctxIsBisectActive }); @@ -346,7 +346,7 @@ registerAction2(class extends Action2 { super({ id: 'extension.bisect.stop', title: { value: localize('title.stop', "Stop Extension Bisect"), original: 'Stop Extension Bisect' }, - category: localize('help', "Help"), + category: Categories.Help, f1: true, precondition: ExtensionBisectUi.ctxIsBisectActive }); From 6fb1636fc438e65c26a1b6b838c9816e619d5f69 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2022 09:49:08 +0200 Subject: [PATCH 321/599] insta :lipstick: (#162714) --- src/vs/platform/instantiation/common/instantiationService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 21908bbcff0..3840b1bec11 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -111,7 +111,7 @@ export class InstantiationService implements IInstantiationService { } // now create the instance - return new ctor(...[...args, ...serviceArgs]); + return Reflect.construct(ctor, args.concat(serviceArgs)); } private _setServiceInstance(id: ServiceIdentifier, instance: T): void { From 7b28c64d7693415a92556aab9cb2b246420817d6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2022 09:50:02 +0200 Subject: [PATCH 322/599] have a toggle-title for toggle sticky scroll (#162717) --- .../contrib/stickyScroll/browser/stickyScrollActions.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts index 30e8e3d9363..54cc4514cd7 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts @@ -16,12 +16,16 @@ export class ToggleStickyScroll extends Action2 { id: 'editor.action.toggleStickyScroll', title: { value: localize('toggleStickyScroll', "Toggle Sticky Scroll"), - mnemonicTitle: localize('miStickyScroll', "&&Sticky Scroll"), + mnemonicTitle: localize('mitoggleStickyScroll', "&&Toggle Sticky Scroll"), original: 'Toggle Sticky Scroll', }, // Hardcoding due to import violation category: { value: localize('view', "View"), original: 'View' }, - toggled: ContextKeyExpr.equals('config.editor.stickyScroll.enabled', true), + toggled: { + condition: ContextKeyExpr.equals('config.editor.stickyScroll.enabled', true), + title: localize('stickyScroll', "Sticky Scroll"), + mnemonicTitle: localize('miStickyScroll', "&&Sticky Scroll"), + }, menu: [ { id: MenuId.CommandPalette }, { id: MenuId.MenubarViewMenu, group: '5_editor', order: 6 }, From ced865edea2364cd8a99fb9f04be7f73d3ca72ef Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 12:07:42 +0200 Subject: [PATCH 323/599] fix telemetry annotation for freeze event --- .../performance/electron-sandbox/rendererAutoProfiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index 6464cd8d16f..b80db72dddb 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -121,7 +121,7 @@ type TelemetryEventClassification = { owner: 'jrieken'; comment: 'Insight about what happened before/while a long task was reported'; sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate CPU samples and events' }; - timestamp: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Unix time at which the long task approximately happened' }; + timestamp: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Unix time at which the long task approximately happened' }; recentCommands: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Events prior to the long task' }; views: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Visible views' }; editors: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Visible editor' }; From a40b5131a05f12235845126dc0262145c94576ea Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 12:39:26 +0200 Subject: [PATCH 324/599] track duration of `setContext` API command invocation renderer freeze detection suggests that this command happens before freezes occur... Maybe listener leaks --- .../contextkey/browser/contextKeyService.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 07a136ef7b9..0ebe4e7c7ef 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -10,12 +10,14 @@ import { TernarySearchTree } from 'vs/base/common/map'; import { MarshalledObject } from 'vs/base/common/marshalling'; import { MarshalledId } from 'vs/base/common/marshallingIds'; import { cloneAndChange, distinct } from 'vs/base/common/objects'; +import { StopWatch } from 'vs/base/common/stopwatch'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpression, ContextKeyInfo, ContextKeyValue, IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, RawContextKey, SET_CONTEXT_COMMAND_ID } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context'; @@ -603,7 +605,27 @@ function findContextAttr(domNode: IContextKeyServiceTarget | null): number { } export function setContext(accessor: ServicesAccessor, contextKey: any, contextValue: any) { - accessor.get(IContextKeyService).createKey(String(contextKey), stringifyURIs(contextValue)); + const contextKeyService = accessor.get(IContextKeyService); + const telemetryService = accessor.get(ITelemetryService); + + const sw = new StopWatch(true); + contextKeyService.createKey(String(contextKey), stringifyURIs(contextValue)); + const duration = sw.elapsed(); + + type TelemetryData = { + duration: number; + contextKey: string; + }; + type TelemetryClassification = { + owner: 'jrieken'; + comment: 'Performance numbers of the setContext-API command'; + duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'The time it took to set the context key' }; + contextKey: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The context key that got set' }; + }; + telemetryService.publicLog2('command.setContext', { + contextKey: String(contextKey), + duration + }); } function stringifyURIs(contextValue: any): any { From 7278d50cc724dede555dbe1fd553da6d1e2500d3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2022 13:14:14 +0200 Subject: [PATCH 325/599] fix treeshaking failure (#162723) --- src/vs/platform/actions/browser/menuEntryActionViewItem.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 76c445d5603..41faa91d8d7 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -16,7 +16,7 @@ import { isLinux, isWindows, OS } from 'vs/base/common/platform'; import 'vs/css!./menuEntryActionViewItem'; import { localize } from 'vs/nls'; import { IMenu, IMenuActionOptions, IMenuService, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; -import { ICommandAction, Icon } from 'vs/platform/action/common/action'; +import { ICommandAction, isICommandActionToggleInfo } from 'vs/platform/action/common/action'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -240,7 +240,7 @@ export class MenuEntryActionViewItem extends ActionViewItem { return; } - const icon = this._commandAction.checked && (item.toggled as { icon?: Icon })?.icon ? (item.toggled as { icon: Icon }).icon : item.icon; + const icon = this._commandAction.checked && isICommandActionToggleInfo(item.toggled) && item.toggled.icon ? item.toggled.icon : item.icon; if (!icon) { return; From 625fec97f27126c4fcd04de37c7cc4d8251c9616 Mon Sep 17 00:00:00 2001 From: Michael Rienstra Date: Wed, 5 Oct 2022 05:22:33 -0700 Subject: [PATCH 326/599] Enforce yarn version (#162610) * Enforce yarn version Actually require >=1.10.1 and <2 * error when yarn >= 2 --- build/npm/preinstall.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js index a839653f75c..afefc404267 100644 --- a/build/npm/preinstall.js +++ b/build/npm/preinstall.js @@ -21,12 +21,19 @@ const path = require('path'); const fs = require('fs'); const cp = require('child_process'); const yarnVersion = cp.execSync('yarn -v', { encoding: 'utf8' }).trim(); -const parsedYarnVersion = /^(\d+)\.(\d+)\./.exec(yarnVersion); +const parsedYarnVersion = /^(\d+)\.(\d+)\.(\d+)/.exec(yarnVersion); const majorYarnVersion = parseInt(parsedYarnVersion[1]); const minorYarnVersion = parseInt(parsedYarnVersion[2]); +const patchYarnVersion = parseInt(parsedYarnVersion[3]); -if (majorYarnVersion < 1 || minorYarnVersion < 10) { - console.error('\033[1;31m*** Please use yarn >=1.10.1.\033[0;0m'); +if ( + majorYarnVersion < 1 || + majorYarnVersion === 1 && ( + minorYarnVersion < 10 || (minorYarnVersion === 10 && patchYarnVersion < 1) + ) || + majorYarnVersion >= 2 +) { + console.error('\033[1;31m*** Please use yarn >=1.10.1 and <2.\033[0;0m'); err = true; } From ef193f9813d375c6acd986b12dc45d0a4744a122 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2022 15:24:27 +0200 Subject: [PATCH 327/599] manually set editor focus after returning from snippet-picker (#162735) workaround and likely not fix for https://github.com/microsoft/vscode/issues/162729 --- .../workbench/contrib/snippets/browser/commands/insertSnippet.ts | 1 + .../contrib/snippets/browser/commands/surroundWithSnippet.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/snippets/browser/commands/insertSnippet.ts b/src/vs/workbench/contrib/snippets/browser/commands/insertSnippet.ts index 5b10727b169..d8b905d5f79 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/insertSnippet.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/insertSnippet.ts @@ -147,6 +147,7 @@ export class InsertSnippetAction extends SnippetEditorAction { if (snippet.needsClipboard) { clipboardText = await clipboardService.readText(); } + editor.focus(); SnippetController2.get(editor)?.insert(snippet.codeSnippet, { clipboardText }); snippetService.updateUsageTimestamp(snippet); } diff --git a/src/vs/workbench/contrib/snippets/browser/commands/surroundWithSnippet.ts b/src/vs/workbench/contrib/snippets/browser/commands/surroundWithSnippet.ts index bdd36872158..e42370ce4fa 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/surroundWithSnippet.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/surroundWithSnippet.ts @@ -72,6 +72,7 @@ export class SurroundWithSnippetEditorAction extends SnippetEditorAction { clipboardText = await clipboardService.readText(); } + editor.focus(); SnippetController2.get(editor)?.insert(snippet.codeSnippet, { clipboardText }); snippetsService.updateUsageTimestamp(snippet); } From 132b81c1970d264f466b17f44b4d6fe8ca67c9ef Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 5 Oct 2022 06:41:09 -0700 Subject: [PATCH 328/599] Move to registerWorkbenchAction usage in terminal Part of #162713 --- .../electron-sandbox/terminalRemote.ts | 87 +++++++++---------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts index e52260f1843..6d2c0b18700 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts @@ -3,59 +3,52 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { TERMINAL_ACTION_CATEGORY, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; -import { Action } from 'vs/base/common/actions'; -import { ITerminalGroupService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { localize } from 'vs/nls'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { URI } from 'vs/base/common/uri'; +import { ITerminalGroupService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { Schemas } from 'vs/base/common/network'; export function registerRemoteContributions() { - const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); - actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(CreateNewLocalTerminalAction), 'Terminal: Create New Integrated Terminal (Local)', TERMINAL_ACTION_CATEGORY); -} - -export class CreateNewLocalTerminalAction extends Action { - static readonly ID = TerminalCommandId.NewLocal; - static readonly LABEL = nls.localize('workbench.action.terminal.newLocal', "Create New Integrated Terminal (Local)"); - - constructor( - id: string, label: string, - @ITerminalService private readonly _terminalService: ITerminalService, - @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, - @INativeEnvironmentService private readonly _nativeEnvironmentService: INativeEnvironmentService, - @IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, - @IHistoryService private readonly _historyService: IHistoryService - ) { - super(id, label); - } - - override async run(): Promise { - let cwd: URI | undefined; - try { - const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.vscodeRemote); - if (activeWorkspaceRootUri) { - const canonicalUri = await this._remoteAuthorityResolverService.getCanonicalURI(activeWorkspaceRootUri); - if (canonicalUri.scheme === Schemas.file) { - cwd = canonicalUri; + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.NewLocal, + title: { value: localize('workbench.action.terminal.newLocal', "Create New Integrated Terminal (Local)"), original: 'Create New Integrated Terminal (Local)' }, + f1: true + }); + } + async run(accessor: ServicesAccessor) { + const historyService = accessor.get(IHistoryService); + const remoteAuthorityResolverService = accessor.get(IRemoteAuthorityResolverService); + const nativeEnvironmentService = accessor.get(INativeEnvironmentService); + const terminalService = accessor.get(ITerminalService); + const terminalGroupService = accessor.get(ITerminalGroupService); + let cwd: URI | undefined; + try { + const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.vscodeRemote); + if (activeWorkspaceRootUri) { + const canonicalUri = await remoteAuthorityResolverService.getCanonicalURI(activeWorkspaceRootUri); + if (canonicalUri.scheme === Schemas.file) { + cwd = canonicalUri; + } } + } catch { } + if (!cwd) { + cwd = nativeEnvironmentService.userHome; + } + const instance = await terminalService.createTerminal({ cwd }); + if (!instance) { + return Promise.resolve(undefined); } - } catch { } - if (!cwd) { - cwd = this._nativeEnvironmentService.userHome; - } - const instance = await this._terminalService.createTerminal({ cwd }); - if (!instance) { - return Promise.resolve(undefined); - } - this._terminalService.setActiveInstance(instance); - return this._terminalGroupService.showPanel(true); - } + terminalService.setActiveInstance(instance); + return terminalGroupService.showPanel(true); + } + }); } From f8feede2aeb45096d9e7ade97a138327cbb40372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 5 Oct 2022 06:48:49 -0700 Subject: [PATCH 329/599] remove usage of `registerWorkbenchAction` in update world (#162740) Related-to: #162713 --- .../update/browser/releaseNotesEditor.ts | 6 +- .../update/browser/update.contribution.ts | 56 +++++++++------ .../contrib/update/browser/update.ts | 68 ++++++++++--------- .../workbench/contrib/update/common/update.ts | 1 - 4 files changed, 71 insertions(+), 60 deletions(-) diff --git a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index 9517be6e2e0..8b83776c6b7 100644 --- a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -17,7 +17,6 @@ import { generateTokensCSSForColorMap } from 'vs/editor/common/languages/support import { ILanguageService } from 'vs/editor/common/languages/language'; import * as nls from 'vs/nls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -63,10 +62,7 @@ export class ReleaseNotesManager { }); } - public async show( - accessor: ServicesAccessor, - version: string - ): Promise { + public async show(version: string): Promise { const releaseNoteText = await this.loadReleaseNotes(version); this._lastText = releaseNoteText; const html = await this.renderBody(releaseNoteText); diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index cbf2d71d4ab..dfc159cd59d 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -7,10 +7,9 @@ import 'vs/platform/update/common/update.config.contribution'; import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { SyncActionDescriptor, MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CheckForVSCodeUpdateAction, CONTEXT_UPDATE_STATE, SwitchProductQualityContribution } from 'vs/workbench/contrib/update/browser/update'; +import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; +import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CONTEXT_UPDATE_STATE, SwitchProductQualityContribution, RELEASE_NOTES_URL } from 'vs/workbench/contrib/update/browser/update'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import product from 'vs/platform/product/common/product'; import { IUpdateService, StateType } from 'vs/platform/update/common/update'; @@ -18,6 +17,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { isWindows } from 'vs/base/common/platform'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; const workbench = Registry.as(WorkbenchExtensions.Workbench); @@ -25,14 +25,39 @@ workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Rest workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); workbench.registerWorkbenchContribution(SwitchProductQualityContribution, LifecyclePhase.Restored); -const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); +// Release notes -// Editor -actionRegistry - .registerWorkbenchAction(SyncActionDescriptor.from(ShowCurrentReleaseNotesAction), `${product.nameShort}: Show Release Notes`, product.nameShort); +registerAction2(ShowCurrentReleaseNotesAction); -actionRegistry - .registerWorkbenchAction(SyncActionDescriptor.from(CheckForVSCodeUpdateAction), `${product.nameShort}: Check for Update`, product.nameShort, CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle)); +MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '1_welcome', + command: { + id: ShowCurrentReleaseNotesActionId, + title: localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes") + }, + when: RELEASE_NOTES_URL, + order: 5 +}); + +// Update + +export class CheckForUpdateAction extends Action2 { + + constructor() { + super({ + id: 'update.checkForUpdate', + title: { value: localize('checkForUpdates', "Check for Updates..."), original: 'Check for Updates...' }, + category: { value: product.nameShort, original: product.nameShort }, + f1: true, + precondition: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle), + }); + } + + async run(accessor: ServicesAccessor): Promise { + const updateService = accessor.get(IUpdateService); + return updateService.checkForUpdates(true); + } +} class DownloadUpdateAction extends Action2 { constructor() { @@ -82,22 +107,11 @@ class RestartToUpdateAction extends Action2 { } } +registerAction2(CheckForUpdateAction); registerAction2(DownloadUpdateAction); registerAction2(InstallUpdateAction); registerAction2(RestartToUpdateAction); -// Menu -if (ShowCurrentReleaseNotesAction.AVAILABE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: ShowCurrentReleaseNotesAction.ID, - title: localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes") - }, - order: 5 - }); -} - if (isWindows) { class DeveloperApplyUpdateAction extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 1ff40d85b54..4b4db5cfb3f 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'vs/workbench/contrib/update/common/update'; +import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; @@ -33,7 +33,8 @@ import { Promises } from 'vs/base/common/async'; import { IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { Event } from 'vs/base/common/event'; -export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Idle); +export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); +export const RELEASE_NOTES_URL = new RawContextKey('releaseNotesUrl', ''); let releaseNotesManager: ReleaseNotesManager | undefined = undefined; @@ -42,7 +43,7 @@ function showReleaseNotes(instantiationService: IInstantiationService, version: releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager); } - return instantiationService.invokeFunction(accessor => releaseNotesManager!.show(accessor, version)); + return releaseNotesManager.show(version); } export class OpenLatestReleaseNotesInBrowserAction extends Action { @@ -104,19 +105,32 @@ export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { } } -export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesAction { +export class ShowCurrentReleaseNotesAction extends Action2 { - static readonly ID = ShowCurrentReleaseNotesActionId; - static readonly LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); - static readonly AVAILABE = !!product.releaseNotesUrl; + constructor() { + super({ + id: ShowCurrentReleaseNotesActionId, + title: { value: nls.localize('showReleaseNotes', "Show Release Notes"), original: 'Show Release Notes' }, + category: { value: product.nameShort, original: product.nameShort }, + f1: true, + precondition: RELEASE_NOTES_URL, + }); + } - constructor( - id = ShowCurrentReleaseNotesAction.ID, - label = ShowCurrentReleaseNotesAction.LABEL, - @IInstantiationService instantiationService: IInstantiationService, - @IProductService productService: IProductService - ) { - super(id, label, productService.version, instantiationService); + async run(accessor: ServicesAccessor): Promise { + const instantiationService = accessor.get(IInstantiationService); + const productService = accessor.get(IProductService); + + try { + await showReleaseNotes(instantiationService, productService.version); + } catch (err) { + const action = instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); + try { + await action.run(); + } catch (err2) { + throw new Error(`${err.message} and ${err2.message}`); + } + } } } @@ -156,8 +170,14 @@ export class ProductContribution implements IWorkbenchContribution { @IOpenerService openerService: IOpenerService, @IConfigurationService configurationService: IConfigurationService, @IHostService hostService: IHostService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IContextKeyService contextKeyService: IContextKeyService, ) { + if (productService.releaseNotesUrl) { + const releaseNotesUrlKey = RELEASE_NOTES_URL.bindTo(contextKeyService); + releaseNotesUrlKey.set(productService.releaseNotesUrl); + } + hostService.hadLastFocus().then(async hadLastFocus => { if (!hadLastFocus) { return; @@ -604,21 +624,3 @@ export class SwitchProductQualityContribution extends Disposable implements IWor } } } - -export class CheckForVSCodeUpdateAction extends Action { - - static readonly ID = CheckForVSCodeUpdateActionId; - static LABEL = nls.localize('checkForUpdates', "Check for Updates..."); - - constructor( - id: string, - label: string, - @IUpdateService private readonly updateService: IUpdateService, - ) { - super(id, label, undefined, true); - } - - override run(): Promise { - return this.updateService.checkForUpdates(true); - } -} diff --git a/src/vs/workbench/contrib/update/common/update.ts b/src/vs/workbench/contrib/update/common/update.ts index 5b9303f6eac..c224d76703a 100644 --- a/src/vs/workbench/contrib/update/common/update.ts +++ b/src/vs/workbench/contrib/update/common/update.ts @@ -4,4 +4,3 @@ *--------------------------------------------------------------------------------------------*/ export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes'; -export const CheckForVSCodeUpdateActionId = 'update.checkForVSCodeUpdate'; \ No newline at end of file From 5850fedb5e17fc47c4c8085a1fbc16bf04ec7a49 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 16:38:42 +0200 Subject: [PATCH 330/599] fix tests --- .../platform/contextkey/test/browser/contextkey.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/contextkey/test/browser/contextkey.test.ts b/src/vs/platform/contextkey/test/browser/contextkey.test.ts index 50309c6fe6b..8cbecda9b4b 100644 --- a/src/vs/platform/contextkey/test/browser/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/browser/contextkey.test.ts @@ -6,12 +6,14 @@ import * as assert from 'assert'; import { DeferredPromise } from 'vs/base/common/async'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { mock } from 'vs/base/test/common/mock'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ContextKeyService, setContext } from 'vs/platform/contextkey/browser/contextKeyService'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; suite('ContextKeyService', () => { test('updateParent', () => { @@ -64,7 +66,12 @@ suite('ContextKeyService', () => { const contextKeyService: IContextKeyService = disposables.add(new ContextKeyService(configurationService)); const instantiationService = new TestInstantiationService(new ServiceCollection( [IConfigurationService, configurationService], - [IContextKeyService, contextKeyService] + [IContextKeyService, contextKeyService], + [ITelemetryService, new class extends mock() { + override async publicLog2() { + // + } + }] )); const uri = URI.parse('test://abc'); From f8aa3a7c04f02edabc806e4a4feac1c86b295c13 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 5 Oct 2022 08:52:39 -0700 Subject: [PATCH 331/599] improve search smoke test (#161652) * improve search smoke test * prevent text to show when clearing results --- .../contrib/search/browser/searchView.ts | 6 +++--- .../contrib/search/common/searchModel.ts | 7 ++++--- .../search/test/common/searchResult.test.ts | 2 +- test/smoke/src/areas/search/search.test.ts | 16 +++++++++------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 9d98dbbadf4..08ce9025877 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -527,7 +527,7 @@ export class SearchView extends ViewPane { private refreshAndUpdateCount(event?: IChangeEvent): void { this.searchWidget.setReplaceAllActionState(!this.viewModel.searchResult.isEmpty()); - this.updateSearchResultCount(this.viewModel.searchResult.query!.userDisabledExcludesAndIgnoreFiles, this.viewModel.searchResult.query?.onlyOpenEditors); + this.updateSearchResultCount(this.viewModel.searchResult.query!.userDisabledExcludesAndIgnoreFiles, this.viewModel.searchResult.query?.onlyOpenEditors, event?.clearingAll); return this.refreshTree(event); } @@ -1646,14 +1646,14 @@ export class SearchView extends ViewPane { this.inputPatternIncludes.setOnlySearchInOpenEditors(false); } - private updateSearchResultCount(disregardExcludesAndIgnores?: boolean, onlyOpenEditors?: boolean): void { + private updateSearchResultCount(disregardExcludesAndIgnores?: boolean, onlyOpenEditors?: boolean, clear: boolean = false): void { const fileCount = this.viewModel.searchResult.fileCount(); this.hasSearchResultsKey.set(fileCount > 0); const msgWasHidden = this.messagesElement.style.display === 'none'; const messageEl = this.clearMessage(); - const resultMsg = this.buildResultCountMessage(this.viewModel.searchResult.count(), fileCount); + const resultMsg = clear ? '' : this.buildResultCountMessage(this.viewModel.searchResult.count(), fileCount); this.tree.ariaLabel = resultMsg + nls.localize('forTerm', " - Search: {0}", this.searchResult.query?.contentPattern.pattern ?? ''); dom.append(messageEl, resultMsg); diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 4b7a435742c..045bf940b95 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -476,6 +476,7 @@ export interface IChangeEvent { elements: FileMatch[]; added?: boolean; removed?: boolean; + clearingAll?: boolean; } export class FolderMatch extends Disposable { @@ -578,10 +579,10 @@ export class FolderMatch extends Disposable { folderMatch.onDispose(() => disposable.dispose()); } - clear(): void { + clear(clearingAll = false): void { const changed: FileMatch[] = this.downstreamFileMatches(); this.disposeMatches(); - this._onChange.fire({ elements: changed, removed: true, added: false }); + this._onChange.fire({ elements: changed, removed: true, added: false, clearingAll }); } remove(matches: FileMatch | FolderMatchWithResource | (FileMatch | FolderMatchWithResource)[]): void { @@ -1191,7 +1192,7 @@ export class SearchResult extends Disposable { } clear(): void { - this.folderMatches().forEach((folderMatch) => folderMatch.clear()); + this.folderMatches().forEach((folderMatch) => folderMatch.clear(true)); this.disposeMatches(); this._folderMatches = []; this._otherFilesMatch = null; diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index fcbce0a9f36..19a836683ee 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -449,7 +449,7 @@ suite('SearchResult', () => { testObject.onChange(target); testObject.remove(folderMatch); assert.ok(target.calledOnce); - assert.deepStrictEqual([{ elements: expectedArrayResult, removed: true, added: false }], target.args[0]); + assert.deepStrictEqual([{ elements: expectedArrayResult, removed: true, added: false, clearingAll: false }], target.args[0]); }); test('Replacing an intermediate folder should remove all downstream folders and file matches', async function () { diff --git a/test/smoke/src/areas/search/search.test.ts b/test/smoke/src/areas/search/search.test.ts index 28796e9b0d7..92c75f14404 100644 --- a/test/smoke/src/areas/search/search.test.ts +++ b/test/smoke/src/areas/search/search.test.ts @@ -29,14 +29,16 @@ export function setup(logger: Logger) { it('searches only for *.js files & checks for correct result number', async function () { const app = this.app as Application; - await app.workbench.search.searchFor('body'); - await app.workbench.search.showQueryDetails(); - await app.workbench.search.setFilesToIncludeText('*.js'); - await app.workbench.search.submitSearch(); + try { + await app.workbench.search.setFilesToIncludeText('*.js'); + await app.workbench.search.searchFor('body'); + await app.workbench.search.showQueryDetails(); - await app.workbench.search.waitForResultText('4 results in 1 file'); - await app.workbench.search.setFilesToIncludeText(''); - await app.workbench.search.hideQueryDetails(); + await app.workbench.search.waitForResultText('4 results in 1 file'); + } finally { + await app.workbench.search.setFilesToIncludeText(''); + await app.workbench.search.hideQueryDetails(); + } }); it('dismisses result & checks for correct result number', async function () { From 52d266e62863dee3dde32ba4a8ffe44f891bf425 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 5 Oct 2022 18:38:47 +0200 Subject: [PATCH 332/599] fix leak and missing ctx-update after model change --- .../contrib/outline/browser/outlinePane.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index aa168798533..f9f9bb3d4c2 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -85,9 +85,6 @@ export class OutlinePane extends ViewPane { private _ctxFilterOnType!: IContextKey; private _ctxSortMode!: IContextKey; private _ctxAllCollapsed!: IContextKey; - private _updateAllCollapsedContext(): void { - this._ctxAllCollapsed.set(this._tree?.getNode(null).children.every(node => !node.collapsible || node.collapsed) || false); - } constructor( options: IViewletViewOptions, @@ -123,8 +120,6 @@ export class OutlinePane extends ViewPane { }; updateContext(); this._disposables.add(this._outlineViewState.onDidChange(updateContext)); - - this._updateAllCollapsedContext(); } override dispose(): void { @@ -371,6 +366,14 @@ export class OutlinePane extends ViewPane { } })); + // feature: update all-collapsed context key + const updateAllCollapsedCtx = () => { + this._ctxAllCollapsed.set(tree.getNode(null).children.every(node => !node.collapsible || node.collapsed)); + }; + this._editorControlDisposables.add(tree.onDidChangeCollapseState(updateAllCollapsedCtx)); + this._editorControlDisposables.add(tree.onDidChangeModel(updateAllCollapsedCtx)); + updateAllCollapsedCtx(); + // last: set tree property and wire it up to one of our context keys tree.layout(this._treeDimensions?.height, this._treeDimensions?.width); this._tree = tree; @@ -378,7 +381,6 @@ export class OutlinePane extends ViewPane { tree.dispose(); this._tree = undefined; })); - this._disposables.add(this._tree.onDidChangeCollapseState(() => this._updateAllCollapsedContext())); } } From 9a493002a27999a52def5d0b7a2fc8b65ca8bfed Mon Sep 17 00:00:00 2001 From: aamunger Date: Wed, 5 Oct 2022 08:53:20 -0700 Subject: [PATCH 333/599] localize category string --- .../browser/interactive.contribution.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 89839abf905..4c686a06160 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -64,7 +64,7 @@ import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/s import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; - +const interactiveWindowCategory = localize('interactiveWindow', 'Interactive Window'); Registry.as(EditorExtensions.EditorPane).registerEditorPane( EditorPaneDescriptor.create( @@ -325,7 +325,7 @@ registerAction2(class extends Action2 { id: '_interactive.open', title: { value: localize('interactive.open', "Open Interactive Window"), original: 'Open Interactive Window' }, f1: false, - category: 'Interactive Window', + category: interactiveWindowCategory, description: { description: localize('interactive.open', "Open Interactive Window"), args: [ @@ -441,7 +441,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.execute', title: { value: localize('interactive.execute', "Execute Code"), original: 'Execute Code' }, - category: 'Interactive Window', + category: interactiveWindowCategory, keybinding: { // when: NOTEBOOK_CELL_LIST_FOCUSED, when: ContextKeyExpr.equals('resourceScheme', Schemas.vscodeInteractive), @@ -557,7 +557,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.input.clear', title: { value: localize('interactive.input.clear', "Clear the interactive window input editor contents"), original: 'Clear the interactive window input editor contents' }, - category: 'Interactive Window', + category: interactiveWindowCategory, f1: false }); } @@ -583,7 +583,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.previous', title: { value: localize('interactive.history.previous', "Previous value in history"), original: 'Previous value in history' }, - category: 'Interactive Window', + category: interactiveWindowCategory, f1: false, keybinding: { when: ContextKeyExpr.and( @@ -622,7 +622,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.next', title: { value: localize('interactive.history.next', "Next value in history"), original: 'Next value in history' }, - category: 'Interactive Window', + category: interactiveWindowCategory, f1: false, keybinding: { when: ContextKeyExpr.and( @@ -668,7 +668,7 @@ registerAction2(class extends Action2 { mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }, weight: KeybindingWeight.WorkbenchContrib }, - category: 'Interactive Window', + category: interactiveWindowCategory, }); } @@ -697,7 +697,7 @@ registerAction2(class extends Action2 { mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, weight: KeybindingWeight.WorkbenchContrib }, - category: 'Interactive Window', + category: interactiveWindowCategory, }); } @@ -721,7 +721,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.input.focus', title: { value: localize('interactive.input.focus', "Focus input editor in the interactive window"), original: 'Focus input editor in the interactive window' }, - category: 'Interactive Window', + category: interactiveWindowCategory, f1: true }); } @@ -756,7 +756,7 @@ registerAction2(class extends Action2 { super({ id: 'interactive.history.focus', title: { value: localize('interactive.history.focus', "Focus history in the interactive window"), original: 'Focus input editor in the interactive window' }, - category: 'Interactive Window', + category: interactiveWindowCategory, f1: true, precondition: ContextKeyExpr.equals('resourceScheme', Schemas.vscodeInteractive), }); From c466c6974a67245effc5559ba2d5d5cbb33f1812 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 5 Oct 2022 19:31:54 +0200 Subject: [PATCH 334/599] Comment button blinks while typing sometimes (#162755) * WIP fix for #156104 * Comment button blinks while typing sometimes Fixes #162580 --- src/vs/platform/tunnel/common/tunnel.ts | 12 ++++++++++++ .../comments/browser/commentsEditorContribution.ts | 8 ++++---- .../services/remote/common/remoteExplorerService.ts | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/tunnel/common/tunnel.ts b/src/vs/platform/tunnel/common/tunnel.ts index 1c0d70f63ff..9fd03586d78 100644 --- a/src/vs/platform/tunnel/common/tunnel.ts +++ b/src/vs/platform/tunnel/common/tunnel.ts @@ -126,6 +126,7 @@ export interface ITunnelService { canTunnel(uri: URI): boolean; openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise | undefined; + setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void; closeTunnel(remoteHost: string, remotePort: number): Promise; setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable; setTunnelFeatures(features: TunnelProviderFeatures): void; @@ -270,6 +271,17 @@ export abstract class AbstractTunnelService implements ITunnelService { this._tunnels.clear(); } + setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void { + this.addTunnelToMap(remoteHost, remotePort, Promise.resolve({ + tunnelRemoteHost: remoteHost, + tunnelRemotePort: remotePort, + localAddress, + privacy, + protocol, + dispose: () => Promise.resolve() + })); + } + openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise | undefined { this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`); if (!addressProvider) { diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 81de2638436..af59bb1d79c 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -50,7 +50,7 @@ import { CommentThreadRangeDecorator } from 'vs/workbench/contrib/comments/brows import { commentThreadRangeActiveBackground, commentThreadRangeActiveBorder, commentThreadRangeBackground, commentThreadRangeBorder } from 'vs/workbench/contrib/comments/browser/commentColors'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/cursorEvents'; import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsView'; -import { withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; export const ID = 'editor.contrib.review'; @@ -180,11 +180,11 @@ class CommentingRangeDecorator { } } - public update(editor: ICodeEditor | undefined, commentInfos: ICommentInfo[]) { + public update(editor: ICodeEditor | undefined, commentInfos: ICommentInfo[], cursorLine?: number, range?: Range) { if (editor) { this._editor = editor; this._infos = commentInfos; - this._doUpdate(editor, commentInfos); + this._doUpdate(editor, commentInfos, cursorLine, range); } } @@ -493,7 +493,7 @@ export class CommentController implements IEditorContribution { }).then(commentInfos => { if (this.commentService.isCommentingEnabled) { const meaningfulCommentInfos = coalesce(commentInfos); - this._commentingRangeDecorator.update(this.editor, meaningfulCommentInfos); + this._commentingRangeDecorator.update(this.editor, meaningfulCommentInfos, this.editor?.getPosition()?.lineNumber, withNullAsUndefined(this.editor?.getSelection())); } }, (err) => { onUnexpectedError(err); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index cbc2eef9ea9..234f9eb50c0 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -705,6 +705,7 @@ export class TunnelModel extends Disposable { description: nls.localize('tunnel.staticallyForwarded', "Statically Forwarded") } }); + this.tunnelService.setEnvironmentTunnel(tunnel.remoteAddress.host, tunnel.remoteAddress.port, localAddress, TunnelPrivacyId.ConstantPrivate, TunnelProtocol.Http); } } this._environmentTunnelsSet = true; From 8f5ef37cd7277941806c0b5df9f7fc00c298d44c Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:08:40 -0700 Subject: [PATCH 335/599] search performance improvements (#162405) * search performance improvements * remove null type from index --- .../contrib/search/browser/searchView.ts | 32 +++++++++++-------- .../contrib/search/common/searchModel.ts | 28 ++++++++-------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 08ce9025877..9dbb88f8ed4 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -153,6 +153,9 @@ export class SearchView extends ViewPane { private treeViewKey: IContextKey; + private _uiRefreshHandle: any; + private _visibleMatches: number = 0; + constructor( options: IViewPaneOptions, @IFileService private readonly fileService: IFileService, @@ -1588,22 +1591,25 @@ export class SearchView extends ViewPane { } }; - let visibleMatches = 0; + this._visibleMatches = 0; // Handle UI updates in an interval to show frequent progress and results - const uiRefreshHandle: any = setInterval(() => { - if (this.state === SearchUIState.Idle) { - window.clearInterval(uiRefreshHandle); - return; - } + if (!this._uiRefreshHandle) { + this._uiRefreshHandle = setInterval(() => { + if (this.state === SearchUIState.Idle) { + window.clearInterval(this._uiRefreshHandle); + this._uiRefreshHandle = undefined; + return; + } - // Search result tree update - const fileCount = this.viewModel.searchResult.fileCount(); - if (visibleMatches !== fileCount) { - visibleMatches = fileCount; - this.refreshAndUpdateCount(); - } - }, 100); + // Search result tree update + const fileCount = this.viewModel.searchResult.fileCount(); + if (this._visibleMatches !== fileCount) { + this._visibleMatches = fileCount; + this.refreshAndUpdateCount(); + } + }, 100); + } this.searchWidget.setReplaceAllActionState(false); diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 045bf940b95..858e3294543 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -500,7 +500,7 @@ export class FolderMatch extends Disposable { constructor( protected _resource: URI | null, private _id: string, - protected _index: number | null, + protected _index: number, protected _query: ITextQuery, private _parent: SearchResult | FolderMatch, private _searchModel: SearchModel, @@ -542,7 +542,7 @@ export class FolderMatch extends Disposable { return this._resource; } - index(): number | null { + index(): number { return this._index; } @@ -567,7 +567,7 @@ export class FolderMatch extends Disposable { } } - public createIntermediateFolderMatch(resource: URI, id: string, index: number | null, query: ITextQuery, baseWorkspaceFolder: FolderMatchWorkspaceRoot): FolderMatchWithResource { + public createIntermediateFolderMatch(resource: URI, id: string, index: number, query: ITextQuery, baseWorkspaceFolder: FolderMatchWorkspaceRoot): FolderMatchWithResource { const folderMatch = this.instantiationService.createInstance(FolderMatchWithResource, resource, id, index, query, this, this._searchModel, baseWorkspaceFolder); this.configureIntermediateMatch(folderMatch); this.doAddFolder(folderMatch); @@ -822,7 +822,7 @@ export class FolderMatch extends Disposable { export class FolderMatchWithResource extends FolderMatch { - constructor(_resource: URI, _id: string, _index: number | null, _query: ITextQuery, _parent: SearchResult | FolderMatch, _searchModel: SearchModel, _closestRoot: FolderMatchWorkspaceRoot | null, + constructor(_resource: URI, _id: string, _index: number, _query: ITextQuery, _parent: SearchResult | FolderMatch, _searchModel: SearchModel, _closestRoot: FolderMatchWorkspaceRoot | null, @IReplaceService replaceService: IReplaceService, @IInstantiationService instantiationService: IInstantiationService, @ILabelService labelService: ILabelService, @@ -888,17 +888,13 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource { for (let i = 0; i < fileMatchParentParts.length; i++) { let folderMatch: FolderMatchWithResource | undefined = parent.getFolderMatch(fileMatchParentParts[i]); if (!folderMatch) { - folderMatch = parent.createIntermediateFolderMatch(fileMatchParentParts[i], fileMatchParentParts[i].toString(), null, this._query, root); + folderMatch = parent.createIntermediateFolderMatch(fileMatchParentParts[i], fileMatchParentParts[i].toString(), -1, this._query, root); } parent = folderMatch; } return this.createFileMatch(this._query.contentPattern, this._query.previewOptions, this._query.maxResults, parent, rawFileMatch, root); } - - override index(): number { - return this._index!; - } } /** @@ -924,6 +920,8 @@ export class FolderMatchNoRoot extends FolderMatch { } } +let elemAIndex: number = -1; +let elemBIndex: number = -1; /** * Compares instances of the same match type. Different match types should not be siblings * and their sort order is undefined. @@ -939,9 +937,9 @@ export function searchMatchComparer(elementA: RenderableMatch, elementB: Rendera } if (elementA instanceof FolderMatch && elementB instanceof FolderMatch) { - const elemAIndex = elementA.index(); - const elemBIndex = elementB.index(); - if (elemAIndex !== null && elemBIndex !== null) { + elemAIndex = elementA.index(); + elemBIndex = elementB.index(); + if (elemAIndex !== -1 && elemBIndex !== -1) { return elemAIndex - elemBIndex; } @@ -1366,7 +1364,7 @@ export class SearchModel extends Disposable { private _replacePattern: ReplacePattern | null = null; private _preserveCase: boolean = false; private _startStreamDelay: Promise = Promise.resolve(); - private _resultQueue: IFileMatch[] = []; + private readonly _resultQueue: IFileMatch[] = []; private readonly _onReplaceTermChanged: Emitter = this._register(new Emitter()); readonly onReplaceTermChanged: Event = this._onReplaceTermChanged.event; @@ -1482,7 +1480,7 @@ export class SearchModel extends Disposable { } this._searchResult.add(this._resultQueue); - this._resultQueue = []; + this._resultQueue.length = 0; const options: IPatternInfo = Object.assign({}, this._searchQuery.contentPattern); delete (options as any).pattern; @@ -1536,7 +1534,7 @@ export class SearchModel extends Disposable { await this._startStreamDelay; if (this._resultQueue.length) { this._searchResult.add(this._resultQueue, true); - this._resultQueue = []; + this._resultQueue.length = 0; } } } From 424f38d15672bfcf825215b51ed6a49b6417951c Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:46:23 -0700 Subject: [PATCH 336/599] debt: remove usages of registerWorkbenchAction (#162762) refs: #162713 --- .../parts/auxiliarybar/auxiliaryBarActions.ts | 61 ++++---- .../parts/auxiliarybar/auxiliaryBarPart.ts | 6 +- .../browser/parts/panel/panelActions.ts | 132 ++++++++---------- .../browser/parts/panel/panelPart.ts | 4 +- 4 files changed, 98 insertions(+), 105 deletions(-) diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts index 0a8890728c3..f53afec57bc 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts @@ -3,19 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Action } from 'vs/base/common/actions'; import { Codicon } from 'vs/base/common/codicons'; import { localize } from 'vs/nls'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { Extensions as WorkbenchExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { AuxiliaryBarVisibleContext } from 'vs/workbench/common/contextkeys'; import { ViewContainerLocation, ViewContainerLocationToString } from 'vs/workbench/common/views'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; const auxiliaryBarRightIcon = registerIcon('auxiliarybar-right-layout-icon', Codicon.layoutSidebarRight, localize('toggleAuxiliaryIconRight', 'Icon to toggle the auxiliary bar off in its right position.')); @@ -23,50 +21,57 @@ const auxiliaryBarRightOffIcon = registerIcon('auxiliarybar-right-off-layout-ico const auxiliaryBarLeftIcon = registerIcon('auxiliarybar-left-layout-icon', Codicon.layoutSidebarLeft, localize('toggleAuxiliaryIconLeft', 'Icon to toggle the auxiliary bar in its left position.')); const auxiliaryBarLeftOffIcon = registerIcon('auxiliarybar-left-off-layout-icon', Codicon.layoutSidebarLeftOff, localize('toggleAuxiliaryIconLeftOn', 'Icon to toggle the auxiliary bar on in its left position.')); -export class ToggleAuxiliaryBarAction extends Action { +export class ToggleAuxiliaryBarAction extends Action2 { static readonly ID = 'workbench.action.toggleAuxiliaryBar'; static readonly LABEL = localize('toggleAuxiliaryBar', "Toggle Secondary Side Bar Visibility"); - constructor( - id: string, - name: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, name, layoutService.isVisible(Parts.AUXILIARYBAR_PART) ? 'auxiliaryBar expanded' : 'auxiliaryBar'); + constructor() { + super({ + id: ToggleAuxiliaryBarAction.ID, + title: { value: ToggleAuxiliaryBarAction.LABEL, original: 'Toggle Secondary Side Bar Visibility' }, + category: Categories.View, + f1: true, + }); } - override async run(): Promise { - this.layoutService.setPartHidden(this.layoutService.isVisible(Parts.AUXILIARYBAR_PART), Parts.AUXILIARYBAR_PART); + override async run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + layoutService.setPartHidden(layoutService.isVisible(Parts.AUXILIARYBAR_PART), Parts.AUXILIARYBAR_PART); } } -class FocusAuxiliaryBarAction extends Action { +registerAction2(ToggleAuxiliaryBarAction); + +registerAction2(class FocusAuxiliaryBarAction extends Action2 { static readonly ID = 'workbench.action.focusAuxiliaryBar'; static readonly LABEL = localize('focusAuxiliaryBar', "Focus into Secondary Side Bar"); - constructor( - id: string, - label: string, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); + + constructor() { + super({ + id: FocusAuxiliaryBarAction.ID, + title: { value: FocusAuxiliaryBarAction.LABEL, original: 'Focus into Secondary Side Bar' }, + category: Categories.View, + f1: true, + }); } - override async run(): Promise { + override async run(accessor: ServicesAccessor): Promise { + const paneCompositeService = accessor.get(IPaneCompositePartService); + const layoutService = accessor.get(IWorkbenchLayoutService); // Show auxiliary bar - if (!this.layoutService.isVisible(Parts.AUXILIARYBAR_PART)) { - this.layoutService.setPartHidden(false, Parts.AUXILIARYBAR_PART); + if (!layoutService.isVisible(Parts.AUXILIARYBAR_PART)) { + layoutService.setPartHidden(false, Parts.AUXILIARYBAR_PART); } // Focus into active composite - const composite = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.AuxiliaryBar); + const composite = paneCompositeService.getActivePaneComposite(ViewContainerLocation.AuxiliaryBar); composite?.focus(); } -} +}); MenuRegistry.appendMenuItems([ { @@ -133,7 +138,3 @@ MenuRegistry.appendMenuItems([ } } ]); - -const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleAuxiliaryBarAction), 'View: Toggle Secondary Side Bar Visibility', Categories.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusAuxiliaryBarAction), 'View: Focus into Secondary Side Bar', Categories.View.value); diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts index e0303f27bb6..404ea6236bf 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarPart.ts @@ -113,10 +113,8 @@ export class AuxiliaryBarPart extends BasePanelPart { const currentPositionRight = this.layoutService.getSideBarPosition() === Position.LEFT; actions.push(...[ new Separator(), - toAction({ - id: ToggleSidebarPositionAction.ID, label: currentPositionRight ? localize('move second side bar left', "Move Secondary Side Bar Left") : localize('move second side bar right', "Move Secondary Side Bar Right"), run: () => this.commandService.executeCommand(ToggleSidebarPositionAction.ID) - }), - this.instantiationService.createInstance(ToggleAuxiliaryBarAction, ToggleAuxiliaryBarAction.ID, localize('hideAuxiliaryBar', "Hide Secondary Side Bar")) + toAction({ id: ToggleSidebarPositionAction.ID, label: currentPositionRight ? localize('move second side bar left', "Move Secondary Side Bar Left") : localize('move second side bar right', "Move Secondary Side Bar Right"), run: () => this.commandService.executeCommand(ToggleSidebarPositionAction.ID) }), + toAction({ id: ToggleAuxiliaryBarAction.ID, label: localize('hide second side bar', "Hide Secondary Side Bar"), run: () => this.commandService.executeCommand(ToggleAuxiliaryBarAction.ID) }) ]); } diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index f68ea5c90e3..0b629fa63ba 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -7,9 +7,7 @@ import 'vs/css!./media/panelpart'; import { localize } from 'vs/nls'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Action } from 'vs/base/common/actions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions'; +import { MenuId, MenuRegistry, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IWorkbenchLayoutService, PanelAlignment, Parts, Position, positionToString } from 'vs/workbench/services/layout/browser/layoutService'; import { ActivityAction, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions'; @@ -23,6 +21,7 @@ import { ViewContainerLocationToString, ViewContainerLocation, IViewDescriptorSe import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICommandActionTitle } from 'vs/platform/action/common/action'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, localize('maximizeIcon', 'Icon to maximize a panel.')); const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown, localize('restoreIcon', 'Icon to restore a panel.')); @@ -30,50 +29,57 @@ const closeIcon = registerIcon('panel-close', Codicon.close, localize('closeIcon const panelIcon = registerIcon('panel-layout-icon', Codicon.layoutPanel, localize('togglePanelOffIcon', 'Icon to toggle the panel off when it is on.')); const panelOffIcon = registerIcon('panel-layout-icon-off', Codicon.layoutPanelOff, localize('togglePanelOnIcon', 'Icon to toggle the panel on when it is off.')); -export class TogglePanelAction extends Action { +export class TogglePanelAction extends Action2 { static readonly ID = 'workbench.action.togglePanel'; static readonly LABEL = localize('togglePanelVisibility', "Toggle Panel Visibility"); - constructor( - id: string, - name: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, name, layoutService.isVisible(Parts.PANEL_PART) ? 'panel expanded' : 'panel'); + constructor() { + super({ + id: TogglePanelAction.ID, + title: { value: TogglePanelAction.LABEL, original: 'Toggle Panel Visibility' }, + f1: true, + category: Categories.View, + keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyJ, weight: KeybindingWeight.WorkbenchContrib }, + }); } - override async run(): Promise { - this.layoutService.setPartHidden(this.layoutService.isVisible(Parts.PANEL_PART), Parts.PANEL_PART); + override async run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + layoutService.setPartHidden(layoutService.isVisible(Parts.PANEL_PART), Parts.PANEL_PART); } } -class FocusPanelAction extends Action { +registerAction2(TogglePanelAction); + +registerAction2(class extends Action2 { static readonly ID = 'workbench.action.focusPanel'; static readonly LABEL = localize('focusPanel', "Focus into Panel"); - constructor( - id: string, - label: string, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.focusPanel', + title: { value: localize('focusPanel', "Focus into Panel"), original: 'Focus into Panel' }, + category: Categories.View, + f1: true, + }); } - override async run(): Promise { + override async run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + const paneCompositeService = accessor.get(IPaneCompositePartService); // Show panel - if (!this.layoutService.isVisible(Parts.PANEL_PART)) { - this.layoutService.setPartHidden(false, Parts.PANEL_PART); + if (!layoutService.isVisible(Parts.PANEL_PART)) { + layoutService.setPartHidden(false, Parts.PANEL_PART); } // Focus into active panel - const panel = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel); + const panel = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel); panel?.focus(); } -} +}); const PositionPanelActionId = { LEFT: 'workbench.action.positionPanelLeft', @@ -257,19 +263,21 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne } } -export class SwitchPanelViewAction extends Action { +class SwitchPanelViewAction extends Action2 { - constructor( - id: string, - name: string, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService - ) { - super(id, name); + constructor(id: string, title: ICommandActionTitle) { + super({ + id, + title, + category: Categories.View, + f1: true, + }); } - override async run(offset: number): Promise { - const pinnedPanels = this.paneCompositeService.getPinnedPaneCompositeIds(ViewContainerLocation.Panel); - const activePanel = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel); + override async run(accessor: ServicesAccessor, offset: number): Promise { + const paneCompositeService = accessor.get(IPaneCompositePartService); + const pinnedPanels = paneCompositeService.getPinnedPaneCompositeIds(ViewContainerLocation.Panel); + const activePanel = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel); if (!activePanel) { return; } @@ -281,52 +289,36 @@ export class SwitchPanelViewAction extends Action { } } if (typeof targetPanelId === 'string') { - await this.paneCompositeService.openPaneComposite(targetPanelId, ViewContainerLocation.Panel, true); + await paneCompositeService.openPaneComposite(targetPanelId, ViewContainerLocation.Panel, true); } } } -export class PreviousPanelViewAction extends SwitchPanelViewAction { - - static readonly ID = 'workbench.action.previousPanelView'; - static readonly LABEL = localize('previousPanelView', 'Previous Panel View'); - - constructor( - id: string, - name: string, - @IPaneCompositePartService paneCompositeService: IPaneCompositePartService - ) { - super(id, name, paneCompositeService); +registerAction2(class extends SwitchPanelViewAction { + constructor() { + super('workbench.action.previousPanelView', { + value: localize('previousPanelView', 'Previous Panel View'), + original: 'Previous Panel View' + }); } - override run(): Promise { - return super.run(-1); + override run(accessor: ServicesAccessor): Promise { + return super.run(accessor, -1); } -} +}); -export class NextPanelViewAction extends SwitchPanelViewAction { - - static readonly ID = 'workbench.action.nextPanelView'; - static readonly LABEL = localize('nextPanelView', 'Next Panel View'); - - constructor( - id: string, - name: string, - @IPaneCompositePartService paneCompositeService: IPaneCompositePartService - ) { - super(id, name, paneCompositeService); +registerAction2(class extends SwitchPanelViewAction { + constructor() { + super('workbench.action.nextPanelView', { + value: localize('nextPanelView', 'Next Panel View'), + original: 'Next Panel View' + }); } - override run(): Promise { - return super.run(1); + override run(accessor: ServicesAccessor): Promise { + return super.run(accessor, 1); } -} - -const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(TogglePanelAction, { primary: KeyMod.CtrlCmd | KeyCode.KeyJ }), 'View: Toggle Panel Visibility', Categories.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPanelAction), 'View: Focus into Panel', Categories.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousPanelViewAction), 'View: Previous Panel View', Categories.View.value); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NextPanelViewAction), 'View: Next Panel View', Categories.View.value); +}); registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 6b8e20f84f4..a0c8283723b 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -46,6 +46,7 @@ import { StringSHA1 } from 'vs/base/common/hash'; import { URI } from 'vs/base/common/uri'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { ICommandService } from 'vs/platform/commands/common/commands'; interface ICachedPanel { id: string; @@ -927,6 +928,7 @@ export class PanelPart extends BasePanelPart { @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IContextKeyService contextKeyService: IContextKeyService, @IExtensionService extensionService: IExtensionService, + @ICommandService private commandService: ICommandService, ) { super( notificationService, @@ -984,7 +986,7 @@ export class PanelPart extends BasePanelPart { // show the contextual menu item if it is not in that position .filter(({ when }) => this.contextKeyService.contextMatchesRules(when)) .map(({ id, title }) => this.instantiationService.createInstance(SetPanelPositionAction, id, title.value)), - this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, localize('hidePanel', "Hide Panel")) + toAction({ id: TogglePanelAction.ID, label: localize('hidePanel', "Hide Panel"), run: () => this.commandService.executeCommand(TogglePanelAction.ID) }) ]); } From b401701d87537c46934c508eb3f4ccadb2218189 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 5 Oct 2022 10:05:40 -0700 Subject: [PATCH 337/599] address pr comments --- build/azure-pipelines/cli/compile-macos.yml | 34 --------- .../cli/install-rust-posix.yml | 35 +++++++++ ...nstall-rust.yml => install-rust-win32.yml} | 10 --- build/azure-pipelines/cli/prepare.js | 50 +------------ build/azure-pipelines/cli/prepare.ts | 57 +-------------- build/azure-pipelines/cli/prepare.yml | 35 --------- build/azure-pipelines/common/createAsset.js | 10 +-- build/azure-pipelines/common/createAsset.ts | 14 +--- .../cli-build-darwin.yml} | 36 ++++++--- .../darwin/product-build-darwin-cli-sign.yml | 17 ++--- .../darwin/product-build-darwin.yml | 3 +- .../cli-build-linux.yml} | 31 +++++++- .../linux/product-build-linux-client.yml | 4 +- build/azure-pipelines/mixin-distro-win32.yml | 1 - build/azure-pipelines/product-build.yml | 73 ++++++------------- .../{cli/vcpkg-deps.yml => vcpkg-install.yml} | 11 ++- .../azure-pipelines/win32/cli-build-win32.yml | 73 +++++++++++++++++++ .../win32/product-build-win32-cli-sign.yml | 18 ++++- .../win32/product-build-win32.yml | 15 ++-- build/gulpfile.editor.js | 3 +- build/gulpfile.extensions.js | 3 +- build/gulpfile.reh.js | 3 +- build/gulpfile.vscode.js | 3 +- build/gulpfile.vscode.linux.js | 3 +- build/gulpfile.vscode.web.js | 3 +- build/lib/electron.js | 3 +- build/lib/electron.ts | 3 +- build/lib/extensions.js | 4 +- build/lib/extensions.ts | 5 +- build/lib/util.js | 4 +- build/lib/util.ts | 2 - 31 files changed, 261 insertions(+), 305 deletions(-) delete mode 100644 build/azure-pipelines/cli/compile-macos.yml create mode 100644 build/azure-pipelines/cli/install-rust-posix.yml rename build/azure-pipelines/cli/{install-rust.yml => install-rust-win32.yml} (71%) delete mode 100644 build/azure-pipelines/cli/prepare.yml rename build/azure-pipelines/{cli/compile-windows.yml => darwin/cli-build-darwin.yml} (55%) rename build/azure-pipelines/{cli/compile-linux.yml => linux/cli-build-linux.yml} (63%) rename build/azure-pipelines/{cli/vcpkg-deps.yml => vcpkg-install.yml} (69%) create mode 100644 build/azure-pipelines/win32/cli-build-win32.yml diff --git a/build/azure-pipelines/cli/compile-macos.yml b/build/azure-pipelines/cli/compile-macos.yml deleted file mode 100644 index 01395a88e7c..00000000000 --- a/build/azure-pipelines/cli/compile-macos.yml +++ /dev/null @@ -1,34 +0,0 @@ -parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object - - name: VSCODE_CLI_DIR - type: string - default: './' - - name: VSCODE_CLI_BINARY_NAME - type: string - - name: channel - type: string - default: stable - -steps: - - template: ./install-rust.yml - parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} - displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} - env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} - artifact: ${{ target.artifact }} - displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/cli/install-rust-posix.yml b/build/azure-pipelines/cli/install-rust-posix.yml new file mode 100644 index 00000000000..16eee1a1b98 --- /dev/null +++ b/build/azure-pipelines/cli/install-rust-posix.yml @@ -0,0 +1,35 @@ +parameters: + - name: channel + type: string + default: stable + - name: targets + default: [] + type: object + +# Todo: use 1ES pipeline once extension is installed in ADO + +steps: + - script: | + set -e + curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Install Rust" + + - bash: | + rustup default $RUSTUP_TOOLCHAIN + rustup update $RUSTUP_TOOLCHAIN + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Set Rust version" + + - ${{ each target in parameters.targets }}: + - script: rustup target add ${{ target.target }} + displayName: "🎯 Adding '${{ target.target }}'" + + - script: | + rustc --version + cargo --version + rustup --version + displayName: "Check Rust versions" diff --git a/build/azure-pipelines/cli/install-rust.yml b/build/azure-pipelines/cli/install-rust-win32.yml similarity index 71% rename from build/azure-pipelines/cli/install-rust.yml rename to build/azure-pipelines/cli/install-rust-win32.yml index 7e70a293c6a..595201cc7c7 100644 --- a/build/azure-pipelines/cli/install-rust.yml +++ b/build/azure-pipelines/cli/install-rust-win32.yml @@ -9,15 +9,6 @@ parameters: # Todo: use 1ES pipeline once extension is installed in ADO steps: - - script: | - set -e - curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - env: - RUSTUP_TOOLCHAIN: ${{ parameters.channel }} - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) - displayName: "Install Rust" - - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs rustup-init.exe -y --profile minimal --default-toolchain %RUSTUP_TOOLCHAIN% --default-host x86_64-pc-windows-msvc @@ -25,7 +16,6 @@ steps: echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" env: RUSTUP_TOOLCHAIN: ${{ parameters.channel }} - condition: eq(variables['Agent.OS'], 'Windows_NT') displayName: "Install Rust" - bash: | diff --git a/build/azure-pipelines/cli/prepare.js b/build/azure-pipelines/cli/prepare.js index fdaf2ef8753..d4c7a556f08 100644 --- a/build/azure-pipelines/cli/prepare.js +++ b/build/azure-pipelines/cli/prepare.js @@ -6,35 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); const getVersion_1 = require("../../lib/getVersion"); const fs = require("fs"); -const cp = require("child_process"); const path = require("path"); const packageJson = require("../../../package.json"); -const os_1 = require("os"); const root = path.dirname(path.dirname(path.dirname(__dirname))); -const cliPath = path.join(root, 'cli'); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); const commit = (0, getVersion_1.getVersion)(root); -const getCargoLines = () => { - const fpath = path.join(cliPath, 'Cargo.toml'); - const cargo = fs.readFileSync(fpath, 'utf-8').split(/\r?\n/g); - return [fpath, cargo]; -}; -const addCargoDependency = (line) => { - const [fpath, cargo] = getCargoLines(); - const depsLine = cargo.findIndex(line => line.includes('[dependencies]')); - cargo.splice(depsLine + 1, 0, line); - fs.writeFileSync(fpath, cargo.join('\n')); -}; -const enableFeature = (feature) => { - const [fpath, cargo] = getCargoLines(); - const featuresLine = cargo.findIndex(line => line.includes('[features]')); - const prefix = 'default = '; - const defaultFeaturesLine = cargo.findIndex((line, i) => i > featuresLine && line.startsWith(prefix)); - const defaultFeatures = new Set(JSON.parse(cargo[defaultFeaturesLine].slice(prefix.length))); - defaultFeatures.add(feature); - cargo[defaultFeaturesLine] = prefix + JSON.stringify([...defaultFeatures]); - fs.writeFileSync(fpath, cargo.join('\n')); -}; /** * Sets build environment variables for the CLI for current contextual info. */ @@ -51,26 +27,6 @@ const setLauncherEnvironmentVars = () => { } } }; -/** - * Enables vscode-encrypt in the CLI if it's available in the current node_modules. - * This is not graceful since Cargo doesn't have a good way to do private or - * true-optional dependencies... - */ -const enableVscodeEncrypt = () => { - const dep = packageJson.dependencies['vscode-encrypt']; - if (!dep) { - return; - } - // If there's a vscode-encrypt in the package.json, install that (alone) in - // a temp dir for the build. This avoids having to do a full install of all - // node modules while building the CLI. - const stagingDir = path.join((0, os_1.tmpdir)(), `vscode-encrypt-staging-${Date.now()}`); - fs.mkdirSync(stagingDir); - fs.writeFileSync(path.join(stagingDir, 'package.json'), JSON.stringify({ dependencies: { 'vscode-encrypt': dep } })); - cp.execSync('yarn', { cwd: stagingDir, stdio: 'inherit' }); - const encryptPath = path.join(stagingDir, 'node_modules', 'vscode-encrypt', 'rs-pure'); - addCargoDependency(`vscode-encrypt = { "path" = "${encryptPath.replace(/\\/g, '/')}" }`); - enableFeature('vscode-encrypt'); -}; -setLauncherEnvironmentVars(); -enableVscodeEncrypt(); +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/prepare.ts b/build/azure-pipelines/cli/prepare.ts index fe08b56c84e..700c356b8b0 100644 --- a/build/azure-pipelines/cli/prepare.ts +++ b/build/azure-pipelines/cli/prepare.ts @@ -5,41 +5,13 @@ import { getVersion } from '../../lib/getVersion'; import * as fs from 'fs'; -import * as cp from 'child_process'; import * as path from 'path'; import * as packageJson from '../../../package.json'; -import { tmpdir } from 'os'; const root = path.dirname(path.dirname(path.dirname(__dirname))); -const cliPath = path.join(root, 'cli'); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); const commit = getVersion(root); -const getCargoLines = () => { - const fpath = path.join(cliPath, 'Cargo.toml'); - const cargo = fs.readFileSync(fpath, 'utf-8').split(/\r?\n/g); - return [fpath, cargo] as const; -}; - -const addCargoDependency = (line: string) => { - const [fpath, cargo] = getCargoLines(); - const depsLine = cargo.findIndex(line => line.includes('[dependencies]')); - cargo.splice(depsLine + 1, 0, line); - fs.writeFileSync(fpath, cargo.join('\n')); -}; - -const enableFeature = (feature: string) => { - const [fpath, cargo] = getCargoLines(); - const featuresLine = cargo.findIndex(line => line.includes('[features]')); - - const prefix = 'default = '; - const defaultFeaturesLine = cargo.findIndex((line, i) => i > featuresLine && line.startsWith(prefix)); - const defaultFeatures = new Set(JSON.parse(cargo[defaultFeaturesLine].slice(prefix.length))); - defaultFeatures.add(feature); - cargo[defaultFeaturesLine] = prefix + JSON.stringify([...defaultFeatures]); - fs.writeFileSync(fpath, cargo.join('\n')); -}; - /** * Sets build environment variables for the CLI for current contextual info. */ @@ -58,29 +30,6 @@ const setLauncherEnvironmentVars = () => { } }; -/** - * Enables vscode-encrypt in the CLI if it's available in the current node_modules. - * This is not graceful since Cargo doesn't have a good way to do private or - * true-optional dependencies... - */ -const enableVscodeEncrypt = () => { - const dep = (packageJson.dependencies as Record)['vscode-encrypt']; - if (!dep) { - return; - } - - // If there's a vscode-encrypt in the package.json, install that (alone) in - // a temp dir for the build. This avoids having to do a full install of all - // node modules while building the CLI. - const stagingDir = path.join(tmpdir(), `vscode-encrypt-staging-${Date.now()}`); - fs.mkdirSync(stagingDir); - fs.writeFileSync(path.join(stagingDir, 'package.json'), JSON.stringify({ dependencies: { 'vscode-encrypt': dep } })); - cp.execSync('yarn', { cwd: stagingDir, stdio: 'inherit' }); - const encryptPath = path.join(stagingDir, 'node_modules', 'vscode-encrypt', 'rs-pure'); - - addCargoDependency(`vscode-encrypt = { "path" = "${encryptPath.replace(/\\/g, '/')}" }`); - enableFeature('vscode-encrypt'); -}; - -setLauncherEnvironmentVars(); -enableVscodeEncrypt(); +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/prepare.yml b/build/azure-pipelines/cli/prepare.yml deleted file mode 100644 index 27bff9f2b4d..00000000000 --- a/build/azure-pipelines/cli/prepare.yml +++ /dev/null @@ -1,35 +0,0 @@ -parameters: - - name: VSCODE_IS_POSIX - type: boolean - - name: VSCODE_QUALITY - type: string - -steps: - - task: NodeTool@0 - inputs: - versionSpec: "16.x" - - - ${{ if eq(parameters.VSCODE_IS_POSIX, true) }}: - - template: ../mixin-distro-posix.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - - script: | - set -e - node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - - ${{ if ne(parameters.VSCODE_IS_POSIX, true) }}: - - template: ../mixin-distro-win32.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/cli/prepare.js } - displayName: Prepare CLI build - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" diff --git a/build/azure-pipelines/common/createAsset.js b/build/azure-pipelines/common/createAsset.js index 2117dbd27ad..10f1503f666 100644 --- a/build/azure-pipelines/common/createAsset.js +++ b/build/azure-pipelines/common/createAsset.js @@ -15,7 +15,6 @@ if (process.argv.length !== 8) { console.error('Usage: node createAsset.js PRODUCT OS ARCH TYPE NAME FILE'); process.exit(-1); } -const Ignore = Symbol('Ignore'); // Contains all of the logic for mapping details to our actual product names in CosmosDB function getPlatform(product, os, arch, type) { switch (os) { @@ -45,7 +44,7 @@ function getPlatform(product, os, arch, type) { } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-win32-${arch}`; + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -79,7 +78,7 @@ function getPlatform(product, os, arch, type) { return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; - case 'cli-unsigned': + case 'cli': return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); @@ -102,7 +101,7 @@ function getPlatform(product, os, arch, type) { } return `server-darwin-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-darwin-${arch}`; + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -142,9 +141,6 @@ async function main() { const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; // getPlatform needs the unprocessedType const platform = getPlatform(product, os, arch, unprocessedType); - if (platform === Ignore) { - return; - } const type = getRealType(unprocessedType); const quality = getEnv('VSCODE_QUALITY'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); diff --git a/build/azure-pipelines/common/createAsset.ts b/build/azure-pipelines/common/createAsset.ts index c9a9449e36d..139338dd24b 100644 --- a/build/azure-pipelines/common/createAsset.ts +++ b/build/azure-pipelines/common/createAsset.ts @@ -28,10 +28,8 @@ if (process.argv.length !== 8) { process.exit(-1); } -const Ignore = Symbol('Ignore'); - // Contains all of the logic for mapping details to our actual product names in CosmosDB -function getPlatform(product: string, os: string, arch: string, type: string): string | typeof Ignore { +function getPlatform(product: string, os: string, arch: string, type: string): string { switch (os) { case 'win32': switch (product) { @@ -59,7 +57,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-win32-${arch}`; + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -93,7 +91,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; - case 'cli-unsigned': + case 'cli': return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); @@ -116,7 +114,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s } return `server-darwin-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-darwin-${arch}`; + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -163,10 +161,6 @@ async function main(): Promise { const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; // getPlatform needs the unprocessedType const platform = getPlatform(product, os, arch, unprocessedType); - if (platform === Ignore) { - return; - } - const type = getRealType(unprocessedType); const quality = getEnv('VSCODE_QUALITY'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); diff --git a/build/azure-pipelines/cli/compile-windows.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml similarity index 55% rename from build/azure-pipelines/cli/compile-windows.yml rename to build/azure-pipelines/darwin/cli-build-darwin.yml index b024a281c69..f31fb4708d4 100644 --- a/build/azure-pipelines/cli/compile-windows.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -2,9 +2,10 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object + - name: VSCODE_QUALITY + type: string - name: VSCODE_CLI_DIR type: string - default: './' - name: VSCODE_CLI_BINARY_NAME type: string - name: channel @@ -12,10 +13,24 @@ parameters: default: stable steps: - - template: ./install-rust.yml + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} @@ -28,13 +43,14 @@ steps: VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: - OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib - OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include - ${{ if eq(target, 'aarch64-pc-windows-msvc') }}: - OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib - OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip artifact: ${{ target.artifact }} displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index d116ddca091..f1aa2f1c5ef 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -44,12 +44,6 @@ steps: artifact: ${{ target }} path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} - - script: | - set -e - mkdir -p $(agent.builddirectory)/signing - zip -j $(agent.builddirectory)/signing/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }} - displayName: Prepare ${{ target }} archive - - task: UseDotNet@2 inputs: version: 2.x @@ -59,21 +53,20 @@ steps: - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory)/signing "*.zip" + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" displayName: Codesign - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory)/signing "*.zip" + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" displayName: Notarize - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - script: | - ASSET_ID=$(echo "${{ target }}" | sed "s/-unsigned//") - mkdir -p $(Build.ArtifactStagingDirectory)/final/${{ target }} - unzip $(agent.builddirectory)/signing/${{ target }}.zip -d $(Build.ArtifactStagingDirectory)/final/${{ target }} + ASSET_ID=$(echo "${{ target }}" | sed "s/not_yet_signed_//") + mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - - publish: $(Build.ArtifactStagingDirectory)/final/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }} + - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 6f9d9f6260b..5778b2af54b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -191,11 +191,12 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(APP_PATH)/Contents/Resources/app/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - script: | set -e + unzip "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -d "$(APP_PATH)/Contents/Resources/app/bin" chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" diff --git a/build/azure-pipelines/cli/compile-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml similarity index 63% rename from build/azure-pipelines/cli/compile-linux.yml rename to build/azure-pipelines/linux/cli-build-linux.yml index d17708ddca2..9c219919aaf 100644 --- a/build/azure-pipelines/cli/compile-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -2,9 +2,10 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object + - name: VSCODE_QUALITY + type: string - name: VSCODE_CLI_DIR type: string - default: './' - name: VSCODE_CLI_BINARY_NAME type: string - name: channel @@ -19,10 +20,24 @@ steps: sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" || echo "link exists" displayName: Install build dependencies - - template: ./install-rust.yml + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} @@ -38,6 +53,14 @@ steps: CXX_aarch64-unknown-linux-musl: musl-g++ CC_aarch64-unknown-linux-musl: musl-gcc - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + includeRootFolder: false + archiveType: tar + tarCompression: gz + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz artifact: ${{ target.artifact }} displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index ddc7a478685..6e12a1167ce 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -263,12 +263,12 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - script: | set -e - chmod +x "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" + tar -xzvf $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" fi diff --git a/build/azure-pipelines/mixin-distro-win32.yml b/build/azure-pipelines/mixin-distro-win32.yml index 2b055428bfa..5ff4eacf41c 100644 --- a/build/azure-pipelines/mixin-distro-win32.yml +++ b/build/azure-pipelines/mixin-distro-win32.yml @@ -1,4 +1,3 @@ - parameters: - name: VSCODE_QUALITY type: string diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 750dd018ac0..c0baba98066 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -111,10 +111,6 @@ variables: value: ${{ parameters.VSCODE_QUALITY }} - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - - name: VSCODE_BUILD_STAGE_ARM_LINUX - value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }} - - name: VSCODE_BUILD_STAGE_X86_LINUX - value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }} - name: VSCODE_BUILD_STAGE_LINUX value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_MACOS @@ -185,25 +181,22 @@ stages: - stage: CompileCLI dependsOn: [] jobs: - - ${{ if eq(variables.VSCODE_BUILD_STAGE_X86_LINUX, true) }}: + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: - job: LinuxX86 pool: vscode-1es-linux steps: - - template: ./cli/prepare.yml + - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-linux.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: - - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli-unsigned } + - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli-unsigned } + - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } - - ${{ if eq(variables.VSCODE_BUILD_STAGE_ARM_LINUX, true) }}: + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }}: - job: LinuxArm64 pool: vscode-1es-linux-20.04-arm64 steps: @@ -217,65 +210,47 @@ stages: sudo apt update -y sudo apt install -y build-essential pkg-config displayName: Install build dependencies - - template: ./cli/prepare.yml + - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-linux.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: - - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli-unsigned } + - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli-unsigned } + - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } - ${{ if eq(variables.VSCODE_BUILD_STAGE_MACOS, true) }}: - job: MacOS pool: vmImage: macOS-latest steps: - - template: ./cli/prepare.yml + - template: ./darwin/cli-build-darwin.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-macos.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - { target: x86_64-apple-darwin, artifact: vscode_cli_darwin_x64_cli-unsigned } + - { target: x86_64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - { target: aarch64-apple-darwin, artifact: vscode_cli_darwin_arm64_cli-unsigned } + - { target: aarch64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_arm64_cli } - ${{ if eq(variables.VSCODE_BUILD_STAGE_WINDOWS, true) }}: - job: Windows pool: vscode-1es-windows steps: - - template: ./cli/prepare.yml + - template: ./win32/cli-build-win32.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: false - - template: ./cli/vcpkg-deps.yml - parameters: - targets: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - x64-windows-static-md - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - arm64-windows-static-md - vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg - targetDirectory: $(Build.ArtifactStagingDirectory)/deps - - template: ./cli/compile-windows.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - { target: x86_64-pc-windows-msvc, artifact: vscode_cli_win32_x64_cli-unsigned } + - { target: x86_64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - { target: aarch64-pc-windows-msvc, artifact: vscode_cli_win32_arm64_cli-unsigned } + - { target: aarch64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_arm64_cli } - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -340,7 +315,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_win32_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: @@ -371,7 +346,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_win32_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: @@ -383,9 +358,9 @@ stages: VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_ARTIFACTS: - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - vscode_cli_win32_x64_cli-unsigned + - not_yet_signed_vscode_cli_win32_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - vscode_cli_win32_arm64_cli-unsigned + - not_yet_signed_vscode_cli_win32_arm64_cli - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -484,7 +459,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true), ne(variables['VSCODE_PUBLISH'], 'false')) }}: @@ -538,7 +513,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} # TODO@joaomoreno: We don't ship ARM snaps for now @@ -633,7 +608,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_darwin_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: @@ -669,9 +644,9 @@ stages: VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_ARTIFACTS: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - vscode_cli_darwin_x64_cli-unsigned + - not_yet_signed_vscode_cli_darwin_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - vscode_cli_darwin_arm64_cli-unsigned + - not_yet_signed_vscode_cli_darwin_arm64_cli - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 @@ -687,7 +662,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_darwin_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: diff --git a/build/azure-pipelines/cli/vcpkg-deps.yml b/build/azure-pipelines/vcpkg-install.yml similarity index 69% rename from build/azure-pipelines/cli/vcpkg-deps.yml rename to build/azure-pipelines/vcpkg-install.yml index 8c2928b0f70..d11d5c5d5c3 100644 --- a/build/azure-pipelines/cli/vcpkg-deps.yml +++ b/build/azure-pipelines/vcpkg-install.yml @@ -8,11 +8,14 @@ parameters: type: string steps: - - script: git clone https://github.com/microsoft/vcpkg.git $(Build.ArtifactStagingDirectory)/vcpkg - displayName: Checkout vcpkg - - - script: $(Build.ArtifactStagingDirectory)/vcpkg/bootstrap-vcpkg.bat + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { git clone https://github.com/microsoft/vcpkg.git $(Build.ArtifactStagingDirectory)/vcpkg } + exec { cd $(Build.ArtifactStagingDirectory)/vcpkg; git checkout 779ce74ef67d3e12d904da1b15f9ed5626d5f677 } + exec { $(Build.ArtifactStagingDirectory)/vcpkg/bootstrap-vcpkg.bat } + Write-Output "##vso[task.setvariable variable=VSCODE_DID_BOOTSTRAP_VCPKG]true" displayName: Bootstrap vcpkg + condition: not(eq(variables.VSCODE_DID_BOOTSTRAP_VCPKG, true)) - ${{ each target in parameters.targets }}: - task: Cache@2 diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml new file mode 100644 index 00000000000..f203f430942 --- /dev/null +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -0,0 +1,73 @@ +parameters: + - name: VSCODE_CLI_TARGETS + default: [] + type: object + - name: VSCODE_QUALITY + type: string + - name: VSCODE_CLI_DIR + type: string + - name: VSCODE_CLI_BINARY_NAME + type: string + - name: channel + type: string + default: stable + +steps: + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/cli/prepare.js } + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-win32.yml + parameters: + targets: ${{ parameters.VSCODE_CLI_TARGETS }} + + - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: + - template: ../vcpkg-install.yml + parameters: + targets: + - ${{ if eq(target.target, 'x86_64-pc-windows-msvc') }}: + - x64-windows-static-md + - ${{ if eq(target.target, 'aarch64-pc-windows-msvc') }}: + - arm64-windows-static-md + vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg + targetDirectory: $(Build.ArtifactStagingDirectory)/deps + + - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + displayName: Compile ${{ target.artifact }} + workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + env: + VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) + VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) + VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) + VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} + VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) + VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) + ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include + ${{ if eq(target, 'aarch64-pc-windows-msvc') }}: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include + + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + artifact: ${{ target.artifact }} + displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index ca45ef2f864..db38e753738 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -31,6 +31,11 @@ steps: artifact: ${{ target }} path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip + destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} + - task: UseDotNet@2 displayName: "Use .NET" inputs: @@ -53,14 +58,21 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.exe" } + exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" } displayName: "Code sign" - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - powershell: | - $ASSET_ID = "${{ target }}".replace("-unsigned", ""); + $ASSET_ID = "${{ target }}".replace("not_yet_signed_", ""); echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + + - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 4a402d478f3..caec3dc49e2 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -186,14 +186,19 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - - ${{ if ne(parameters.VSCODE_QUALITY, 'stable') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + Expand-Archive -Path "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" + + if ("$(VSCODE_QUALITY)" -ne "stable") + { Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME).exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY).exe" - displayName: Move VS Code CLI + } + + displayName: Move VS Code CLI - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - powershell: | diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 94724bb410d..fb3a148f9a8 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -6,6 +6,7 @@ const gulp = require('gulp'); const path = require('path'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const es = require('event-stream'); @@ -18,7 +19,7 @@ const monacoapi = require('./lib/monaco-api'); const fs = require('fs'); const root = path.dirname(__dirname); -const sha1 = util.getVersion(root); +const sha1 = getVersion(root); const semver = require('./monaco/package.json').version; const headerVersion = semver + '(' + sha1 + ')'; diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 07033b9c960..c0b79bc0f9d 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -12,12 +12,13 @@ const nodeUtil = require('util'); const es = require('event-stream'); const filter = require('gulp-filter'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const watcher = require('./lib/watch'); const createReporter = require('./lib/reporter').createReporter; const glob = require('glob'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const plumber = require('gulp-plumber'); const ext = require('./lib/extensions'); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 980f647c854..7475e04d6e5 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -9,6 +9,7 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const product = require('../product.json'); @@ -30,7 +31,7 @@ const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileCont const cp = require('child_process'); const REPO_ROOT = path.dirname(__dirname); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const BUILD_ROOT = path.dirname(REPO_ROOT); const REMOTE_FOLDER = path.join(REPO_ROOT, 'remote'); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 6947d1ee1ed..b6d3523d8b5 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -18,11 +18,12 @@ const replace = require('gulp-replace'); const filter = require('gulp-filter'); const _ = require('underscore'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const buildfile = require('../src/buildfile'); const optimize = require('./lib/optimize'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const packageJson = require('../package.json'); const product = require('../product.json'); const crypto = require('crypto'); diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 4a25ca5ab04..cdc887013d8 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -12,6 +12,7 @@ const shell = require('gulp-shell'); const es = require('event-stream'); const vfs = require('vinyl-fs'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const packageJson = require('../package.json'); const product = require('../product.json'); @@ -20,7 +21,7 @@ const sysrootInstaller = require('./linux/debian/install-sysroot'); const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps; const path = require('path'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const linuxPackageRevision = Math.floor(new Date().getTime() / 1000); diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index c5b09393728..115f3ce499f 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -9,6 +9,7 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const product = require('../product.json'); @@ -26,7 +27,7 @@ const REPO_ROOT = path.dirname(__dirname); const BUILD_ROOT = path.dirname(REPO_ROOT); const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const quality = product.quality; const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version; diff --git a/build/lib/electron.js b/build/lib/electron.js index 610d5bb6377..38f13d0ff08 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -11,12 +11,13 @@ const vfs = require("vinyl-fs"); const filter = require("gulp-filter"); const _ = require("underscore"); const util = require("./util"); +const getVersion_1 = require("./getVersion"); function isDocumentSuffix(str) { return str === 'document' || str === 'script' || str === 'file' || str === 'source code'; } const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); /** * Generate a `DarwinDocumentType` given a list of file extensions, an icon name, and an optional suffix or file type name. diff --git a/build/lib/electron.ts b/build/lib/electron.ts index c37a0f6eae3..247de01c563 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -9,6 +9,7 @@ import * as vfs from 'vinyl-fs'; import * as filter from 'gulp-filter'; import * as _ from 'underscore'; import * as util from './util'; +import { getVersion } from './getVersion'; type DarwinDocumentSuffix = 'document' | 'script' | 'file' | 'source code'; type DarwinDocumentType = { @@ -26,7 +27,7 @@ function isDocumentSuffix(str?: string): str is DarwinDocumentSuffix { const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = getVersion(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index f22d9749fb0..f69b3322018 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -26,9 +26,9 @@ const jsoncParser = require("jsonc-parser"); const dependencies_1 = require("./dependencies"); const _ = require("underscore"); const builtInExtensions_1 = require("./builtInExtensions"); -const util = require('./util'); +const getVersion_1 = require("./getVersion"); const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input) { const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 35447b284ad..36f29fcf3a1 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -26,9 +26,10 @@ import webpack = require('webpack'); import { getProductionDependencies } from './dependencies'; import _ = require('underscore'); import { getExtensionStream } from './builtInExtensions'; -const util = require('./util'); +import { getVersion } from './getVersion'; + const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = getVersion(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input: Stream): Stream { diff --git a/build/lib/util.js b/build/lib/util.js index fc62c844b6a..3eae325612a 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = exports.getVersion = void 0; +exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = void 0; const es = require("event-stream"); const _debounce = require("debounce"); const _filter = require("gulp-filter"); @@ -13,8 +13,6 @@ const path = require("path"); const fs = require("fs"); const _rimraf = require("rimraf"); const VinylFile = require("vinyl"); -var getVersion_1 = require("./getVersion"); -Object.defineProperty(exports, "getVersion", { enumerable: true, get: function () { return getVersion_1.getVersion; } }); const root = path.dirname(path.dirname(__dirname)); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { diff --git a/build/lib/util.ts b/build/lib/util.ts index 6fb799f2699..bbe6c52ef41 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -15,8 +15,6 @@ import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; -export { getVersion } from './getVersion'; - const root = path.dirname(path.dirname(__dirname)); export interface ICancellationToken { From 18f743d534ef3f528c5e81e82e695b87c60d2ebf Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 5 Oct 2022 10:05:40 -0700 Subject: [PATCH 338/599] address pr comments --- build/azure-pipelines/cli/compile-macos.yml | 34 --------- .../cli/install-rust-posix.yml | 35 +++++++++ ...nstall-rust.yml => install-rust-win32.yml} | 10 --- build/azure-pipelines/cli/prepare.js | 50 +------------ build/azure-pipelines/cli/prepare.ts | 57 +-------------- build/azure-pipelines/cli/prepare.yml | 35 --------- build/azure-pipelines/common/createAsset.js | 10 +-- build/azure-pipelines/common/createAsset.ts | 14 +--- .../cli-build-darwin.yml} | 36 ++++++--- .../darwin/product-build-darwin-cli-sign.yml | 17 ++--- .../darwin/product-build-darwin.yml | 3 +- .../cli-build-linux.yml} | 31 +++++++- .../linux/product-build-linux-client.yml | 4 +- build/azure-pipelines/mixin-distro-win32.yml | 1 - build/azure-pipelines/product-build.yml | 73 ++++++------------- .../{cli/vcpkg-deps.yml => vcpkg-install.yml} | 11 ++- .../azure-pipelines/win32/cli-build-win32.yml | 73 +++++++++++++++++++ .../win32/product-build-win32-cli-sign.yml | 18 ++++- .../win32/product-build-win32.yml | 15 ++-- build/gulpfile.editor.js | 3 +- build/gulpfile.extensions.js | 3 +- build/gulpfile.reh.js | 3 +- build/gulpfile.vscode.js | 3 +- build/gulpfile.vscode.linux.js | 3 +- build/gulpfile.vscode.web.js | 3 +- build/lib/electron.js | 3 +- build/lib/electron.ts | 3 +- build/lib/extensions.js | 4 +- build/lib/extensions.ts | 5 +- build/lib/util.js | 4 +- build/lib/util.ts | 2 - 31 files changed, 261 insertions(+), 305 deletions(-) delete mode 100644 build/azure-pipelines/cli/compile-macos.yml create mode 100644 build/azure-pipelines/cli/install-rust-posix.yml rename build/azure-pipelines/cli/{install-rust.yml => install-rust-win32.yml} (71%) delete mode 100644 build/azure-pipelines/cli/prepare.yml rename build/azure-pipelines/{cli/compile-windows.yml => darwin/cli-build-darwin.yml} (55%) rename build/azure-pipelines/{cli/compile-linux.yml => linux/cli-build-linux.yml} (63%) rename build/azure-pipelines/{cli/vcpkg-deps.yml => vcpkg-install.yml} (69%) create mode 100644 build/azure-pipelines/win32/cli-build-win32.yml diff --git a/build/azure-pipelines/cli/compile-macos.yml b/build/azure-pipelines/cli/compile-macos.yml deleted file mode 100644 index 01395a88e7c..00000000000 --- a/build/azure-pipelines/cli/compile-macos.yml +++ /dev/null @@ -1,34 +0,0 @@ -parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object - - name: VSCODE_CLI_DIR - type: string - default: './' - - name: VSCODE_CLI_BINARY_NAME - type: string - - name: channel - type: string - default: stable - -steps: - - template: ./install-rust.yml - parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} - displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} - env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} - artifact: ${{ target.artifact }} - displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/cli/install-rust-posix.yml b/build/azure-pipelines/cli/install-rust-posix.yml new file mode 100644 index 00000000000..16eee1a1b98 --- /dev/null +++ b/build/azure-pipelines/cli/install-rust-posix.yml @@ -0,0 +1,35 @@ +parameters: + - name: channel + type: string + default: stable + - name: targets + default: [] + type: object + +# Todo: use 1ES pipeline once extension is installed in ADO + +steps: + - script: | + set -e + curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Install Rust" + + - bash: | + rustup default $RUSTUP_TOOLCHAIN + rustup update $RUSTUP_TOOLCHAIN + env: + RUSTUP_TOOLCHAIN: ${{ parameters.channel }} + displayName: "Set Rust version" + + - ${{ each target in parameters.targets }}: + - script: rustup target add ${{ target.target }} + displayName: "🎯 Adding '${{ target.target }}'" + + - script: | + rustc --version + cargo --version + rustup --version + displayName: "Check Rust versions" diff --git a/build/azure-pipelines/cli/install-rust.yml b/build/azure-pipelines/cli/install-rust-win32.yml similarity index 71% rename from build/azure-pipelines/cli/install-rust.yml rename to build/azure-pipelines/cli/install-rust-win32.yml index 7e70a293c6a..595201cc7c7 100644 --- a/build/azure-pipelines/cli/install-rust.yml +++ b/build/azure-pipelines/cli/install-rust-win32.yml @@ -9,15 +9,6 @@ parameters: # Todo: use 1ES pipeline once extension is installed in ADO steps: - - script: | - set -e - curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - env: - RUSTUP_TOOLCHAIN: ${{ parameters.channel }} - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) - displayName: "Install Rust" - - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs rustup-init.exe -y --profile minimal --default-toolchain %RUSTUP_TOOLCHAIN% --default-host x86_64-pc-windows-msvc @@ -25,7 +16,6 @@ steps: echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" env: RUSTUP_TOOLCHAIN: ${{ parameters.channel }} - condition: eq(variables['Agent.OS'], 'Windows_NT') displayName: "Install Rust" - bash: | diff --git a/build/azure-pipelines/cli/prepare.js b/build/azure-pipelines/cli/prepare.js index fdaf2ef8753..d4c7a556f08 100644 --- a/build/azure-pipelines/cli/prepare.js +++ b/build/azure-pipelines/cli/prepare.js @@ -6,35 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); const getVersion_1 = require("../../lib/getVersion"); const fs = require("fs"); -const cp = require("child_process"); const path = require("path"); const packageJson = require("../../../package.json"); -const os_1 = require("os"); const root = path.dirname(path.dirname(path.dirname(__dirname))); -const cliPath = path.join(root, 'cli'); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); const commit = (0, getVersion_1.getVersion)(root); -const getCargoLines = () => { - const fpath = path.join(cliPath, 'Cargo.toml'); - const cargo = fs.readFileSync(fpath, 'utf-8').split(/\r?\n/g); - return [fpath, cargo]; -}; -const addCargoDependency = (line) => { - const [fpath, cargo] = getCargoLines(); - const depsLine = cargo.findIndex(line => line.includes('[dependencies]')); - cargo.splice(depsLine + 1, 0, line); - fs.writeFileSync(fpath, cargo.join('\n')); -}; -const enableFeature = (feature) => { - const [fpath, cargo] = getCargoLines(); - const featuresLine = cargo.findIndex(line => line.includes('[features]')); - const prefix = 'default = '; - const defaultFeaturesLine = cargo.findIndex((line, i) => i > featuresLine && line.startsWith(prefix)); - const defaultFeatures = new Set(JSON.parse(cargo[defaultFeaturesLine].slice(prefix.length))); - defaultFeatures.add(feature); - cargo[defaultFeaturesLine] = prefix + JSON.stringify([...defaultFeatures]); - fs.writeFileSync(fpath, cargo.join('\n')); -}; /** * Sets build environment variables for the CLI for current contextual info. */ @@ -51,26 +27,6 @@ const setLauncherEnvironmentVars = () => { } } }; -/** - * Enables vscode-encrypt in the CLI if it's available in the current node_modules. - * This is not graceful since Cargo doesn't have a good way to do private or - * true-optional dependencies... - */ -const enableVscodeEncrypt = () => { - const dep = packageJson.dependencies['vscode-encrypt']; - if (!dep) { - return; - } - // If there's a vscode-encrypt in the package.json, install that (alone) in - // a temp dir for the build. This avoids having to do a full install of all - // node modules while building the CLI. - const stagingDir = path.join((0, os_1.tmpdir)(), `vscode-encrypt-staging-${Date.now()}`); - fs.mkdirSync(stagingDir); - fs.writeFileSync(path.join(stagingDir, 'package.json'), JSON.stringify({ dependencies: { 'vscode-encrypt': dep } })); - cp.execSync('yarn', { cwd: stagingDir, stdio: 'inherit' }); - const encryptPath = path.join(stagingDir, 'node_modules', 'vscode-encrypt', 'rs-pure'); - addCargoDependency(`vscode-encrypt = { "path" = "${encryptPath.replace(/\\/g, '/')}" }`); - enableFeature('vscode-encrypt'); -}; -setLauncherEnvironmentVars(); -enableVscodeEncrypt(); +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/prepare.ts b/build/azure-pipelines/cli/prepare.ts index fe08b56c84e..700c356b8b0 100644 --- a/build/azure-pipelines/cli/prepare.ts +++ b/build/azure-pipelines/cli/prepare.ts @@ -5,41 +5,13 @@ import { getVersion } from '../../lib/getVersion'; import * as fs from 'fs'; -import * as cp from 'child_process'; import * as path from 'path'; import * as packageJson from '../../../package.json'; -import { tmpdir } from 'os'; const root = path.dirname(path.dirname(path.dirname(__dirname))); -const cliPath = path.join(root, 'cli'); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); const commit = getVersion(root); -const getCargoLines = () => { - const fpath = path.join(cliPath, 'Cargo.toml'); - const cargo = fs.readFileSync(fpath, 'utf-8').split(/\r?\n/g); - return [fpath, cargo] as const; -}; - -const addCargoDependency = (line: string) => { - const [fpath, cargo] = getCargoLines(); - const depsLine = cargo.findIndex(line => line.includes('[dependencies]')); - cargo.splice(depsLine + 1, 0, line); - fs.writeFileSync(fpath, cargo.join('\n')); -}; - -const enableFeature = (feature: string) => { - const [fpath, cargo] = getCargoLines(); - const featuresLine = cargo.findIndex(line => line.includes('[features]')); - - const prefix = 'default = '; - const defaultFeaturesLine = cargo.findIndex((line, i) => i > featuresLine && line.startsWith(prefix)); - const defaultFeatures = new Set(JSON.parse(cargo[defaultFeaturesLine].slice(prefix.length))); - defaultFeatures.add(feature); - cargo[defaultFeaturesLine] = prefix + JSON.stringify([...defaultFeatures]); - fs.writeFileSync(fpath, cargo.join('\n')); -}; - /** * Sets build environment variables for the CLI for current contextual info. */ @@ -58,29 +30,6 @@ const setLauncherEnvironmentVars = () => { } }; -/** - * Enables vscode-encrypt in the CLI if it's available in the current node_modules. - * This is not graceful since Cargo doesn't have a good way to do private or - * true-optional dependencies... - */ -const enableVscodeEncrypt = () => { - const dep = (packageJson.dependencies as Record)['vscode-encrypt']; - if (!dep) { - return; - } - - // If there's a vscode-encrypt in the package.json, install that (alone) in - // a temp dir for the build. This avoids having to do a full install of all - // node modules while building the CLI. - const stagingDir = path.join(tmpdir(), `vscode-encrypt-staging-${Date.now()}`); - fs.mkdirSync(stagingDir); - fs.writeFileSync(path.join(stagingDir, 'package.json'), JSON.stringify({ dependencies: { 'vscode-encrypt': dep } })); - cp.execSync('yarn', { cwd: stagingDir, stdio: 'inherit' }); - const encryptPath = path.join(stagingDir, 'node_modules', 'vscode-encrypt', 'rs-pure'); - - addCargoDependency(`vscode-encrypt = { "path" = "${encryptPath.replace(/\\/g, '/')}" }`); - enableFeature('vscode-encrypt'); -}; - -setLauncherEnvironmentVars(); -enableVscodeEncrypt(); +if (require.main === module) { + setLauncherEnvironmentVars(); +} diff --git a/build/azure-pipelines/cli/prepare.yml b/build/azure-pipelines/cli/prepare.yml deleted file mode 100644 index 27bff9f2b4d..00000000000 --- a/build/azure-pipelines/cli/prepare.yml +++ /dev/null @@ -1,35 +0,0 @@ -parameters: - - name: VSCODE_IS_POSIX - type: boolean - - name: VSCODE_QUALITY - type: string - -steps: - - task: NodeTool@0 - inputs: - versionSpec: "16.x" - - - ${{ if eq(parameters.VSCODE_IS_POSIX, true) }}: - - template: ../mixin-distro-posix.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - - script: | - set -e - node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - - ${{ if ne(parameters.VSCODE_IS_POSIX, true) }}: - - template: ../mixin-distro-win32.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/azure-pipelines/cli/prepare.js } - displayName: Prepare CLI build - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" diff --git a/build/azure-pipelines/common/createAsset.js b/build/azure-pipelines/common/createAsset.js index 2117dbd27ad..10f1503f666 100644 --- a/build/azure-pipelines/common/createAsset.js +++ b/build/azure-pipelines/common/createAsset.js @@ -15,7 +15,6 @@ if (process.argv.length !== 8) { console.error('Usage: node createAsset.js PRODUCT OS ARCH TYPE NAME FILE'); process.exit(-1); } -const Ignore = Symbol('Ignore'); // Contains all of the logic for mapping details to our actual product names in CosmosDB function getPlatform(product, os, arch, type) { switch (os) { @@ -45,7 +44,7 @@ function getPlatform(product, os, arch, type) { } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-win32-${arch}`; + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -79,7 +78,7 @@ function getPlatform(product, os, arch, type) { return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; - case 'cli-unsigned': + case 'cli': return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); @@ -102,7 +101,7 @@ function getPlatform(product, os, arch, type) { } return `server-darwin-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-darwin-${arch}`; + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -142,9 +141,6 @@ async function main() { const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; // getPlatform needs the unprocessedType const platform = getPlatform(product, os, arch, unprocessedType); - if (platform === Ignore) { - return; - } const type = getRealType(unprocessedType); const quality = getEnv('VSCODE_QUALITY'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); diff --git a/build/azure-pipelines/common/createAsset.ts b/build/azure-pipelines/common/createAsset.ts index c9a9449e36d..139338dd24b 100644 --- a/build/azure-pipelines/common/createAsset.ts +++ b/build/azure-pipelines/common/createAsset.ts @@ -28,10 +28,8 @@ if (process.argv.length !== 8) { process.exit(-1); } -const Ignore = Symbol('Ignore'); - // Contains all of the logic for mapping details to our actual product names in CosmosDB -function getPlatform(product: string, os: string, arch: string, type: string): string | typeof Ignore { +function getPlatform(product: string, os: string, arch: string, type: string): string { switch (os) { case 'win32': switch (product) { @@ -59,7 +57,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s } return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-win32-${arch}`; + return `cli-win32-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -93,7 +91,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s return `linux-deb-${arch}`; case 'rpm-package': return `linux-rpm-${arch}`; - case 'cli-unsigned': + case 'cli': return `cli-linux-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); @@ -116,7 +114,7 @@ function getPlatform(product: string, os: string, arch: string, type: string): s } return `server-darwin-${arch}-web`; case 'cli': - return type === 'cli-unsigned' ? Ignore : `cli-darwin-${arch}`; + return `cli-darwin-${arch}`; default: throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); } @@ -163,10 +161,6 @@ async function main(): Promise { const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; // getPlatform needs the unprocessedType const platform = getPlatform(product, os, arch, unprocessedType); - if (platform === Ignore) { - return; - } - const type = getRealType(unprocessedType); const quality = getEnv('VSCODE_QUALITY'); const commit = process.env['VSCODE_DISTRO_COMMIT'] || getEnv('BUILD_SOURCEVERSION'); diff --git a/build/azure-pipelines/cli/compile-windows.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml similarity index 55% rename from build/azure-pipelines/cli/compile-windows.yml rename to build/azure-pipelines/darwin/cli-build-darwin.yml index b024a281c69..f31fb4708d4 100644 --- a/build/azure-pipelines/cli/compile-windows.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -2,9 +2,10 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object + - name: VSCODE_QUALITY + type: string - name: VSCODE_CLI_DIR type: string - default: './' - name: VSCODE_CLI_BINARY_NAME type: string - name: channel @@ -12,10 +13,24 @@ parameters: default: stable steps: - - template: ./install-rust.yml + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} @@ -28,13 +43,14 @@ steps: VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: - OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib - OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include - ${{ if eq(target, 'aarch64-pc-windows-msvc') }}: - OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib - OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip artifact: ${{ target.artifact }} displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index d116ddca091..f1aa2f1c5ef 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -44,12 +44,6 @@ steps: artifact: ${{ target }} path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} - - script: | - set -e - mkdir -p $(agent.builddirectory)/signing - zip -j $(agent.builddirectory)/signing/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }} - displayName: Prepare ${{ target }} archive - - task: UseDotNet@2 inputs: version: 2.x @@ -59,21 +53,20 @@ steps: - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory)/signing "*.zip" + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" displayName: Codesign - script: | set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(agent.builddirectory)/signing "*.zip" + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" displayName: Notarize - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - script: | - ASSET_ID=$(echo "${{ target }}" | sed "s/-unsigned//") - mkdir -p $(Build.ArtifactStagingDirectory)/final/${{ target }} - unzip $(agent.builddirectory)/signing/${{ target }}.zip -d $(Build.ArtifactStagingDirectory)/final/${{ target }} + ASSET_ID=$(echo "${{ target }}" | sed "s/not_yet_signed_//") + mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - - publish: $(Build.ArtifactStagingDirectory)/final/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }} + - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 6f9d9f6260b..5778b2af54b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -191,11 +191,12 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(APP_PATH)/Contents/Resources/app/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - script: | set -e + unzip "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -d "$(APP_PATH)/Contents/Resources/app/bin" chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" diff --git a/build/azure-pipelines/cli/compile-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml similarity index 63% rename from build/azure-pipelines/cli/compile-linux.yml rename to build/azure-pipelines/linux/cli-build-linux.yml index d17708ddca2..9c219919aaf 100644 --- a/build/azure-pipelines/cli/compile-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -2,9 +2,10 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object + - name: VSCODE_QUALITY + type: string - name: VSCODE_CLI_DIR type: string - default: './' - name: VSCODE_CLI_BINARY_NAME type: string - name: channel @@ -19,10 +20,24 @@ steps: sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" || echo "link exists" displayName: Install build dependencies - - template: ./install-rust.yml + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-posix.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - script: | + set -e + node build/azure-pipelines/cli/prepare.js + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-posix.yml parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - channel: ${{ parameters.channel }} - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} @@ -38,6 +53,14 @@ steps: CXX_aarch64-unknown-linux-musl: musl-g++ CC_aarch64-unknown-linux-musl: musl-gcc - - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + includeRootFolder: false + archiveType: tar + tarCompression: gz + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz artifact: ${{ target.artifact }} displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index ddc7a478685..6e12a1167ce 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -263,12 +263,12 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - script: | set -e - chmod +x "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" + tar -xzvf $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" fi diff --git a/build/azure-pipelines/mixin-distro-win32.yml b/build/azure-pipelines/mixin-distro-win32.yml index 2b055428bfa..5ff4eacf41c 100644 --- a/build/azure-pipelines/mixin-distro-win32.yml +++ b/build/azure-pipelines/mixin-distro-win32.yml @@ -1,4 +1,3 @@ - parameters: - name: VSCODE_QUALITY type: string diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 750dd018ac0..c0baba98066 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -111,10 +111,6 @@ variables: value: ${{ parameters.VSCODE_QUALITY }} - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - - name: VSCODE_BUILD_STAGE_ARM_LINUX - value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }} - - name: VSCODE_BUILD_STAGE_X86_LINUX - value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }} - name: VSCODE_BUILD_STAGE_LINUX value: ${{ or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_MACOS @@ -185,25 +181,22 @@ stages: - stage: CompileCLI dependsOn: [] jobs: - - ${{ if eq(variables.VSCODE_BUILD_STAGE_X86_LINUX, true) }}: + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: - job: LinuxX86 pool: vscode-1es-linux steps: - - template: ./cli/prepare.yml + - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-linux.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: - - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli-unsigned } + - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli-unsigned } + - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } - - ${{ if eq(variables.VSCODE_BUILD_STAGE_ARM_LINUX, true) }}: + - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }}: - job: LinuxArm64 pool: vscode-1es-linux-20.04-arm64 steps: @@ -217,65 +210,47 @@ stages: sudo apt update -y sudo apt install -y build-essential pkg-config displayName: Install build dependencies - - template: ./cli/prepare.yml + - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-linux.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: - - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli-unsigned } + - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli-unsigned } + - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } - ${{ if eq(variables.VSCODE_BUILD_STAGE_MACOS, true) }}: - job: MacOS pool: vmImage: macOS-latest steps: - - template: ./cli/prepare.yml + - template: ./darwin/cli-build-darwin.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: true - - template: ./cli/compile-macos.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - { target: x86_64-apple-darwin, artifact: vscode_cli_darwin_x64_cli-unsigned } + - { target: x86_64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - { target: aarch64-apple-darwin, artifact: vscode_cli_darwin_arm64_cli-unsigned } + - { target: aarch64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_arm64_cli } - ${{ if eq(variables.VSCODE_BUILD_STAGE_WINDOWS, true) }}: - job: Windows pool: vscode-1es-windows steps: - - template: ./cli/prepare.yml + - template: ./win32/cli-build-win32.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_IS_POSIX: false - - template: ./cli/vcpkg-deps.yml - parameters: - targets: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - x64-windows-static-md - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - arm64-windows-static-md - vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg - targetDirectory: $(Build.ArtifactStagingDirectory)/deps - - template: ./cli/compile-windows.yml - parameters: VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_TARGETS: - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - { target: x86_64-pc-windows-msvc, artifact: vscode_cli_win32_x64_cli-unsigned } + - { target: x86_64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_x64_cli } - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - { target: aarch64-pc-windows-msvc, artifact: vscode_cli_win32_arm64_cli-unsigned } + - { target: aarch64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_arm64_cli } - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -340,7 +315,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_win32_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: @@ -371,7 +346,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_win32_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: @@ -383,9 +358,9 @@ stages: VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_ARTIFACTS: - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - vscode_cli_win32_x64_cli-unsigned + - not_yet_signed_vscode_cli_win32_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - vscode_cli_win32_arm64_cli-unsigned + - not_yet_signed_vscode_cli_win32_arm64_cli - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -484,7 +459,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true), ne(variables['VSCODE_PUBLISH'], 'false')) }}: @@ -538,7 +513,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} # TODO@joaomoreno: We don't ship ARM snaps for now @@ -633,7 +608,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_darwin_x64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_x64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: @@ -669,9 +644,9 @@ stages: VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} VSCODE_CLI_ARTIFACTS: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - vscode_cli_darwin_x64_cli-unsigned + - not_yet_signed_vscode_cli_darwin_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - vscode_cli_darwin_arm64_cli-unsigned + - not_yet_signed_vscode_cli_darwin_arm64_cli - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 @@ -687,7 +662,7 @@ stages: VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_darwin_arm64_cli-unsigned + VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_arm64_cli VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: diff --git a/build/azure-pipelines/cli/vcpkg-deps.yml b/build/azure-pipelines/vcpkg-install.yml similarity index 69% rename from build/azure-pipelines/cli/vcpkg-deps.yml rename to build/azure-pipelines/vcpkg-install.yml index 8c2928b0f70..d11d5c5d5c3 100644 --- a/build/azure-pipelines/cli/vcpkg-deps.yml +++ b/build/azure-pipelines/vcpkg-install.yml @@ -8,11 +8,14 @@ parameters: type: string steps: - - script: git clone https://github.com/microsoft/vcpkg.git $(Build.ArtifactStagingDirectory)/vcpkg - displayName: Checkout vcpkg - - - script: $(Build.ArtifactStagingDirectory)/vcpkg/bootstrap-vcpkg.bat + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { git clone https://github.com/microsoft/vcpkg.git $(Build.ArtifactStagingDirectory)/vcpkg } + exec { cd $(Build.ArtifactStagingDirectory)/vcpkg; git checkout 779ce74ef67d3e12d904da1b15f9ed5626d5f677 } + exec { $(Build.ArtifactStagingDirectory)/vcpkg/bootstrap-vcpkg.bat } + Write-Output "##vso[task.setvariable variable=VSCODE_DID_BOOTSTRAP_VCPKG]true" displayName: Bootstrap vcpkg + condition: not(eq(variables.VSCODE_DID_BOOTSTRAP_VCPKG, true)) - ${{ each target in parameters.targets }}: - task: Cache@2 diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml new file mode 100644 index 00000000000..f203f430942 --- /dev/null +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -0,0 +1,73 @@ +parameters: + - name: VSCODE_CLI_TARGETS + default: [] + type: object + - name: VSCODE_QUALITY + type: string + - name: VSCODE_CLI_DIR + type: string + - name: VSCODE_CLI_BINARY_NAME + type: string + - name: channel + type: string + default: stable + +steps: + - task: NodeTool@0 + inputs: + versionSpec: "16.x" + + - template: ../mixin-distro-win32.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/cli/prepare.js } + displayName: Prepare CLI build + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + + - template: ../cli/install-rust-win32.yml + parameters: + targets: ${{ parameters.VSCODE_CLI_TARGETS }} + + - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: + - template: ../vcpkg-install.yml + parameters: + targets: + - ${{ if eq(target.target, 'x86_64-pc-windows-msvc') }}: + - x64-windows-static-md + - ${{ if eq(target.target, 'aarch64-pc-windows-msvc') }}: + - arm64-windows-static-md + vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg + targetDirectory: $(Build.ArtifactStagingDirectory)/deps + + - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + displayName: Compile ${{ target.artifact }} + workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + env: + VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) + VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) + VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) + VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} + VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) + VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) + ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include + ${{ if eq(target, 'aarch64-pc-windows-msvc') }}: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include + + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip + artifact: ${{ target.artifact }} + displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index ca45ef2f864..db38e753738 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -31,6 +31,11 @@ steps: artifact: ${{ target }} path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip + destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} + - task: UseDotNet@2 displayName: "Use .NET" inputs: @@ -53,14 +58,21 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.exe" } + exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" } displayName: "Code sign" - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - powershell: | - $ASSET_ID = "${{ target }}".replace("-unsigned", ""); + $ASSET_ID = "${{ target }}".replace("not_yet_signed_", ""); echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + + - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 4a402d478f3..caec3dc49e2 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -186,14 +186,19 @@ steps: inputs: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} patterns: '**' - path: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin + path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI - - ${{ if ne(parameters.VSCODE_QUALITY, 'stable') }}: - - powershell: | - . build/azure-pipelines/win32/exec.ps1 + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + Expand-Archive -Path "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" + + if ("$(VSCODE_QUALITY)" -ne "stable") + { Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME).exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY).exe" - displayName: Move VS Code CLI + } + + displayName: Move VS Code CLI - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - powershell: | diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 94724bb410d..fb3a148f9a8 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -6,6 +6,7 @@ const gulp = require('gulp'); const path = require('path'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const es = require('event-stream'); @@ -18,7 +19,7 @@ const monacoapi = require('./lib/monaco-api'); const fs = require('fs'); const root = path.dirname(__dirname); -const sha1 = util.getVersion(root); +const sha1 = getVersion(root); const semver = require('./monaco/package.json').version; const headerVersion = semver + '(' + sha1 + ')'; diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 07033b9c960..c0b79bc0f9d 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -12,12 +12,13 @@ const nodeUtil = require('util'); const es = require('event-stream'); const filter = require('gulp-filter'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const watcher = require('./lib/watch'); const createReporter = require('./lib/reporter').createReporter; const glob = require('glob'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const plumber = require('gulp-plumber'); const ext = require('./lib/extensions'); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 980f647c854..7475e04d6e5 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -9,6 +9,7 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const product = require('../product.json'); @@ -30,7 +31,7 @@ const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileCont const cp = require('child_process'); const REPO_ROOT = path.dirname(__dirname); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const BUILD_ROOT = path.dirname(REPO_ROOT); const REMOTE_FOLDER = path.join(REPO_ROOT, 'remote'); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 6947d1ee1ed..b6d3523d8b5 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -18,11 +18,12 @@ const replace = require('gulp-replace'); const filter = require('gulp-filter'); const _ = require('underscore'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const buildfile = require('../src/buildfile'); const optimize = require('./lib/optimize'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const packageJson = require('../package.json'); const product = require('../product.json'); const crypto = require('crypto'); diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 4a25ca5ab04..cdc887013d8 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -12,6 +12,7 @@ const shell = require('gulp-shell'); const es = require('event-stream'); const vfs = require('vinyl-fs'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const packageJson = require('../package.json'); const product = require('../product.json'); @@ -20,7 +21,7 @@ const sysrootInstaller = require('./linux/debian/install-sysroot'); const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps; const path = require('path'); const root = path.dirname(__dirname); -const commit = util.getVersion(root); +const commit = getVersion(root); const linuxPackageRevision = Math.floor(new Date().getTime() / 1000); diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index c5b09393728..115f3ce499f 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -9,6 +9,7 @@ const gulp = require('gulp'); const path = require('path'); const es = require('event-stream'); const util = require('./lib/util'); +const { getVersion } = require('./lib/getVersion'); const task = require('./lib/task'); const optimize = require('./lib/optimize'); const product = require('../product.json'); @@ -26,7 +27,7 @@ const REPO_ROOT = path.dirname(__dirname); const BUILD_ROOT = path.dirname(REPO_ROOT); const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); -const commit = util.getVersion(REPO_ROOT); +const commit = getVersion(REPO_ROOT); const quality = product.quality; const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version; diff --git a/build/lib/electron.js b/build/lib/electron.js index 610d5bb6377..38f13d0ff08 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -11,12 +11,13 @@ const vfs = require("vinyl-fs"); const filter = require("gulp-filter"); const _ = require("underscore"); const util = require("./util"); +const getVersion_1 = require("./getVersion"); function isDocumentSuffix(str) { return str === 'document' || str === 'script' || str === 'file' || str === 'source code'; } const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); /** * Generate a `DarwinDocumentType` given a list of file extensions, an icon name, and an optional suffix or file type name. diff --git a/build/lib/electron.ts b/build/lib/electron.ts index c37a0f6eae3..247de01c563 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -9,6 +9,7 @@ import * as vfs from 'vinyl-fs'; import * as filter from 'gulp-filter'; import * as _ from 'underscore'; import * as util from './util'; +import { getVersion } from './getVersion'; type DarwinDocumentSuffix = 'document' | 'script' | 'file' | 'source code'; type DarwinDocumentType = { @@ -26,7 +27,7 @@ function isDocumentSuffix(str?: string): str is DarwinDocumentSuffix { const root = path.dirname(path.dirname(__dirname)); const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); -const commit = util.getVersion(root); +const commit = getVersion(root); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index f22d9749fb0..f69b3322018 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -26,9 +26,9 @@ const jsoncParser = require("jsonc-parser"); const dependencies_1 = require("./dependencies"); const _ = require("underscore"); const builtInExtensions_1 = require("./builtInExtensions"); -const util = require('./util'); +const getVersion_1 = require("./getVersion"); const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = (0, getVersion_1.getVersion)(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input) { const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 35447b284ad..36f29fcf3a1 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -26,9 +26,10 @@ import webpack = require('webpack'); import { getProductionDependencies } from './dependencies'; import _ = require('underscore'); import { getExtensionStream } from './builtInExtensions'; -const util = require('./util'); +import { getVersion } from './getVersion'; + const root = path.dirname(path.dirname(__dirname)); -const commit = util.getVersion(root); +const commit = getVersion(root); const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; function minifyExtensionResources(input: Stream): Stream { diff --git a/build/lib/util.js b/build/lib/util.js index fc62c844b6a..3eae325612a 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = exports.getVersion = void 0; +exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = void 0; const es = require("event-stream"); const _debounce = require("debounce"); const _filter = require("gulp-filter"); @@ -13,8 +13,6 @@ const path = require("path"); const fs = require("fs"); const _rimraf = require("rimraf"); const VinylFile = require("vinyl"); -var getVersion_1 = require("./getVersion"); -Object.defineProperty(exports, "getVersion", { enumerable: true, get: function () { return getVersion_1.getVersion; } }); const root = path.dirname(path.dirname(__dirname)); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { diff --git a/build/lib/util.ts b/build/lib/util.ts index 6fb799f2699..bbe6c52ef41 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -15,8 +15,6 @@ import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; -export { getVersion } from './getVersion'; - const root = path.dirname(path.dirname(__dirname)); export interface ICancellationToken { From 6a8a73318d786fe1089a62e37b9edc34228718ed Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 5 Oct 2022 13:01:50 -0700 Subject: [PATCH 339/599] fix run task bug (#162753) fix #162369 --- .../contrib/tasks/browser/abstractTaskService.ts | 15 +++++++++++++-- .../contrib/tasks/browser/taskQuickPick.ts | 1 - 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 2b90f232779..59288a8935d 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2800,7 +2800,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } const exactMatchTask = tasks.find(t => task && (t.getDefinition(true)?.configurationProperties?.identifier === task || t.configurationProperties?.identifier === task || t._label === task)); - const filteredTasks = tasks.filter(t => t._label.includes(task)); + const atLeastOneMatch = tasks.some(t => { + if (task) { + if (t._label.includes(task)) { + if (!type || t.type === type) { + return true; + } + } + } else if (type && t.type === type) { + return true; + } + return false; + }); if (exactMatchTask) { const id = exactMatchTask.configurationProperties?.identifier || exactMatchTask.getDefinition(true)?.configurationProperties?.identifier; if (id) { @@ -2812,7 +2823,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } } - } else if (filteredTasks?.length > 1) { + } else if (atLeastOneMatch) { return this._doRunTaskCommand(tasks, type, task); } else { return this._doRunTaskCommand(); diff --git a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts index dc5551150c3..2fedd4e2d70 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts @@ -273,7 +273,6 @@ export class TaskQuickPick extends Disposable { firstLevelTask = await this._doPickerFirstLevel(picker, taskQuickPickEntries); } do { - if (Types.isString(firstLevelTask)) { if (name) { await this._doPickerFirstLevel(picker, (await this.getTopLevelEntries(defaultEntry)).entries); From f73e76e6d99d6b07757549833aa1a28b3990b808 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 5 Oct 2022 17:29:55 -0400 Subject: [PATCH 340/599] Switch to registerAction2 (#162768) --- .../files/browser/fileActions.contribution.ts | 48 +++-- .../contrib/files/browser/fileActions.ts | 177 ++++++++++-------- .../welcomeOverlay/browser/welcomeOverlay.ts | 52 ++--- .../browser/editor/editorWalkThrough.ts | 29 +-- .../browser/walkThrough.contribution.ts | 9 +- 5 files changed, 168 insertions(+), 147 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index a2b85639809..5ebfe7c291c 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -4,13 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { ToggleAutoSaveAction, FocusFilesExplorer, GlobalCompareResourcesAction, ShowActiveFileInExplorer, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow, UPLOAD_COMMAND_ID, UPLOAD_LABEL } from 'vs/workbench/contrib/files/browser/fileActions'; +import { ToggleAutoSaveAction, FocusFilesExplorer, GlobalCompareResourcesAction, ShowActiveFileInExplorer, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow, UPLOAD_COMMAND_ID, UPLOAD_LABEL, fileCategory } from 'vs/workbench/contrib/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler'; -import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ILocalizedString } from 'vs/platform/action/common/action'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { openWindowCommand, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands'; import { COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, OpenEditorsDirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, OpenEditorsReadonlyEditorContext, OPEN_WITH_EXPLORER_COMMAND_ID, NEW_UNTITLED_FILE_COMMAND_ID, NEW_UNTITLED_FILE_LABEL, SAVE_ALL_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileConstants'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; @@ -22,7 +20,7 @@ import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOS import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { Schemas } from 'vs/base/common/network'; -import { DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/contextkeys'; +import { DirtyWorkingCopiesContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, WorkbenchStateContext, WorkspaceFolderCountContext, SidebarFocusContext, ActiveEditorCanRevertContext, ActiveEditorContext, ResourceContextKey, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/contextkeys'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -30,15 +28,13 @@ import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; import { Codicon } from 'vs/base/common/codicons'; // Contribute Global Actions -const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalCompareResourcesAction), 'File: Compare Active File With...', category.value, ActiveEditorContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusFilesExplorer), 'File: Focus on Files Explorer', category.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowActiveFileInExplorer), 'File: Reveal Active File in Explorer View', category.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CompareWithClipboardAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyC) }), 'File: Compare Active File with Clipboard', category.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleAutoSaveAction), 'File: Toggle Auto Save', category.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowOpenedFileInNewWindow, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyO) }), 'File: Open Active File in New Window', category.value, EmptyWorkspaceSupportContext); +registerAction2(GlobalCompareResourcesAction); +registerAction2(FocusFilesExplorer); +registerAction2(ShowActiveFileInExplorer); +registerAction2(CompareWithClipboardAction); +registerAction2(ToggleAutoSaveAction); +registerAction2(ShowOpenedFileInNewWindow); // Commands CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand); @@ -198,18 +194,18 @@ export function appendToCommandPalette(id: string, title: ILocalizedString, cate }); } -appendToCommandPalette(COPY_PATH_COMMAND_ID, { value: nls.localize('copyPathOfActive', "Copy Path of Active File"), original: 'Copy Path of Active File' }, category); -appendToCommandPalette(COPY_RELATIVE_PATH_COMMAND_ID, { value: nls.localize('copyRelativePathOfActive', "Copy Relative Path of Active File"), original: 'Copy Relative Path of Active File' }, category); -appendToCommandPalette(SAVE_FILE_COMMAND_ID, { value: SAVE_FILE_LABEL, original: 'Save' }, category); -appendToCommandPalette(SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, { value: SAVE_FILE_WITHOUT_FORMATTING_LABEL, original: 'Save without Formatting' }, category); -appendToCommandPalette(SAVE_ALL_IN_GROUP_COMMAND_ID, { value: nls.localize('saveAllInGroup', "Save All in Group"), original: 'Save All in Group' }, category); -appendToCommandPalette(SAVE_FILES_COMMAND_ID, { value: nls.localize('saveFiles', "Save All Files"), original: 'Save All Files' }, category); -appendToCommandPalette(REVERT_FILE_COMMAND_ID, { value: nls.localize('revert', "Revert File"), original: 'Revert File' }, category); -appendToCommandPalette(COMPARE_WITH_SAVED_COMMAND_ID, { value: nls.localize('compareActiveWithSaved', "Compare Active File with Saved"), original: 'Compare Active File with Saved' }, category); -appendToCommandPalette(SAVE_FILE_AS_COMMAND_ID, { value: SAVE_FILE_AS_LABEL, original: 'Save As...' }, category); -appendToCommandPalette(NEW_FILE_COMMAND_ID, { value: NEW_FILE_LABEL, original: 'New File' }, category, WorkspaceFolderCountContext.notEqualsTo('0')); -appendToCommandPalette(NEW_FOLDER_COMMAND_ID, { value: NEW_FOLDER_LABEL, original: 'New Folder' }, category, WorkspaceFolderCountContext.notEqualsTo('0')); -appendToCommandPalette(NEW_UNTITLED_FILE_COMMAND_ID, { value: NEW_UNTITLED_FILE_LABEL, original: 'New Untitled File' }, category); +appendToCommandPalette(COPY_PATH_COMMAND_ID, { value: nls.localize('copyPathOfActive', "Copy Path of Active File"), original: 'Copy Path of Active File' }, fileCategory); +appendToCommandPalette(COPY_RELATIVE_PATH_COMMAND_ID, { value: nls.localize('copyRelativePathOfActive', "Copy Relative Path of Active File"), original: 'Copy Relative Path of Active File' }, fileCategory); +appendToCommandPalette(SAVE_FILE_COMMAND_ID, { value: SAVE_FILE_LABEL, original: 'Save' }, fileCategory); +appendToCommandPalette(SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, { value: SAVE_FILE_WITHOUT_FORMATTING_LABEL, original: 'Save without Formatting' }, fileCategory); +appendToCommandPalette(SAVE_ALL_IN_GROUP_COMMAND_ID, { value: nls.localize('saveAllInGroup', "Save All in Group"), original: 'Save All in Group' }, fileCategory); +appendToCommandPalette(SAVE_FILES_COMMAND_ID, { value: nls.localize('saveFiles', "Save All Files"), original: 'Save All Files' }, fileCategory); +appendToCommandPalette(REVERT_FILE_COMMAND_ID, { value: nls.localize('revert', "Revert File"), original: 'Revert File' }, fileCategory); +appendToCommandPalette(COMPARE_WITH_SAVED_COMMAND_ID, { value: nls.localize('compareActiveWithSaved', "Compare Active File with Saved"), original: 'Compare Active File with Saved' }, fileCategory); +appendToCommandPalette(SAVE_FILE_AS_COMMAND_ID, { value: SAVE_FILE_AS_LABEL, original: 'Save As...' }, fileCategory); +appendToCommandPalette(NEW_FILE_COMMAND_ID, { value: NEW_FILE_LABEL, original: 'New File' }, fileCategory, WorkspaceFolderCountContext.notEqualsTo('0')); +appendToCommandPalette(NEW_FOLDER_COMMAND_ID, { value: NEW_FOLDER_LABEL, original: 'New Folder' }, fileCategory, WorkspaceFolderCountContext.notEqualsTo('0')); +appendToCommandPalette(NEW_UNTITLED_FILE_COMMAND_ID, { value: NEW_UNTITLED_FILE_LABEL, original: 'New Untitled File' }, fileCategory); // Menu registration - open editors diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index caf9e8e8967..b1f29827fbb 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -51,6 +51,10 @@ import { BrowserFileUpload, FileDownload } from 'vs/workbench/contrib/files/brow import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { Action2 } from 'vs/platform/actions/common/actions'; +import { ActiveEditorContext, EmptyWorkspaceSupportContext } from 'vs/workbench/common/contextkeys'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File..."); @@ -67,6 +71,7 @@ export const UPLOAD_COMMAND_ID = 'explorer.upload'; export const UPLOAD_LABEL = nls.localize('upload', "Upload..."); const CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete'; const MAX_UNDO_FILE_SIZE = 5000000; // 5mb +export const fileCategory = { value: nls.localize('filesCategory', "File"), original: 'File' }; function onError(notificationService: INotificationService, error: any): void { if (error.message === 'string') { @@ -451,30 +456,34 @@ async function askForOverwrite(fileService: IFileService, dialogService: IDialog } // Global Compare with -export class GlobalCompareResourcesAction extends Action { +export class GlobalCompareResourcesAction extends Action2 { static readonly ID = 'workbench.files.action.compareFileWith'; static readonly LABEL = nls.localize('globalCompareFile', "Compare Active File With..."); - constructor( - id: string, - label: string, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IEditorService private readonly editorService: IEditorService, - @ITextModelService private readonly textModelService: ITextModelService - ) { - super(id, label); + constructor() { + super({ + id: GlobalCompareResourcesAction.ID, + title: { value: GlobalCompareResourcesAction.LABEL, original: 'Compare Active File With...' }, + f1: true, + category: fileCategory, + precondition: ActiveEditorContext + }); } - override async run(): Promise { - const activeInput = this.editorService.activeEditor; + override async run(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const textModelService = accessor.get(ITextModelService); + const quickInputService = accessor.get(IQuickInputService); + + const activeInput = editorService.activeEditor; const activeResource = EditorResourceAccessor.getOriginalUri(activeInput); - if (activeResource && this.textModelService.canHandleResource(activeResource)) { - const picks = await this.quickInputService.quickAccess.pick('', { itemActivation: ItemActivation.SECOND }); + if (activeResource && textModelService.canHandleResource(activeResource)) { + const picks = await quickInputService.quickAccess.pick('', { itemActivation: ItemActivation.SECOND }); if (picks?.length === 1) { const resource = (picks[0] as unknown as { resource: unknown }).resource; - if (URI.isUri(resource) && this.textModelService.canHandleResource(resource)) { - this.editorService.openEditor({ + if (URI.isUri(resource) && textModelService.canHandleResource(resource)) { + editorService.openEditor({ original: { resource: activeResource }, modified: { resource: resource }, options: { pinned: true } @@ -485,20 +494,22 @@ export class GlobalCompareResourcesAction extends Action { } } -export class ToggleAutoSaveAction extends Action { +export class ToggleAutoSaveAction extends Action2 { static readonly ID = 'workbench.action.toggleAutoSave'; static readonly LABEL = nls.localize('toggleAutoSave', "Toggle Auto Save"); - constructor( - id: string, - label: string, - @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService - ) { - super(id, label); + constructor() { + super({ + id: ToggleAutoSaveAction.ID, + title: { value: ToggleAutoSaveAction.LABEL, original: 'Toggle Auto Save' }, + f1: true, + category: fileCategory + }); } - override run(): Promise { - return this.filesConfigurationService.toggleAutoSave(); + override run(accessor: ServicesAccessor): Promise { + const filesConfigurationService = accessor.get(IFilesConfigurationService); + return filesConfigurationService.toggleAutoSave(); } } @@ -573,69 +584,79 @@ export class CloseGroupAction extends Action { } } -export class FocusFilesExplorer extends Action { +export class FocusFilesExplorer extends Action2 { static readonly ID = 'workbench.files.action.focusFilesExplorer'; static readonly LABEL = nls.localize('focusFilesExplorer', "Focus on Files Explorer"); - constructor( - id: string, - label: string, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService - ) { - super(id, label); + constructor() { + super({ + id: FocusFilesExplorer.ID, + title: { value: FocusFilesExplorer.LABEL, original: 'Focus on Files Explorer' }, + f1: true, + category: fileCategory + }); } - override async run(): Promise { - await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true); + override async run(accessor: ServicesAccessor): Promise { + const paneCompositeService = accessor.get(IPaneCompositePartService); + await paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true); } } -export class ShowActiveFileInExplorer extends Action { +export class ShowActiveFileInExplorer extends Action2 { static readonly ID = 'workbench.files.action.showActiveFileInExplorer'; static readonly LABEL = nls.localize('showInExplorer', "Reveal Active File in Explorer View"); - constructor( - id: string, - label: string, - @IEditorService private readonly editorService: IEditorService, - @ICommandService private readonly commandService: ICommandService - ) { - super(id, label); + constructor() { + super({ + id: ShowActiveFileInExplorer.ID, + title: { value: ShowActiveFileInExplorer.LABEL, original: 'Reveal Active File in Explorer View' }, + f1: true, + category: fileCategory + }); } - override async run(): Promise { - const resource = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); + override async run(accessor: ServicesAccessor): Promise { + const commandService = accessor.get(ICommandService); + const editorService = accessor.get(IEditorService); + const resource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); if (resource) { - this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource); + commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource); } } } -export class ShowOpenedFileInNewWindow extends Action { +export class ShowOpenedFileInNewWindow extends Action2 { static readonly ID = 'workbench.action.files.showOpenedFileInNewWindow'; static readonly LABEL = nls.localize('openFileInNewWindow', "Open Active File in New Window"); constructor( - id: string, - label: string, - @IEditorService private readonly editorService: IEditorService, - @IHostService private readonly hostService: IHostService, - @IDialogService private readonly dialogService: IDialogService, - @IFileService private readonly fileService: IFileService ) { - super(id, label); + super({ + id: ShowOpenedFileInNewWindow.ID, + title: { value: ShowOpenedFileInNewWindow.LABEL, original: 'Open Active File in New Window' }, + f1: true, + category: fileCategory, + keybinding: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyO), weight: KeybindingWeight.WorkbenchContrib }, + precondition: EmptyWorkspaceSupportContext + }); } - override async run(): Promise { - const fileResource = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); + override async run(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const hostService = accessor.get(IHostService); + const dialogService = accessor.get(IDialogService); + const fileService = accessor.get(IFileService); + + const fileResource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); if (fileResource) { - if (this.fileService.hasProvider(fileResource)) { - this.hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true }); + if (fileService.hasProvider(fileResource)) { + hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true }); } else { - this.dialogService.show(Severity.Error, nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); + dialogService.show(Severity.Error, nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); } } } @@ -718,7 +739,7 @@ function getWellFormedFileName(filename: string): string { return filename; } -export class CompareWithClipboardAction extends Action { +export class CompareWithClipboardAction extends Action2 { static readonly ID = 'workbench.files.action.compareWithClipboard'; static readonly LABEL = nls.localize('compareWithClipboard', "Compare Active File with Clipboard"); @@ -726,32 +747,34 @@ export class CompareWithClipboardAction extends Action { private registrationDisposal: IDisposable | undefined; private static SCHEME_COUNTER = 0; - constructor( - id: string, - label: string, - @IEditorService private readonly editorService: IEditorService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @ITextModelService private readonly textModelService: ITextModelService, - @IFileService private readonly fileService: IFileService - ) { - super(id, label); - - this.enabled = true; + constructor() { + super({ + id: CompareWithClipboardAction.ID, + title: { value: CompareWithClipboardAction.LABEL, original: 'Compare Active File with Clipboard' }, + f1: true, + category: fileCategory, + keybinding: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyC), weight: KeybindingWeight.WorkbenchContrib } + }); } - override async run(): Promise { - const resource = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); + override async run(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const instantiationService = accessor.get(IInstantiationService); + const textModelService = accessor.get(ITextModelService); + const fileService = accessor.get(IFileService); + + const resource = EditorResourceAccessor.getOriginalUri(editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }); const scheme = `clipboardCompare${CompareWithClipboardAction.SCHEME_COUNTER++}`; - if (resource && (this.fileService.hasProvider(resource) || resource.scheme === Schemas.untitled)) { + if (resource && (fileService.hasProvider(resource) || resource.scheme === Schemas.untitled)) { if (!this.registrationDisposal) { - const provider = this.instantiationService.createInstance(ClipboardContentProvider); - this.registrationDisposal = this.textModelService.registerTextModelContentProvider(scheme, provider); + const provider = instantiationService.createInstance(ClipboardContentProvider); + this.registrationDisposal = textModelService.registerTextModelContentProvider(scheme, provider); } const name = resources.basename(resource); const editorLabel = nls.localize('clipboardComparisonLabel', "Clipboard ↔ {0}", name); - await this.editorService.openEditor({ + await editorService.openEditor({ original: { resource: resource.with({ scheme }) }, modified: { resource: resource }, label: editorLabel, @@ -763,9 +786,7 @@ export class CompareWithClipboardAction extends Action { } } - override dispose(): void { - super.dispose(); - + dispose(): void { dispose(this.registrationDisposal); this.registrationDisposal = undefined; } diff --git a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts index 5ad26e2f482..7bdc7f207c4 100644 --- a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts @@ -5,25 +5,23 @@ import 'vs/css!./media/welcomeOverlay'; import * as dom from 'vs/base/browser/dom'; -import { Registry } from 'vs/platform/registry/common/platform'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ShowAllCommandsAction } from 'vs/workbench/contrib/quickaccess/browser/commandsQuickAccess'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { localize } from 'vs/nls'; -import { Action } from 'vs/base/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { Disposable } from 'vs/base/common/lifecycle'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { textPreformatForeground, foreground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color'; import { Codicon } from 'vs/base/common/codicons'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; const $ = dom.$; @@ -110,38 +108,49 @@ const OVERLAY_VISIBLE = new RawContextKey('interfaceOverviewVisible', f let welcomeOverlay: WelcomeOverlay; -export class WelcomeOverlayAction extends Action { +export class WelcomeOverlayAction extends Action2 { public static readonly ID = 'workbench.action.showInterfaceOverview'; public static readonly LABEL = localize('welcomeOverlay', "User Interface Overview"); constructor( - id: string, - label: string, - @IInstantiationService private readonly instantiationService: IInstantiationService ) { - super(id, label); + super({ + id: WelcomeOverlayAction.ID, + title: WelcomeOverlayAction.LABEL, + category: Categories.Help, + f1: true + }); } - public override run(): Promise { + public override run(accessor: ServicesAccessor): Promise { + const instantiationService = accessor.get(IInstantiationService); if (!welcomeOverlay) { - welcomeOverlay = this.instantiationService.createInstance(WelcomeOverlay); + welcomeOverlay = instantiationService.createInstance(WelcomeOverlay); } welcomeOverlay.show(); return Promise.resolve(); } } -export class HideWelcomeOverlayAction extends Action { +export class HideWelcomeOverlayAction extends Action2 { public static readonly ID = 'workbench.action.hideInterfaceOverview'; public static readonly LABEL = localize('hideWelcomeOverlay', "Hide Interface Overview"); - constructor( - id: string, - label: string - ) { - super(id, label); + constructor() { + super({ + id: HideWelcomeOverlayAction.ID, + title: HideWelcomeOverlayAction.LABEL, + category: Categories.Help, + f1: true, + keybinding: { + primary: KeyCode.Escape, + when: OVERLAY_VISIBLE, + weight: KeybindingWeight.WorkbenchContrib + }, + precondition: OVERLAY_VISIBLE + }); } public override run(): Promise { @@ -257,11 +266,8 @@ class WelcomeOverlay extends Disposable { } } -Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(SyncActionDescriptor.from(WelcomeOverlayAction), 'Help: User Interface Overview', Categories.Help.value); - -Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction(SyncActionDescriptor.from(HideWelcomeOverlayAction, { primary: KeyCode.Escape }, OVERLAY_VISIBLE), 'Help: Hide Interface Overview', Categories.Help.value); +registerAction2(WelcomeOverlayAction); +registerAction2(HideWelcomeOverlayAction); // theming diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts index 51b2b120941..8eaf3e7322b 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts @@ -6,12 +6,13 @@ import 'vs/workbench/contrib/welcomeWalkthrough/browser/editor/vs_code_editor_walkthrough'; import { localize } from 'vs/nls'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { Action } from 'vs/base/common/actions'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { WalkThroughInput, WalkThroughInputOptions } from 'vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughInput'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { IEditorSerializer } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { Action2 } from 'vs/platform/actions/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; const typeId = 'workbench.editors.walkThroughInput'; const inputOptions: WalkThroughInputOptions = { @@ -25,24 +26,26 @@ const inputOptions: WalkThroughInputOptions = { telemetryFrom: 'walkThrough' }; -export class EditorWalkThroughAction extends Action { +export class EditorWalkThroughAction extends Action2 { public static readonly ID = 'workbench.action.showInteractivePlayground'; public static readonly LABEL = localize('editorWalkThrough', "Interactive Editor Playground"); - constructor( - id: string, - label: string, - @IEditorService private readonly editorService: IEditorService, - @IInstantiationService private readonly instantiationService: IInstantiationService - ) { - super(id, label); + constructor() { + super({ + id: EditorWalkThroughAction.ID, + title: EditorWalkThroughAction.LABEL, + category: Categories.Help, + f1: true + }); } - public override run(): Promise { - const input = this.instantiationService.createInstance(WalkThroughInput, inputOptions); + public override run(serviceAccessor: ServicesAccessor): Promise { + const editorService = serviceAccessor.get(IEditorService); + const instantiationService = serviceAccessor.get(IInstantiationService); + const input = instantiationService.createInstance(WalkThroughInput, inputOptions); // TODO @lramos15 adopt the resolver here - return this.editorService.openEditor(input, { pinned: true }) + return editorService.openEditor(input, { pinned: true }) .then(() => void (0)); } } diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts index be550f72b66..39957579811 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThrough.contribution.ts @@ -12,9 +12,7 @@ import { EditorWalkThroughAction, EditorWalkThroughInputSerializer } from 'vs/wo import { Registry } from 'vs/platform/registry/common/platform'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -28,10 +26,7 @@ Registry.as(EditorExtensions.EditorPane) ), [new SyncDescriptor(WalkThroughInput)]); -Registry.as(Extensions.WorkbenchActions) - .registerWorkbenchAction( - SyncActionDescriptor.from(EditorWalkThroughAction), - 'Help: Interactive Editor Playground', Categories.Help.value); +registerAction2(EditorWalkThroughAction); Registry.as(EditorExtensions.EditorFactory).registerEditorSerializer(EditorWalkThroughInputSerializer.ID, EditorWalkThroughInputSerializer); From cbdd0959d04cdb9e0f8bc049ca995680e2f08f5d Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 5 Oct 2022 14:44:22 -0700 Subject: [PATCH 341/599] return `false` if `workspaceFolder` is undefined (#162746) --- .../workbench/contrib/tasks/browser/abstractTaskService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 59288a8935d..8433840a94f 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -327,7 +327,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._register(this.onDidStateChange(e => { if ((this._willRestart || e.exitReason === TerminalExitReason.User) && e.taskId) { this.removePersistentTask(e.taskId); - } else if (e.kind === TaskEventKind.Start && e.__task) { + } else if (e.kind === TaskEventKind.Start && e.__task && e.__task.getWorkspaceFolder()) { this._setPersistentTask(e.__task); } })); @@ -2354,8 +2354,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return { workspaceFolder, set: undefined, configurations: undefined, hasErrors: false }; } - private async _computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise { - if (!config) { + private async _computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder | undefined, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise { + if (!config || !workspaceFolder) { return false; } const taskSystemInfo: ITaskSystemInfo | undefined = workspaceFolder ? this._getTaskSystemInfo(workspaceFolder.uri.scheme) : undefined; From 4bd2f94ec1ece243eb5ef71bf5c91b507029c8e0 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 5 Oct 2022 15:08:20 -0700 Subject: [PATCH 342/599] Remove unused "Extensions" output channel (#162774) Fix #162458 --- .../contrib/debug/node/debugAdapter.ts | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index b4f6c7e4daf..4275f9e0a89 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -3,19 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Promises } from 'vs/base/node/pfs'; import * as cp from 'child_process'; -import * as stream from 'stream'; -import * as nls from 'vs/nls'; import * as net from 'net'; -import * as path from 'vs/base/common/path'; -import * as strings from 'vs/base/common/strings'; +import * as stream from 'stream'; import * as objects from 'vs/base/common/objects'; +import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; -import { ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IOutputService } from 'vs/workbench/services/output/common/output'; -import { IDebugAdapterExecutable, IDebuggerContribution, IPlatformSpecificAdapterContribution, IDebugAdapterServer, IDebugAdapterNamedPipeServer } from 'vs/workbench/contrib/debug/common/debug'; +import * as strings from 'vs/base/common/strings'; +import { Promises } from 'vs/base/node/pfs'; +import * as nls from 'vs/nls'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IDebugAdapterExecutable, IDebugAdapterNamedPipeServer, IDebugAdapterServer, IDebuggerContribution, IPlatformSpecificAdapterContribution } from 'vs/workbench/contrib/debug/common/debug'; import { AbstractDebugAdapter } from '../common/abstractDebugAdapter'; /** @@ -169,7 +167,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { private serverProcess: cp.ChildProcess | undefined; - constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private readonly outputService?: IOutputService) { + constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string) { super(); } @@ -251,19 +249,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { this._onError.fire(error); }); - const outputService = this.outputService; - if (outputService) { - const sanitize = (s: string) => s.toString().replace(/\r?\n$/mg, ''); - // this.serverProcess.stdout.on('data', (data: string) => { - // console.log('%c' + sanitize(data), 'background: #ddd; font-style: italic;'); - // }); - this.serverProcess.stderr!.on('data', (data: string) => { - const channel = outputService.getChannel(ExtensionsChannelId); - channel?.append(sanitize(data)); - }); - } else { - this.serverProcess.stderr!.resume(); - } + this.serverProcess.stderr!.resume(); // finally connect to the DA this.connect(this.serverProcess.stdout!, this.serverProcess.stdin!); From d47ae7a2e789298305493b921ee6eb8b405b51b5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 5 Oct 2022 15:08:51 -0700 Subject: [PATCH 343/599] Pick up latest markdown language service version (#162777) Fixes #162776 Fixes #162775 --- .../markdown-language-features/package.json | 23 +++++++++++++++++++ .../package.nls.json | 2 ++ .../server/README.md | 4 ++++ .../server/package.json | 2 +- .../server/src/configuration.ts | 8 ++++++- .../src/languageFeatures/diagnostics.ts | 7 +++++- .../server/src/server.ts | 9 ++++++++ .../server/yarn.lock | 8 +++---- 8 files changed, 56 insertions(+), 7 deletions(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 059fe5d1a61..763f946d9a3 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -493,6 +493,29 @@ "type": "string" } }, + "markdown.validate.unusedLinkDefinitions.enabled": { + "type": "string", + "scope": "resource", + "markdownDescription": "%configuration.markdown.validate.unusedLinkDefinitions.description%", + "default": "hint", + "enum": [ + "ignore", + "hint", + "warning", + "error" + ] + }, + "markdown.validate.duplicateLinkDefinitions.enabled": { + "type": "string", + "scope": "resource", + "markdownDescription": "%configuration.markdown.validate.duplicateLinkDefinitions.description%", + "default": "warning", + "enum": [ + "ignore", + "warning", + "error" + ] + }, "markdown.experimental.updateLinksOnFileMove.enabled": { "type": "string", "enum": [ diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 3aae783308d..b1d65edabe2 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -37,6 +37,8 @@ "configuration.markdown.validate.fileLinks.enabled.description": "Validate links to other files in Markdown files, e.g. `[link](/path/to/file.md)`. This checks that the target files exists. Requires enabling `#markdown.validate.enabled#`.", "configuration.markdown.validate.fileLinks.markdownFragmentLinks.description": "Validate the fragment part of links to headers in other files in Markdown files, e.g. `[link](/path/to/file.md#header)`. Inherits the setting value from `#markdown.validate.fragmentLinks.enabled#` by default.", "configuration.markdown.validate.ignoredLinks.description": "Configure links that should not be validated. For example adding `/about` would not validate the link `[about](/about)`, while the glob `/assets/**/*.svg` would let you skip validation for any link to `.svg` files under the `assets` directory.", + "configuration.markdown.validate.unusedLinkDefinitions.description": "Validate link definitions that are unused in the current file.", + "configuration.markdown.validate.duplicateLinkDefinitions.description": "Validate duplicated definitions in the current file.", "configuration.markdown.experimental.updateLinksOnFileMove.enabled": "Try to update links in Markdown files when a file is renamed/moved in the workspace. Use `#markdown.experimental.updateLinksOnFileMove.externalFileGlobs#` to configure which files trigger link updates.", "configuration.markdown.experimental.updateLinksOnFileMove.enabled.prompt": "Prompt on each file move.", "configuration.markdown.experimental.updateLinksOnFileMove.enabled.always": "Always update links automatically.", diff --git a/extensions/markdown-language-features/server/README.md b/extensions/markdown-language-features/server/README.md index a4935ad3ebb..6b6e0b0c81c 100644 --- a/extensions/markdown-language-features/server/README.md +++ b/extensions/markdown-language-features/server/README.md @@ -66,6 +66,10 @@ The server supports the following settings: - `enabled` — Enable/disable validation of links to file in the workspace. - `markdownFragmentLinks` — Enable/disable validation of links to headers in other Markdown files. Use `inherit` to inherit the `fragmentLinks` setting. - `ignoredLinks` — Array of glob patterns for files that should not be validated. + - `unusedLinkDefinitions` + - `enabled` — Enable/disable validation of unused link definitions. + - `duplicateLinkDefinitions` + - `enabled` — Enable/disable validation of duplicated link definitions. ### Custom requests diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json index 2f6f3a5981a..dd812e21af6 100644 --- a/extensions/markdown-language-features/server/package.json +++ b/extensions/markdown-language-features/server/package.json @@ -13,7 +13,7 @@ "vscode-languageserver": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.5", "vscode-languageserver-types": "^3.17.1", - "vscode-markdown-languageservice": "^0.1.0", + "vscode-markdown-languageservice": "^0.2.0-alpha.1", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, diff --git a/extensions/markdown-language-features/server/src/configuration.ts b/extensions/markdown-language-features/server/src/configuration.ts index 8bd3fcc730b..b521e478605 100644 --- a/extensions/markdown-language-features/server/src/configuration.ts +++ b/extensions/markdown-language-features/server/src/configuration.ts @@ -6,7 +6,7 @@ import { Connection, Emitter } from 'vscode-languageserver'; import { Disposable } from './util/dispose'; -export type ValidateEnabled = 'ignore' | 'warning' | 'error'; +export type ValidateEnabled = 'ignore' | 'warning' | 'error' | 'hint'; interface Settings { readonly markdown: { @@ -29,6 +29,12 @@ interface Settings { readonly markdownFragmentLinks: ValidateEnabled | 'inherit'; }; readonly ignoredLinks: readonly string[]; + readonly unusedLinkDefinitions: { + readonly enabled: ValidateEnabled; + }; + readonly duplicateLinkDefinitions: { + readonly enabled: ValidateEnabled; + }; }; }; } diff --git a/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts index a7b43877f5d..0f7e6954dbc 100644 --- a/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts +++ b/extensions/markdown-language-features/server/src/languageFeatures/diagnostics.ts @@ -15,6 +15,8 @@ const defaultDiagnosticOptions: md.DiagnosticOptions = { validateReferences: md.DiagnosticLevel.ignore, validateFragmentLinks: md.DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: md.DiagnosticLevel.ignore, + validateUnusedLinkDefinitions: md.DiagnosticLevel.ignore, + validateDuplicateLinkDefinitions: md.DiagnosticLevel.ignore, ignoreLinks: [], }; @@ -23,6 +25,7 @@ function convertDiagnosticLevel(enabled: ValidateEnabled): md.DiagnosticLevel | case 'error': return md.DiagnosticLevel.error; case 'warning': return md.DiagnosticLevel.warning; case 'ignore': return md.DiagnosticLevel.ignore; + case 'hint': return md.DiagnosticLevel.hint; default: return md.DiagnosticLevel.ignore; } } @@ -37,8 +40,10 @@ function getDiagnosticsOptions(config: ConfigurationManager): md.DiagnosticOptio return { validateFileLinks: convertDiagnosticLevel(settings.markdown.validate.fileLinks.enabled), validateReferences: convertDiagnosticLevel(settings.markdown.validate.referenceLinks.enabled), - validateFragmentLinks, + validateFragmentLinks: convertDiagnosticLevel(settings.markdown.validate.fragmentLinks.enabled), validateMarkdownFileLinkFragments: settings.markdown.validate.fileLinks.markdownFragmentLinks === 'inherit' ? validateFragmentLinks : convertDiagnosticLevel(settings.markdown.validate.fileLinks.markdownFragmentLinks), + validateUnusedLinkDefinitions: convertDiagnosticLevel(settings.markdown.validate.unusedLinkDefinitions.enabled), + validateDuplicateLinkDefinitions: convertDiagnosticLevel(settings.markdown.validate.duplicateLinkDefinitions.enabled), ignoreLinks: settings.markdown.validate.ignoredLinks, }; } diff --git a/extensions/markdown-language-features/server/src/server.ts b/extensions/markdown-language-features/server/src/server.ts index 95a088b439b..c17a32a63ee 100644 --- a/extensions/markdown-language-features/server/src/server.ts +++ b/extensions/markdown-language-features/server/src/server.ts @@ -93,6 +93,7 @@ export async function startServer(connection: Connection, serverConfig: { completionProvider: { triggerCharacters: ['.', '/', '#'] }, definitionProvider: true, documentLinkProvider: { resolveProvider: true }, + documentHighlightProvider: false, // TODO: Disabling for now documentSymbolProvider: true, foldingRangeProvider: true, referencesProvider: true, @@ -232,6 +233,14 @@ export async function startServer(connection: Connection, serverConfig: { return codeAction; }); + connection.onDocumentHighlight(async (params, token) => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return undefined; + } + return mdLs!.getDocumentHighlights(document, params.position, token); + }); + connection.onRequest(protocol.getReferencesToFileInWorkspace, (async (params: { uri: string }, token: CancellationToken) => { return mdLs!.getFileReferences(URI.parse(params.uri), token); })); diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index c99899494bc..df3fe7b2b5b 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -42,10 +42,10 @@ vscode-languageserver@^8.0.2: dependencies: vscode-languageserver-protocol "3.17.2" -vscode-markdown-languageservice@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.1.0.tgz#6027e15094da005b66318e8edb099644c7557b25" - integrity sha512-fMUFjM7AZo7Mto7NS8PEDNJ5IpJQUvVemhlnLs3AP2jC59pOHwpeciuTEINF0ymjWQwu94OIbilBn7OB/Z1sUg== +vscode-markdown-languageservice@^0.2.0-alpha.1: + version "0.2.0-alpha.1" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.2.0-alpha.1.tgz#ab4b75ef4584551b8531b7b9cee3f9c64d5bd344" + integrity sha512-doJBc1Jx5xGEjsagNz3hOkDzAWDyTiJ7mBYsxkgDz0/49rCxjNdXBlfMioeoSSMVmyVUvY1hlAX8Q/I9jyUc+Q== dependencies: picomatch "^2.3.1" vscode-languageserver-textdocument "^1.0.5" From 99d4474e92a8bb133ebf38d19ecde93e81dc9005 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 5 Oct 2022 15:09:52 -0700 Subject: [PATCH 344/599] Re #162713. Keyboard Layout move to registerAction2 (#162780) --- .../browser/keyboardLayoutPicker.ts | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts index f5dff19e6d8..fdbef87f153 100644 --- a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts +++ b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts @@ -10,18 +10,17 @@ import { parseKeyboardLayoutDescription, areKeyboardLayoutsEqual, getKeyboardLay import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KEYBOARD_LAYOUT_OPEN_PICKER } from 'vs/workbench/contrib/preferences/common/preferences'; -import { Action } from 'vs/base/common/actions'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { QuickPickInput, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { VSBuffer } from 'vs/base/common/buffer'; import { IEditorPane } from 'vs/workbench/common/editor'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export class KeyboardLayoutPickerContribution extends Disposable implements IWorkbenchContribution { private readonly pickerElement = this._register(new MutableDisposable()); @@ -93,35 +92,34 @@ interface IUnknownLayout { layout?: string; } -export class KeyboardLayoutPickerAction extends Action { - static readonly ID = KEYBOARD_LAYOUT_OPEN_PICKER; - static readonly LABEL = nls.localize('keyboard.chooseLayout', "Change Keyboard Layout"); +const DEFAULT_CONTENT: string = [ + `// ${nls.localize('displayLanguage', 'Defines the keyboard layout used in VS Code in the browser environment.')}`, + `// ${nls.localize('doc', 'Open VS Code and run "Developer: Inspect Key Mappings (JSON)" from Command Palette.')}`, + ``, + `// Once you have the keyboard layout info, please paste it below.`, + '\n' +].join('\n'); - private static DEFAULT_CONTENT: string = [ - `// ${nls.localize('displayLanguage', 'Defines the keyboard layout used in VS Code in the browser environment.')}`, - `// ${nls.localize('doc', 'Open VS Code and run "Developer: Inspect Key Mappings (JSON)" from Command Palette.')}`, - ``, - `// Once you have the keyboard layout info, please paste it below.`, - '\n' - ].join('\n'); - - constructor( - actionId: string, - actionLabel: string, - @IFileService private readonly fileService: IFileService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IKeyboardLayoutService private readonly keyboardLayoutService: IKeyboardLayoutService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IEditorService private readonly editorService: IEditorService - ) { - super(actionId, actionLabel, undefined, true); +registerAction2(class extends Action2 { + constructor() { + super({ + id: KEYBOARD_LAYOUT_OPEN_PICKER, + title: { value: nls.localize('keyboard.chooseLayout', "Change Keyboard Layout"), original: 'Change Keyboard Layout' }, + f1: true + }); } - override async run(): Promise { - const layouts = this.keyboardLayoutService.getAllKeyboardLayouts(); - const currentLayout = this.keyboardLayoutService.getCurrentKeyboardLayout(); - const layoutConfig = this.configurationService.getValue('keyboard.layout'); + async run(accessor: ServicesAccessor): Promise { + const keyboardLayoutService = accessor.get(IKeyboardLayoutService); + const quickInputService = accessor.get(IQuickInputService); + const configurationService = accessor.get(IConfigurationService); + const environmentService = accessor.get(IEnvironmentService); + const editorService = accessor.get(IEditorService); + const fileService = accessor.get(IFileService); + + const layouts = keyboardLayoutService.getAllKeyboardLayouts(); + const currentLayout = keyboardLayoutService.getCurrentKeyboardLayout(); + const layoutConfig = configurationService.getValue('keyboard.layout'); const isAutoDetect = layoutConfig === 'autodetect'; const picks: QuickPickInput[] = layouts.map(layout => { @@ -156,27 +154,27 @@ export class KeyboardLayoutPickerAction extends Action { picks.unshift(autoDetectMode); - const pick = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickKeyboardLayout', "Select Keyboard Layout"), matchOnDescription: true }); + const pick = await quickInputService.pick(picks, { placeHolder: nls.localize('pickKeyboardLayout', "Select Keyboard Layout"), matchOnDescription: true }); if (!pick) { return; } if (pick === autoDetectMode) { // set keymap service to auto mode - this.configurationService.updateValue('keyboard.layout', 'autodetect'); + configurationService.updateValue('keyboard.layout', 'autodetect'); return; } if (pick === configureKeyboardLayout) { - const file = this.environmentService.keyboardLayoutResource; + const file = environmentService.keyboardLayoutResource; - await this.fileService.stat(file).then(undefined, () => { - return this.fileService.createFile(file, VSBuffer.fromString(KeyboardLayoutPickerAction.DEFAULT_CONTENT)); + await fileService.stat(file).then(undefined, () => { + return fileService.createFile(file, VSBuffer.fromString(DEFAULT_CONTENT)); }).then((stat): Promise | undefined => { if (!stat) { return undefined; } - return this.editorService.openEditor({ + return editorService.openEditor({ resource: stat.resource, languageId: 'jsonc', options: { pinned: true } @@ -188,9 +186,6 @@ export class KeyboardLayoutPickerAction extends Action { return Promise.resolve(); } - this.configurationService.updateValue('keyboard.layout', getKeyboardLayoutId((pick).layout)); + configurationService.updateValue('keyboard.layout', getKeyboardLayoutId((pick).layout)); } -} - -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(KeyboardLayoutPickerAction, {}), 'Preferences: Change Keyboard Layout', nls.localize('preferences', "Preferences")); +}); From 4991cf2112ccc2af9f024ac8b3d333e31a2c72aa Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 5 Oct 2022 15:25:52 -0700 Subject: [PATCH 345/599] Remove console.log (#162784) --- extensions/markdown-language-features/preview-src/scroll-sync.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/markdown-language-features/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts index d936e42dc06..e9fc98a269b 100644 --- a/extensions/markdown-language-features/preview-src/scroll-sync.ts +++ b/extensions/markdown-language-features/preview-src/scroll-sync.ts @@ -36,7 +36,6 @@ const getCodeLineElements = (() => { cachedElements.push({ element: element as HTMLElement, line }); } } - console.log(cachedElements); } return cachedElements; }; From d81ba3a6f27a4f0fe3096a3520afc8a7e1f34985 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Wed, 5 Oct 2022 16:20:41 -0700 Subject: [PATCH 346/599] Minor quick pick style updates (#162789) --- src/vs/base/parts/quickinput/browser/media/quickInput.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/media/quickInput.css b/src/vs/base/parts/quickinput/browser/media/quickInput.css index e3357d75fe8..891ab4f1e1f 100644 --- a/src/vs/base/parts/quickinput/browser/media/quickInput.css +++ b/src/vs/base/parts/quickinput/browser/media/quickInput.css @@ -10,6 +10,7 @@ left: 50%; margin-left: -300px; -webkit-app-region: no-drag; + border-radius: 4px; } .quick-input-titlebar { @@ -56,7 +57,7 @@ .quick-input-header { display: flex; - padding: 6px 6px 0px 6px; + padding: 8px 8px 0px 8px; margin-bottom: -2px; } @@ -149,7 +150,7 @@ .quick-input-list { line-height: 22px; - margin-top: 6px; + margin-top: 8px; padding: 0px 1px 1px 1px; } From 3b63023489329145b42bc4ffc944f2ab0c04117e Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 5 Oct 2022 16:28:10 -0700 Subject: [PATCH 347/599] Always show kernel picker. (#162790) --- .../browser/contrib/editorStatusBar/editorStatusBar.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts index d3d04163713..78a1fba167d 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts @@ -31,7 +31,7 @@ import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/note import { selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_KERNEL_SOURCE_COUNT, NOTEBOOK_MISSING_KERNEL_EXTENSION } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; +import { NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { INotebookKernel, INotebookKernelService, ISourceAction } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -52,17 +52,13 @@ registerAction2(class extends Action2 { id: MenuId.EditorTitle, when: ContextKeyExpr.and( NOTEBOOK_IS_ACTIVE_EDITOR, - ContextKeyExpr.or(NOTEBOOK_KERNEL_COUNT.notEqualsTo(0), NOTEBOOK_KERNEL_SOURCE_COUNT.notEqualsTo(0), NOTEBOOK_MISSING_KERNEL_EXTENSION), ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) ), group: 'navigation', order: -10 }, { id: MenuId.NotebookToolbar, - when: ContextKeyExpr.and( - ContextKeyExpr.or(NOTEBOOK_KERNEL_COUNT.notEqualsTo(0), NOTEBOOK_KERNEL_SOURCE_COUNT.notEqualsTo(0), NOTEBOOK_MISSING_KERNEL_EXTENSION), - ContextKeyExpr.equals('config.notebook.globalToolbar', true) - ), + when: ContextKeyExpr.equals('config.notebook.globalToolbar', true), group: 'status', order: -10 }, { From ec5226a847e33475bb5bafe89a1915b414c32cc0 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 5 Oct 2022 23:56:16 -0700 Subject: [PATCH 348/599] Adopt MenuId.EditorContent in debug (#162797) For #158741 --- .../contrib/debug/browser/debugCommands.ts | 28 +++++++++++++------ .../debug/browser/debugEditorContribution.ts | 16 ----------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index f04f2889942..583c82929b7 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -12,7 +12,7 @@ import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_ import { Expression, Variable, Breakpoint, FunctionBreakpoint, DataBreakpoint, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -20,7 +20,7 @@ import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpo import { INotificationService } from 'vs/platform/notification/common/notification'; import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; -import { PanelFocusContext } from 'vs/workbench/common/contextkeys'; +import { ActiveEditorContext, PanelFocusContext, ResourceContextKey } from 'vs/workbench/common/contextkeys'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -33,6 +33,7 @@ import { saveAllBeforeDebugStart } from 'vs/workbench/contrib/debug/common/debug import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { showLoadedScriptMenu } from 'vs/workbench/contrib/debug/common/loadedScriptsPicker'; import { showDebugSessionMenu } from 'vs/workbench/contrib/debug/browser/debugSessionPicker'; +import { TEXT_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; export const ADD_CONFIGURATION_ID = 'debug.addConfiguration'; export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint'; @@ -915,12 +916,23 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: ADD_CONFIGURATION_ID, - weight: KeybindingWeight.WorkbenchContrib, - when: undefined, - primary: undefined, - handler: async (accessor, launchUri: string) => { +registerAction2(class AddConfigurationAction extends Action2 { + constructor() { + super({ + id: ADD_CONFIGURATION_ID, + title: nls.localize('addConfiguration', "Add Configuration..."), + category: DEBUG_COMMAND_CATEGORY, + f1: true, + menu: { + id: MenuId.EditorContent, + when: ContextKeyExpr.and( + ContextKeyExpr.regex(ResourceContextKey.Path.key, /\.vscode\/launch\.json$/), + ActiveEditorContext.isEqualTo(TEXT_FILE_EDITOR_ID)) + } + }); + } + + async run(accessor: ServicesAccessor, launchUri: string): Promise { const manager = accessor.get(IDebugService).getConfigurationManager(); const launch = manager.getLaunches().find(l => l.uri.toString() === launchUri) || manager.selectedConfiguration.launch; diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 48a002966c6..251241bb2d5 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -48,7 +48,6 @@ import { DomEmitter } from 'vs/base/browser/event'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce'; -const LAUNCH_JSON_REGEX = /\.vscode\/launch\.json$/; const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We want to limit ourselves for perf reasons const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped @@ -241,7 +240,6 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.hoverWidget = this.instantiationService.createInstance(DebugHoverWidget, this.editor); this.toDispose = []; this.registerListeners(); - this.updateConfigurationWidgetVisibility(); this.exceptionWidgetVisible = CONTEXT_EXCEPTION_WIDGET_VISIBLE.bindTo(contextKeyService); this.toggleExceptionWidget(); } @@ -280,7 +278,6 @@ export class DebugEditorContribution implements IDebugEditorContribution { } this.toggleExceptionWidget(); this.hideHoverWidget(); - this.updateConfigurationWidgetVisibility(); this._wordToLineNumbersMap = undefined; await this.updateInlineValueDecorations(stackFrame); })); @@ -524,19 +521,6 @@ export class DebugEditorContribution implements IDebugEditorContribution { } } - // configuration widget - private updateConfigurationWidgetVisibility(): void { - const model = this.editor.getModel(); - if (this.configurationWidget) { - this.configurationWidget.dispose(); - } - if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getOption(EditorOption.readOnly)) { - this.configurationWidget = this.instantiationService.createInstance(FloatingClickWidget, this.editor, nls.localize('addConfiguration', "Add Configuration..."), null); - this.configurationWidget.render(); - this.toDispose.push(this.configurationWidget.onClick(() => this.addLaunchConfiguration())); - } - } - async addLaunchConfiguration(): Promise { const model = this.editor.getModel(); if (!model) { From b7c45338adf30f5fad2f860dfb101cc39ca95809 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 5 Oct 2022 23:56:54 -0700 Subject: [PATCH 349/599] Debt from previous save dialog file filter fix (#162799) Fix #150928 --- .../dialogs/browser/abstractFileDialogService.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index fabbda76cb7..2282c22ec86 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -323,12 +323,16 @@ export abstract class AbstractFileDialogService implements IFileDialogService { const filter: IFilter = { name: languageName, extensions: distinct(extensions).slice(0, 10).map(e => trim(e, '.')) }; - if (!matchingFilter && extensions.includes(ext || PLAINTEXT_EXTENSION /* https://github.com/microsoft/vscode/issues/115860 */)) { + // https://github.com/microsoft/vscode/issues/115860 + const extOrPlaintext = ext || PLAINTEXT_EXTENSION; + if (!matchingFilter && extensions.includes(extOrPlaintext)) { matchingFilter = filter; - const trimmedExt = trim(ext || PLAINTEXT_EXTENSION, '.'); + // The selected extension must be in the set of extensions that are in the filter list that is sent to the save dialog. + // If it isn't, add it manually. https://github.com/microsoft/vscode/issues/147657 + const trimmedExt = trim(extOrPlaintext, '.'); if (!filter.extensions.includes(trimmedExt)) { - filter.extensions.push(trimmedExt); + filter.extensions.unshift(trimmedExt); } return null; // first matching filter will be added to the top From a71ef85de11ae41776ba46dd3387c2fff83cf1f2 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 6 Oct 2022 09:06:33 +0200 Subject: [PATCH 350/599] =?UTF-8?q?=F0=9F=92=84=20IWorkspaceTrustRequestSe?= =?UTF-8?q?rvice=20delayed=20insta=20(#162720)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 💄 IWorkspaceTrustRequestService delayed insta * Fix compilation error --- src/vs/workbench/services/workspaces/common/workspaceTrust.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 2e249f7aa57..d9cdd1ba7ac 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -10,7 +10,7 @@ import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { IPath } from 'vs/platform/window/common/window'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { isVirtualResource } from 'vs/platform/workspace/common/virtualWorkspace'; @@ -887,4 +887,4 @@ class WorkspaceTrustMemento { } } -registerSingleton(IWorkspaceTrustRequestService, WorkspaceTrustRequestService, false); +registerSingleton(IWorkspaceTrustRequestService, WorkspaceTrustRequestService, InstantiationType.Delayed); From bfb1a738d1af124c9552118dfdf82e18b2587177 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 00:50:10 -0700 Subject: [PATCH 351/599] Fix markdown open preview opening duplicate preview (#162793) This fixes the markdown 'open preview' command when used with `vscode.ViewColumn.Active` or `vscode.ViewColumn.Beside` --- .../src/preview/previewManager.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/src/preview/previewManager.ts b/extensions/markdown-language-features/src/preview/previewManager.ts index 50196ac882e..9e32e954c92 100644 --- a/extensions/markdown-language-features/src/preview/previewManager.ts +++ b/extensions/markdown-language-features/src/preview/previewManager.ts @@ -42,8 +42,9 @@ class PreviewStore extends Disposable { } public get(resource: vscode.Uri, previewSettings: DynamicPreviewSettings): T | undefined { + const previewColumn = this.resolvePreviewColumn(previewSettings); for (const preview of this._previews) { - if (preview.matchesResource(resource, previewSettings.previewColumn, previewSettings.locked)) { + if (preview.matchesResource(resource, previewColumn, previewSettings.locked)) { return preview; } } @@ -57,6 +58,18 @@ class PreviewStore extends Disposable { public delete(preview: T) { this._previews.delete(preview); } + + private resolvePreviewColumn(previewSettings: DynamicPreviewSettings): vscode.ViewColumn | undefined { + if (previewSettings.previewColumn === vscode.ViewColumn.Active) { + return vscode.window.tabGroups.activeTabGroup.viewColumn; + } + + if (previewSettings.previewColumn === vscode.ViewColumn.Beside) { + return vscode.window.tabGroups.activeTabGroup.viewColumn + 1; + } + + return previewSettings.previewColumn; + } } export class MarkdownPreviewManager extends Disposable implements vscode.WebviewPanelSerializer, vscode.CustomTextEditorProvider { From 902df6fc99233be30e90aaa244d72ce9cf0751bb Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 6 Oct 2022 00:50:43 -0700 Subject: [PATCH 352/599] Remove unused "extensions" output channel (#162796) --- .../extensionManagement/common/extensionManagement.ts | 1 - .../contrib/extensions/browser/extensions.contribution.ts | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 3b4958cba2b..7ab51f1d2cd 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -496,7 +496,6 @@ export interface IExtensionTipsService { export const ExtensionsLabel = localize('extensions', "Extensions"); export const ExtensionsLocalizedLabel = { value: ExtensionsLabel, original: 'Extensions' }; -export const ExtensionsChannelId = 'extensions'; export const PreferencesLabel = localize('preferences', "Preferences"); export const PreferencesLocalizedLabel = { value: PreferencesLabel, original: 'Preferences' }; diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 1519416d891..c00311ba0d7 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -8,11 +8,10 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; import { MenuRegistry, MenuId, registerAction2, Action2, ISubmenuItem, IMenuItem, IAction2Options } from 'vs/platform/actions/common/actions'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ExtensionsLabel, ExtensionsLocalizedLabel, ExtensionsChannelId, IExtensionManagementService, IExtensionGalleryService, PreferencesLocalizedLabel, InstallOperation, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionsLocalizedLabel, IExtensionManagementService, IExtensionGalleryService, PreferencesLocalizedLabel, InstallOperation, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { EnablementState, IExtensionManagementServerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, OUTDATED_EXTENSIONS_VIEW_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, SetColorThemeAction, SetFileIconThemeAction, SetProductIconThemeAction, ClearLanguageAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; @@ -84,9 +83,6 @@ registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService, Insta registerSingleton(IExtensionRecommendationNotificationService, ExtensionRecommendationNotificationService, InstantiationType.Delayed); registerSingleton(IExtensionRecommendationsService, ExtensionRecommendationsService, InstantiationType.Eager /* Prompts recommendations in the background */); -Registry.as(OutputExtensions.OutputChannels) - .registerChannel({ id: ExtensionsChannelId, label: ExtensionsLabel, log: false }); - // Quick Access Registry.as(Extensions.Quickaccess).registerQuickAccessProvider({ ctor: ManageExtensionsQuickAccessProvider, From a6a31f761f70bbedff2b462f0b8c72f0c9fffd87 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2022 09:57:00 +0200 Subject: [PATCH 353/599] remove `quickSuggestions` team setting (#162811) --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0f3f3d6e48b..4285774b5d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -105,11 +105,6 @@ "git", "sash" ], - "editor.quickSuggestions": { - "other": "inline", - "comments": "inline", - "strings": "inline" - }, "githubPullRequests.assignCreated": "${user}", "githubPullRequests.defaultMergeMethod": "squash" } From 8245b4770a022c3b8785bd5ad9d45f254fab702a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 6 Oct 2022 04:01:43 -0700 Subject: [PATCH 354/599] refactor show release notes action (#162823) Related-to: #162713 --- .../update/browser/update.contribution.ts | 58 ++++++++++++++----- .../contrib/update/browser/update.ts | 33 +---------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index dfc159cd59d..6cfdd311e50 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -8,16 +8,19 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CONTEXT_UPDATE_STATE, SwitchProductQualityContribution, RELEASE_NOTES_URL } from 'vs/workbench/contrib/update/browser/update'; +import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; +import { ProductContribution, UpdateContribution, CONTEXT_UPDATE_STATE, SwitchProductQualityContribution, RELEASE_NOTES_URL, showReleaseNotes } from 'vs/workbench/contrib/update/browser/update'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import product from 'vs/platform/product/common/product'; import { IUpdateService, StateType } from 'vs/platform/update/common/update'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { isWindows } from 'vs/base/common/platform'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { URI } from 'vs/base/common/uri'; const workbench = Registry.as(WorkbenchExtensions.Workbench); @@ -27,17 +30,46 @@ workbench.registerWorkbenchContribution(SwitchProductQualityContribution, Lifecy // Release notes -registerAction2(ShowCurrentReleaseNotesAction); +export class ShowCurrentReleaseNotesAction extends Action2 { -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: ShowCurrentReleaseNotesActionId, - title: localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes") - }, - when: RELEASE_NOTES_URL, - order: 5 -}); + constructor() { + super({ + id: ShowCurrentReleaseNotesActionId, + title: { + value: localize('showReleaseNotes', "Show Release Notes"), + mnemonicTitle: localize('mshowReleaseNotes', "Show &&Release Notes"), + original: 'Show Release Notes' + }, + category: { value: product.nameShort, original: product.nameShort }, + f1: true, + precondition: RELEASE_NOTES_URL, + menu: [{ + id: MenuId.MenubarHelpMenu, + group: '1_welcome', + order: 5, + when: RELEASE_NOTES_URL, + }] + }); + } + + async run(accessor: ServicesAccessor): Promise { + const instantiationService = accessor.get(IInstantiationService); + const productService = accessor.get(IProductService); + const openerService = accessor.get(IOpenerService); + + try { + await showReleaseNotes(instantiationService, productService.version); + } catch (err) { + if (productService.releaseNotesUrl) { + await openerService.open(URI.parse(productService.releaseNotesUrl)); + } else { + throw new Error(localize('update.noReleaseNotesOnline', "This version of {0} does not have release notes online", productService.nameLong)); + } + } + } +} + +registerAction2(ShowCurrentReleaseNotesAction); // Update diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 4b4db5cfb3f..83166c9f475 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -23,10 +23,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; -import product from 'vs/platform/product/common/product'; import { IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, SyncStatus, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { Promises } from 'vs/base/common/async'; @@ -38,7 +36,7 @@ export const RELEASE_NOTES_URL = new RawContextKey('releaseNotesUrl', '' let releaseNotesManager: ReleaseNotesManager | undefined = undefined; -function showReleaseNotes(instantiationService: IInstantiationService, version: string) { +export function showReleaseNotes(instantiationService: IInstantiationService, version: string) { if (!releaseNotesManager) { releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager); } @@ -105,35 +103,6 @@ export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { } } -export class ShowCurrentReleaseNotesAction extends Action2 { - - constructor() { - super({ - id: ShowCurrentReleaseNotesActionId, - title: { value: nls.localize('showReleaseNotes', "Show Release Notes"), original: 'Show Release Notes' }, - category: { value: product.nameShort, original: product.nameShort }, - f1: true, - precondition: RELEASE_NOTES_URL, - }); - } - - async run(accessor: ServicesAccessor): Promise { - const instantiationService = accessor.get(IInstantiationService); - const productService = accessor.get(IProductService); - - try { - await showReleaseNotes(instantiationService, productService.version); - } catch (err) { - const action = instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); - try { - await action.run(); - } catch (err2) { - throw new Error(`${err.message} and ${err2.message}`); - } - } - } -} - interface IVersion { major: number; minor: number; From b2b7e0be6e1ef71265c6e27994affc29d159405a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2022 13:04:35 +0200 Subject: [PATCH 355/599] send telemetry about git-exec duration (#162731) * send telemetry about git-exec duration * measure spawn and exec --- extensions/git/src/git.ts | 23 ++++++++++++++++++++--- extensions/git/src/main.ts | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 205ba569cdd..300f8e23184 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -18,6 +18,7 @@ import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git'; import * as byline from 'byline'; import { StringDecoder } from 'string_decoder'; +import TelemetryReporter from '@vscode/extension-telemetry'; // https://github.com/microsoft/vscode/issues/65693 const MAX_CLI_LENGTH = 30000; @@ -373,11 +374,14 @@ export class Git { private _onOutput = new EventEmitter(); get onOutput(): EventEmitter { return this._onOutput; } - constructor(options: IGitOptions) { + private readonly telemetryReporter: TelemetryReporter; + + constructor(options: IGitOptions, telemetryReporter: TelemetryReporter) { this.path = options.gitPath; this.version = options.version; this.userAgent = options.userAgent; this.env = options.env || {}; + this.telemetryReporter = telemetryReporter; const onConfigurationChanged = (e?: ConfigurationChangeEvent) => { if (e !== undefined && !e.affectsConfiguration('git.commandsToLog')) { @@ -555,7 +559,9 @@ export class Git { } private async _exec(args: string[], options: SpawnOptions = {}): Promise> { + const startSpawn = Date.now(); const child = this.spawn(args, options); + const durSpawn = Date.now() - startSpawn; options.onSpawn?.(child); @@ -563,12 +569,13 @@ export class Git { child.stdin!.end(options.input, 'utf8'); } - const startTime = Date.now(); + const startExec = Date.now(); const bufferResult = await exec(child, options.cancellationToken); + const durExec = Date.now() - startExec; if (options.log !== false) { // command - this.log(`> git ${args.join(' ')} [${Date.now() - startTime}ms]\n`); + this.log(`> git ${args.join(' ')} [${durExec}ms]\n`); // stdout if (bufferResult.stdout.length > 0 && args.find(a => this.commandsToLog.includes(a))) { @@ -581,6 +588,16 @@ export class Git { } } + /* __GDPR__ + "git.execDuration" : { + "owner": "lszomoru", + "comment": "Time it takes to spawn and execute a git command", + "durSpawn": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth","isMeasurement": true, "comment": "Time it took to run spawn git" }, + "durExec": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth","isMeasurement": true, "comment": "Time git took" }, + } + */ + this.telemetryReporter.sendTelemetryEvent('git.execDuration', undefined, { durSpawn, durExec }); + let encoding = options.encoding || 'utf8'; encoding = iconv.encodingExists(encoding) ? encoding : 'utf8'; diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 907c0147398..dd2e8904c3b 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -89,7 +89,7 @@ async function createModel(context: ExtensionContext, outputChannelLogger: Outpu userAgent: `git/${info.version} (${(os as any).version?.() ?? os.type()} ${os.release()}; ${os.platform()} ${os.arch()}) vscode/${vscodeVersion} (${env.appName})`, version: info.version, env: environment, - }); + }, telemetryReporter); const model = new Model(git, askpass, context.globalState, outputChannelLogger, telemetryReporter); disposables.push(model); From 3f21113b39ac03fad556271357272636bdced86c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 14:35:17 +0200 Subject: [PATCH 356/599] #155990 Improve extension merging (#162829) - handle custom buultin extensions --- .../userDataSync/common/extensionsMerge.ts | 224 ++++++++------ .../userDataSync/common/extensionsSync.ts | 17 +- .../test/common/extensionsMerge.test.ts | 280 +++++++++++++----- 3 files changed, 351 insertions(+), 170 deletions(-) diff --git a/src/vs/platform/userDataSync/common/extensionsMerge.ts b/src/vs/platform/userDataSync/common/extensionsMerge.ts index 8def92906ef..6c046e61e8d 100644 --- a/src/vs/platform/userDataSync/common/extensionsMerge.ts +++ b/src/vs/platform/userDataSync/common/extensionsMerge.ts @@ -6,7 +6,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { deepClone, equals } from 'vs/base/common/objects'; import * as semver from 'vs/base/common/semver/semver'; -import { isUndefined } from 'vs/base/common/types'; +import { assertIsDefined } from 'vs/base/common/types'; import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ISyncExtension, ISyncExtensionWithVersion } from 'vs/platform/userDataSync/common/userDataSync'; @@ -15,7 +15,7 @@ export interface IMergeResult { readonly remote: { added: ISyncExtension[]; removed: ISyncExtension[]; updated: ISyncExtension[]; all: ISyncExtension[] } | null; } -export function merge(localExtensions: ISyncExtensionWithVersion[], remoteExtensions: ISyncExtension[] | null, lastSyncExtensions: ISyncExtension[] | null, skippedExtensions: ISyncExtension[], ignoredExtensions: string[]): IMergeResult { +export function merge(localExtensions: ISyncExtensionWithVersion[], remoteExtensions: ISyncExtension[] | null, lastSyncExtensions: ISyncExtension[] | null, skippedExtensions: ISyncExtension[], ignoredExtensions: string[], lastSyncBuiltinExtensions: IExtensionIdentifier[]): IMergeResult { const added: ISyncExtension[] = []; const removed: IExtensionIdentifier[] = []; const updated: ISyncExtensionWithVersion[] = []; @@ -57,138 +57,164 @@ export function merge(localExtensions: ISyncExtensionWithVersion[], remoteExtens }; const localExtensionsMap: Map = localExtensions.reduce(addExtensionToMap, new Map()); const remoteExtensionsMap = remoteExtensions.reduce(addExtensionToMap, new Map()); - const newRemoteExtensionsMap = remoteExtensions.reduce((map: Map, extension: ISyncExtension) => { - const key = getKey(extension); - extension = deepClone(extension); - const localExtension = localExtensionsMap.get(key); - if (localExtension) { - if (localExtension.installed) { - extension.installed = true; - } - if (!extension.version) { - extension.version = localExtension.version; - } - } - return addExtensionToMap(map, extension); - }, new Map()); + const newRemoteExtensionsMap = remoteExtensions.reduce((map: Map, extension: ISyncExtension) => addExtensionToMap(map, deepClone(extension)), new Map()); const lastSyncExtensionsMap = lastSyncExtensions ? lastSyncExtensions.reduce(addExtensionToMap, new Map()) : null; const skippedExtensionsMap = skippedExtensions.reduce(addExtensionToMap, new Map()); const ignoredExtensionsSet = ignoredExtensions.reduce((set, id) => { const uuid = uuids.get(id.toLowerCase()); return set.add(uuid ? `uuid:${uuid}` : `id:${id.toLowerCase()}`); }, new Set()); + const lastSyncBuiltinExtensionsSet = lastSyncBuiltinExtensions.reduce((set, { id, uuid }) => { + uuid = uuid ?? uuids.get(id.toLowerCase()); + return set.add(uuid ? `uuid:${uuid}` : `id:${id.toLowerCase()}`); + }, new Set()); - const localToRemote = compare(localExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet); + const localToRemote = compare(localExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet, false); if (localToRemote.added.size > 0 || localToRemote.removed.size > 0 || localToRemote.updated.size > 0) { - const baseToLocal = compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet); - const baseToRemote = compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet); + const baseToLocal = compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet, false); + const baseToRemote = compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet, true); - const merge = (key: string, updatedInRemote: boolean): ISyncExtensionWithVersion | undefined => { - const localExtension = localExtensionsMap.get(key); - if (localExtension) { - const remoteExtension = remoteExtensionsMap.get(key)!; - const mergedExtension = updatedInRemote ? remoteExtension : localExtension; - return { - ...mergedExtension, - version: remoteExtension.version && (!localExtension.installed || semver.gt(remoteExtension.version, localExtension.version)) ? remoteExtension.version : localExtension.version, - state: mergeExtensionState(localExtension, remoteExtension, lastSyncExtensionsMap?.get(key)), - preRelease: isUndefined(mergedExtension.preRelease) /* from older client*/ ? localExtension.preRelease - : (localExtension.installed ? mergedExtension.preRelease : remoteExtension.preRelease) - }; - - } - return undefined; + const merge = (key: string, localExtension: ISyncExtensionWithVersion, remoteExtension: ISyncExtension, preferred: ISyncExtension): ISyncExtensionWithVersion => { + return { + ...preferred, + installed: localExtension.installed || remoteExtension.installed, + version: remoteExtension.version && (!localExtension.installed || semver.gt(remoteExtension.version, localExtension.version)) ? remoteExtension.version : localExtension.version, + state: mergeExtensionState(localExtension, remoteExtension, lastSyncExtensionsMap?.get(key)), + preRelease: (localExtension.installed ? preferred.preRelease : remoteExtension.preRelease) ?? /* from older client*/ localExtension.preRelease + }; }; - // Remotely removed extension. + // Remotely removed extension => exist in base and does not in remote for (const key of baseToRemote.removed.values()) { - const e = localExtensionsMap.get(key); - if (e) { - removed.push(e.identifier); + const localExtension = localExtensionsMap.get(key); + if (!localExtension) { + continue; } + + const baseExtension = assertIsDefined(lastSyncExtensionsMap?.get(key)); + const wasAnInstalledExtensionDuringLastSync = !lastSyncBuiltinExtensionsSet.has(key) && baseExtension.installed; + if (localExtension.installed && wasAnInstalledExtensionDuringLastSync /* It is an installed extension now and during last sync */) { + // Installed extension is removed from remote. Remove it from local. + removed.push(localExtension.identifier); + } else { + // Add to remote: It is a builtin extenision or got installed after last sync + newRemoteExtensionsMap.set(key, localExtension); + } + } - // Remotely added extension + // Remotely added extension => does not exist in base and exist in remote for (const key of baseToRemote.added.values()) { - // Got added in local - if (baseToLocal.added.has(key)) { + const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); + const localExtension = localExtensionsMap.get(key); + + // Also exist in local + if (localExtension) { // Is different from local to remote if (localToRemote.updated.has(key)) { - const mergedExtension = merge(key, true); - if (mergedExtension) { + const mergedExtension = merge(key, localExtension, remoteExtension, remoteExtension); + // Update locally only when the extension has changes in properties other than installed poperty + if (!areSame(localExtension, remoteExtension, false, false)) { updated.push(massageOutgoingExtension(mergedExtension, key)); - newRemoteExtensionsMap.set(key, mergedExtension); } + newRemoteExtensionsMap.set(key, mergedExtension); } } else { - // Add only installed extension to local - const remoteExtension = remoteExtensionsMap.get(key)!; + // Add only if the extension is an installed extension if (remoteExtension.installed) { added.push(massageOutgoingExtension(remoteExtension, key)); } } } - // Remotely updated extensions + // Remotely updated extension => exist in base and remote for (const key of baseToRemote.updated.values()) { - // Update in local always - const mergedExtension = merge(key, true); - if (mergedExtension) { - updated.push(massageOutgoingExtension(mergedExtension, key)); - newRemoteExtensionsMap.set(key, mergedExtension); - } - } + const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); + const baseExtension = assertIsDefined(lastSyncExtensionsMap?.get(key)); + const localExtension = localExtensionsMap.get(key); - // Locally added extensions - for (const key of baseToLocal.added.values()) { - // Not there in remote - if (!baseToRemote.added.has(key)) { - newRemoteExtensionsMap.set(key, localExtensionsMap.get(key)!); - } - } - - // Locally updated extensions - for (const key of baseToLocal.updated.values()) { - // If removed in remote - if (baseToRemote.removed.has(key)) { - continue; - } - - // If not updated in remote - if (!baseToRemote.updated.has(key)) { - const mergedExtension = merge(key, false); - if (mergedExtension) { - // Retain installed property - if (newRemoteExtensionsMap.get(key)?.installed) { - mergedExtension.installed = true; - } + // Also exist in local + if (localExtension) { + const wasAnInstalledExtensionDuringLastSync = !lastSyncBuiltinExtensionsSet.has(key) && baseExtension.installed; + if (wasAnInstalledExtensionDuringLastSync && localExtension.installed && !remoteExtension.installed) { + // Remove it locally if it is installed locally and not remotely + removed.push(localExtension.identifier); + } else { + // Update in local always + const mergedExtension = merge(key, localExtension, remoteExtension, remoteExtension); + updated.push(massageOutgoingExtension(mergedExtension, key)); newRemoteExtensionsMap.set(key, mergedExtension); } } + // Add it locally if does not exist locally and installed remotely + else if (remoteExtension.installed) { + added.push(massageOutgoingExtension(remoteExtension, key)); + } + } - // Locally removed extensions - for (const key of baseToLocal.removed.values()) { - // If not skipped and not updated in remote - if (!skippedExtensionsMap.has(key) && !baseToRemote.updated.has(key)) { - // Remove only if it is an installed extension - if (lastSyncExtensionsMap?.get(key)?.installed) { - newRemoteExtensionsMap.delete(key); - } + // Locally added extension => does not exist in base and exist in local + for (const key of baseToLocal.added.values()) { + // If added in remote (already handled) + if (baseToRemote.added.has(key)) { + continue; } + newRemoteExtensionsMap.set(key, assertIsDefined(localExtensionsMap.get(key))); + } + + // Locally updated extension => exist in base and local + for (const key of baseToLocal.updated.values()) { + // If removed in remote (already handled) + if (baseToRemote.removed.has(key)) { + continue; + } + // If updated in remote (already handled) + if (baseToRemote.updated.has(key)) { + continue; + } + const localExtension = assertIsDefined(localExtensionsMap.get(key)); + const remoteExtension = assertIsDefined(remoteExtensionsMap.get(key)); + // Update remotely + newRemoteExtensionsMap.set(key, merge(key, localExtension, remoteExtension, localExtension)); + } + + // Locally removed extensions => exist in base and does not exit in local + for (const key of baseToLocal.removed.values()) { + // If updated in remote (already handled) + if (baseToRemote.updated.has(key)) { + continue; + } + // If removed in remote (already handled) + if (baseToRemote.removed.has(key)) { + continue; + } + // Skipped + if (skippedExtensionsMap.has(key)) { + continue; + } + // Skip if it is a builtin extension + if (!assertIsDefined(remoteExtensionsMap.get(key)).installed) { + continue; + } + // Skip if it was a builtin extension during last sync + if (lastSyncBuiltinExtensionsSet.has(key) || !assertIsDefined(lastSyncExtensionsMap?.get(key)).installed) { + continue; + } + newRemoteExtensionsMap.delete(key); } } const remote: ISyncExtension[] = []; - const remoteChanges = compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set(), { checkInstalledProperty: true, checkVersionProperty: true }); - if (remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0) { + const remoteChanges = compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set(), true); + const hasRemoteChanges = remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0; + if (hasRemoteChanges) { newRemoteExtensionsMap.forEach((value, key) => remote.push(massageOutgoingExtension(value, key))); } return { local: { added, removed, updated }, - remote: remote.length ? { + remote: hasRemoteChanges ? { added: [...remoteChanges.added].map(id => newRemoteExtensionsMap.get(id)!), updated: [...remoteChanges.updated].map(id => newRemoteExtensionsMap.get(id)!), removed: [...remoteChanges.removed].map(id => remoteExtensionsMap.get(id)!), @@ -197,7 +223,7 @@ export function merge(localExtensions: ISyncExtensionWithVersion[], remoteExtens }; } -function compare(from: Map | null, to: Map, ignoredExtensions: Set, { checkInstalledProperty, checkVersionProperty }: { checkInstalledProperty: boolean; checkVersionProperty: boolean } = { checkInstalledProperty: false, checkVersionProperty: false }): { added: Set; removed: Set; updated: Set } { +function compare(from: Map | null, to: Map, ignoredExtensions: Set, checkVersionProperty: boolean): { added: Set; removed: Set; updated: Set } { const fromKeys = from ? [...from.keys()].filter(key => !ignoredExtensions.has(key)) : []; const toKeys = [...to.keys()].filter(key => !ignoredExtensions.has(key)); const added = toKeys.filter(key => fromKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set()); @@ -210,13 +236,7 @@ function compare(from: Map | null, to: Map | null, to: Map | undefined { const localState = localExtension.state; const remoteState = remoteExtension.state; diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index f2e742095d9..118b998774a 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -37,12 +37,15 @@ type IExtensionResourceMergeResult = IAcceptResult & IExtensionMergeResult; interface IExtensionResourcePreview extends IResourcePreview { readonly localExtensions: ISyncExtensionWithVersion[]; + readonly remoteExtensions: ISyncExtension[] | null; readonly skippedExtensions: ISyncExtension[]; + readonly builtinExtensions: IExtensionIdentifier[]; readonly previewResult: IExtensionResourceMergeResult; } interface ILastSyncUserData extends IRemoteUserData { skippedExtensions: ISyncExtension[] | undefined; + builtinExtensions: IExtensionIdentifier[] | undefined; } async function parseAndMigrateExtensions(syncData: ISyncData, extensionManagementService: IExtensionManagementService): Promise { @@ -127,6 +130,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse protected async generateSyncPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise { const remoteExtensions: ISyncExtension[] | null = remoteUserData.syncData ? await parseAndMigrateExtensions(remoteUserData.syncData, this.extensionManagementService) : null; const skippedExtensions: ISyncExtension[] = lastSyncUserData?.skippedExtensions || []; + const builtinExtensions: IExtensionIdentifier[] = lastSyncUserData?.builtinExtensions || []; const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData?.syncData ? await parseAndMigrateExtensions(lastSyncUserData.syncData, this.extensionManagementService) : null; const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); @@ -139,7 +143,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`); } - const { local, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions); + const { local, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions, builtinExtensions); const previewResult: IExtensionResourceMergeResult = { local, remote, content: this.getPreviewContent(localExtensions, local.added, local.updated, local.removed), @@ -150,12 +154,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const localContent = this.stringify(localExtensions, false); return [{ skippedExtensions, + builtinExtensions, baseResource: this.baseResource, baseContent: lastSyncExtensions ? this.stringify(lastSyncExtensions, false) : localContent, localResource: this.localResource, localContent, localExtensions, remoteResource: this.remoteResource, + remoteExtensions, remoteContent: remoteExtensions ? this.stringify(remoteExtensions, false) : null, previewResource: this.previewResource, previewResult, @@ -170,7 +176,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); const localExtensions = await this.getLocalExtensions(installedExtensions); const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); - const { remote } = merge(localExtensions, lastSyncExtensions, lastSyncExtensions, lastSyncUserData.skippedExtensions || [], ignoredExtensions); + const { remote } = merge(localExtensions, lastSyncExtensions, lastSyncExtensions, lastSyncUserData.skippedExtensions || [], ignoredExtensions, lastSyncUserData.builtinExtensions || []); return remote !== null; } @@ -225,7 +231,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse private async acceptLocal(resourcePreview: IExtensionResourcePreview): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(undefined, this.profileLocation); const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); - const mergeResult = merge(resourcePreview.localExtensions, null, null, resourcePreview.skippedExtensions, ignoredExtensions); + const mergeResult = merge(resourcePreview.localExtensions, null, null, resourcePreview.skippedExtensions, ignoredExtensions, resourcePreview.builtinExtensions); const { local, remote } = mergeResult; return { content: resourcePreview.localContent, @@ -241,7 +247,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); const remoteExtensions = resourcePreview.remoteContent ? JSON.parse(resourcePreview.remoteContent) : null; if (remoteExtensions !== null) { - const mergeResult = merge(resourcePreview.localExtensions, remoteExtensions, resourcePreview.localExtensions, [], ignoredExtensions); + const mergeResult = merge(resourcePreview.localExtensions, remoteExtensions, resourcePreview.localExtensions, [], ignoredExtensions, resourcePreview.builtinExtensions); const { local, remote } = mergeResult; return { content: resourcePreview.remoteContent, @@ -285,7 +291,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse if (lastSyncUserData?.ref !== remoteUserData.ref) { // update last sync this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized extensions...`); - await this.updateLastSyncUserData(remoteUserData, { skippedExtensions }); + const builtinExtensions = localExtensions.filter(e => !e.installed).map(e => e.identifier); + await this.updateLastSyncUserData(remoteUserData, { skippedExtensions, builtinExtensions }); this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized extensions.${skippedExtensions.length ? ` Skipped: ${JSON.stringify(skippedExtensions.map(e => e.identifier.id))}.` : ''}`); } } diff --git a/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts b/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts index 5d3ec0c49f3..039b660c450 100644 --- a/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts +++ b/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts @@ -16,7 +16,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, null, null, [], []); + const actual = merge(localExtensions, null, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -35,7 +35,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, null, null, [], ['a']); + const actual = merge(localExtensions, null, null, [], ['a'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -54,7 +54,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, null, null, [], ['A']); + const actual = merge(localExtensions, null, null, [], ['A'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -77,7 +77,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, null, null, skippedExtension, []); + const actual = merge(localExtensions, null, null, skippedExtension, [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -99,7 +99,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, null, null, skippedExtension, ['a']); + const actual = merge(localExtensions, null, null, skippedExtension, ['a'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -123,7 +123,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, []); @@ -146,7 +146,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], ['a']); + const actual = merge(localExtensions, remoteExtensions, null, [], ['a'], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, []); @@ -168,7 +168,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'a', uuid: 'a' }, { id: 'd', uuid: 'd' }]); @@ -191,7 +191,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'd', uuid: 'd' }, disabled: true, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'a', uuid: 'a' }]); @@ -213,7 +213,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a'], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'd', uuid: 'd' }]); @@ -237,7 +237,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'd', uuid: 'd' }]); @@ -261,7 +261,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['b']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['b'], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'd', uuid: 'd' }]); @@ -270,9 +270,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when local is moved forwarded', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const localExtensions: ISyncExtensionWithVersion[] = [ { identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0' }, @@ -287,7 +287,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -296,9 +296,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when local is moved forwarded with disabled extensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const localExtensions: ISyncExtensionWithVersion[] = [ { identifier: { id: 'a', uuid: 'a' }, disabled: true, installed: true, version: '1.0.0' }, @@ -315,7 +315,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -324,9 +324,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when local is moved forwarded with ignored settings', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const localExtensions: ISyncExtensionWithVersion[] = [ { identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0' }, @@ -337,7 +337,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['b']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['b'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -348,9 +348,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when local is moved forwarded with skipped extensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const skippedExtensions: ISyncExtension[] = [ { identifier: { id: 'd', uuid: 'd' }, installed: true }, @@ -369,7 +369,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -378,9 +378,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when local is moved forwarded with skipped and ignored extensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const skippedExtensions: ISyncExtension[] = [ { identifier: { id: 'd', uuid: 'd' }, installed: true }, @@ -398,7 +398,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'b', uuid: 'b' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['c']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['c'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -407,9 +407,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when both moved forwarded', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const localExtensions: ISyncExtensionWithVersion[] = [ { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, @@ -427,7 +427,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'e', uuid: 'e' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, [{ id: 'a', uuid: 'a' }]); @@ -436,9 +436,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when both moved forwarded with ignored extensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const localExtensions: ISyncExtensionWithVersion[] = [ { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, @@ -456,7 +456,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a', 'e']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a', 'e'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -465,9 +465,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when both moved forwarded with skipped extensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const skippedExtensions: ISyncExtension[] = [ { identifier: { id: 'a', uuid: 'a' }, installed: true }, @@ -487,7 +487,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'e', uuid: 'e' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, []); @@ -496,9 +496,9 @@ suite('ExtensionsMerge', () => { }); test('merge local and remote extensions when both moved forwarded with skipped and ignoredextensions', () => { - const baseExtensions: ISyncExtension[] = [ - { identifier: { id: 'a', uuid: 'a' }, installed: true }, - { identifier: { id: 'd', uuid: 'd' }, installed: true }, + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0' }, + { identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0' }, ]; const skippedExtensions: ISyncExtension[] = [ { identifier: { id: 'a', uuid: 'a' }, installed: true }, @@ -518,7 +518,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['e']); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['e'], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -543,7 +543,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'c', uuid: 'c' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'd', uuid: 'd' }, installed: true, version: '1.0.0', preRelease: false }]); assert.deepStrictEqual(actual.local.removed, []); @@ -560,7 +560,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'b', uuid: 'b' }, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -579,7 +579,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, installed: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -596,7 +596,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'b', uuid: 'b' }, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -615,7 +615,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, installed: true, disabled: true, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -631,7 +631,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, installed: true, disabled: true, version: '1.0.0' }, ]; - const actual = merge(localExtensions, remoteExtensions, localExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, localExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -653,7 +653,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -667,7 +667,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }]); assert.deepStrictEqual(actual.local.removed, []); @@ -681,7 +681,7 @@ suite('ExtensionsMerge', () => { ]; const remoteExtensions: ISyncExtensionWithVersion[] = []; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -697,7 +697,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -713,7 +713,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, ]; - const actual = merge(localExtensions, remoteExtensions, null, [], []); + const actual = merge(localExtensions, remoteExtensions, null, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -729,7 +729,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, localExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, localExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -745,7 +745,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, localExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, localExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -761,7 +761,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -777,7 +777,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -793,7 +793,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -809,7 +809,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -828,7 +828,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true, preRelease: true, disabled: true }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -844,7 +844,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -860,7 +860,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, ]; - const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, remoteExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -879,7 +879,7 @@ suite('ExtensionsMerge', () => { { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false, disabled: true }, ]; - const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []); + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); assert.deepStrictEqual(actual.local.added, []); assert.deepStrictEqual(actual.local.removed, []); @@ -887,4 +887,146 @@ suite('ExtensionsMerge', () => { assert.deepStrictEqual(actual.remote, null); }); + test('merge: base has builtin extension, local does not have extension, remote has extension installed', () => { + const localExtensions: ISyncExtensionWithVersion[] = []; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: false, preRelease: false }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); + + assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }]); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote, null); + }); + + test('merge: base has installed extension, local has installed extension, remote has extension builtin', () => { + const localExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: false }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, [{ id: 'a', uuid: 'a' }]); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote, null); + }); + + test('merge: base has installed extension, local has builtin extension, remote does not has extension', () => { + const localExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: false }, + ]; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = []; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote?.all, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false }]); + }); + + test('merge: base has builtin extension, local has installed extension, remote has builtin extension with updated state', () => { + const localExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: false }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: false, state: { 'a': 1 } }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], [{ id: 'a', uuid: 'a' }]); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false, installed: true, state: { 'a': 1 } }]); + assert.deepStrictEqual(actual.remote?.all, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false, installed: true, state: { 'a': 1 } }]); + }); + + test('merge: base has installed extension, last time synced as builtin extension, local has installed extension, remote has builtin extension with updated state', () => { + const localExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: true }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', installed: false, state: { 'a': 1 } }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], [{ id: 'a', uuid: 'a' }]); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false, installed: true, state: { 'a': 1 } }]); + assert.deepStrictEqual(actual.remote?.all, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.0.0', preRelease: false, installed: true, state: { 'a': 1 } }]); + }); + + test('merge: base has builtin extension, local does not have extension, remote has builtin extension', () => { + const localExtensions: ISyncExtensionWithVersion[] = []; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: false, preRelease: false }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: false, preRelease: false }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], []); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote, null); + }); + + test('merge: base has installed extension, last synced as builtin, local does not have extension, remote has installed extension', () => { + const localExtensions: ISyncExtensionWithVersion[] = []; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], [{ id: 'a', uuid: 'a' }]); + + assert.deepStrictEqual(actual.local.added, []); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote, null); + }); + + test('merge: base has builtin extension, last synced as builtin, local does not have extension, remote has installed extension', () => { + const localExtensions: ISyncExtensionWithVersion[] = []; + const baseExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: false, preRelease: false }, + ]; + const remoteExtensions: ISyncExtensionWithVersion[] = [ + { identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }, + ]; + + const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], [], [{ id: 'a', uuid: 'a' }]); + + assert.deepStrictEqual(actual.local.added, [{ identifier: { id: 'a', uuid: 'a' }, version: '1.1.0', installed: true, preRelease: false }]); + assert.deepStrictEqual(actual.local.removed, []); + assert.deepStrictEqual(actual.local.updated, []); + assert.deepStrictEqual(actual.remote, null); + }); + }); From 0f8068478eaf2f02792aa79937dcc3d614e99859 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 6 Oct 2022 06:02:33 -0700 Subject: [PATCH 357/599] Support format2 (#162785) --- .../workbench/api/common/extHost.api.impl.ts | 8 +++-- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLocalizationService.ts | 6 ++-- .../vscode.proposed.localization.d.ts | 29 +++++++++++++++---- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 413b1ff5505..8e0c6af5fbd 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1171,12 +1171,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // namespace: l10n const l10n: typeof vscode.l10n = { - t(...params: [message: string, ...args: any[]] | [{ message: string; args?: any[]; comment: string[] }]): string { + t(...params: [message: string, ...args: Array] | [message: string, args: Record] | [{ message: string; args?: Array | Record; comment: string[] }]): string { checkProposedApiEnabled(extension, 'localization'); if (typeof params[0] === 'string') { const key = params.shift() as string; - return extHostLocalization.getMessage(extension.identifier.value, { message: key, args: params as any[] | undefined }); + + // We have either rest args which are Array or an array with a single Record. This ensures we get a + // Record which will be formatted correctly. + const argsFormatted = !params || typeof params[0] !== 'object' ? params : params[0]; + return extHostLocalization.getMessage(extension.identifier.value, { message: key, args: argsFormatted as Record | undefined }); } return extHostLocalization.getMessage(extension.identifier.value, params[0]); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 50ad7f3c9e3..8ffa6eb5e0d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2206,7 +2206,7 @@ export interface ExtHostLocalizationShape { export interface IStringDetails { message: string; - args?: any[]; + args?: Record; comment?: string[]; } diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index 335fdf88ac6..57d41228c5e 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { LANGUAGE_DEFAULT } from 'vs/base/common/platform'; -import { format } from 'vs/base/common/strings'; +import { format2 } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -35,7 +35,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { getMessage(extensionId: string, details: IStringDetails): string { const { message, args, comment } = details; if (this.isDefaultLanguage) { - return format(message, ...(args ?? [])); + return format2(message, (args ?? {})); } let key = message; @@ -46,7 +46,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { if (!str) { this.logService.warn(`Using default string since no string found in i18n bundle that has the key: ${key}`); } - return format(str ?? key, ...(args ?? [])); + return format2(str ?? key, (args ?? {})); } getBundle(extensionId: string): { [key: string]: string } | undefined { diff --git a/src/vscode-dts/vscode.proposed.localization.d.ts b/src/vscode-dts/vscode.proposed.localization.d.ts index 40a3b83118e..5bae5d5b35f 100644 --- a/src/vscode-dts/vscode.proposed.localization.d.ts +++ b/src/vscode-dts/vscode.proposed.localization.d.ts @@ -20,8 +20,22 @@ declare module 'vscode' { * @param args The arguments to be used in the localized string. The index of the argument is used to * match the template placeholder in the localized string. * @returns localized string with injected arguments. + * @example l10n.localize('hello', 'Hello {0}!', 'World'); */ - export function t(message: string, ...args: any[]): string; + export function t(message: string, ...args: Array): string; + + /** + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected {@link args} values for any templated values). + * @param message The message to localize. Supports named templating where strings like {foo} and {bar} are + * replaced by the value in the Record for that key (foo, bar, etc). + * @param args The arguments to be used in the localized string. The name of the key in the record is used to + * match the template placeholder in the localized string. + * @returns localized string with injected arguments. + * @example l10n.t('Hello {name}', { name: 'Erich' }); + */ + export function t(message: string, args: Record): string; /** * Marks a string for localization. If a localized bundle is available for the language specified by * {@link env.language} and the bundle has a localized value for this message, then that localized @@ -31,15 +45,18 @@ declare module 'vscode' { */ export function t(options: { /** - * The message to localize. Supports index templating where strings like {0} and {1} are - * replaced by the item at that index in the {@link args} array. + * The message to localize. If {@link args} is an array, this message supports index templating where strings like + * {0} and {1} are replaced by the item at that index in the {@link args} array. If args is a Record, + * this supports named templating where strings like {foo} and {bar} are replaced by the value in + * the Record for that key (foo, bar, etc). */ message: string; /** - * The arguments to be used in the localized string. The index of the argument is used to - * match the template placeholder in the localized string. + * The arguments to be used in the localized string. As an array, the index of the argument is used to + * match the template placeholder in the localized string. As a Record, the key is used to match the template + * placeholder in the localized string. */ - args?: any[]; + args?: Array | Record; /** * A comment to help translators understand the context of the message. */ From 03f98efb757dbb4ba105284d1533642598c0f98a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2022 15:17:12 +0200 Subject: [PATCH 358/599] fix `Extract Telemetry` step (#162832) --- extensions/git/src/git.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 300f8e23184..46d58ce6d90 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -593,7 +593,7 @@ export class Git { "owner": "lszomoru", "comment": "Time it takes to spawn and execute a git command", "durSpawn": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth","isMeasurement": true, "comment": "Time it took to run spawn git" }, - "durExec": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth","isMeasurement": true, "comment": "Time git took" }, + "durExec": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth","isMeasurement": true, "comment": "Time git took" } } */ this.telemetryReporter.sendTelemetryEvent('git.execDuration', undefined, { durSpawn, durExec }); From 19f4680c266b8d236183b74f3406f26e2392ca1f Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 6 Oct 2022 07:01:23 -0700 Subject: [PATCH 359/599] simplify process kill (#162833) fix #162344 --- src/vs/platform/terminal/common/terminal.ts | 2 +- .../platform/terminal/node/ptyHostService.ts | 4 +- src/vs/platform/terminal/node/ptyService.ts | 73 +++++-------------- src/vs/server/node/remoteTerminalChannel.ts | 2 +- .../contrib/terminal/browser/remotePty.ts | 2 +- .../terminal/common/remoteTerminalChannel.ts | 4 +- .../terminal/electron-sandbox/localPty.ts | 2 +- 7 files changed, 27 insertions(+), 62 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 692f8844b9c..60ec1dacd1f 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -331,7 +331,7 @@ export interface IPtyService extends IPtyHostController { reduceConnectionGraceTime(): Promise; requestDetachInstance(workspaceId: string, instanceId: number): Promise; acceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise; - freePortKillProcess?(id: number, port: string): Promise<{ port: string; processId: string }>; + freePortKillProcess?(port: string): Promise<{ port: string; processId: string }>; /** * Serializes and returns terminal state. * @param ids The persistent terminal IDs to serialize. diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index 41cb6ae3a14..98bc9f4180e 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -316,11 +316,11 @@ export class PtyHostService extends Disposable implements IPtyService { return this._proxy.acceptDetachInstanceReply(requestId, persistentProcessId); } - async freePortKillProcess(id: number, port: string): Promise<{ port: string; processId: string }> { + async freePortKillProcess(port: string): Promise<{ port: string; processId: string }> { if (!this._proxy.freePortKillProcess) { throw new Error('freePortKillProcess does not exist on the pty proxy'); } - return this._proxy.freePortKillProcess(id, port); + return this._proxy.freePortKillProcess(port); } async serializeTerminalState(ids: number[]): Promise { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 85ea2b0cc33..325a911670c 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -105,64 +105,29 @@ export class PtyService extends Disposable implements IPtyService { this._detachInstanceRequestStore.acceptReply(requestId, processDetails); } - async freePortKillProcess(id: number, port: string): Promise<{ port: string; processId: string }> { - let result: { port: string; processId: string } | undefined; - if (!isWindows) { - const stdout = await new Promise((resolve, reject) => { - exec(`lsof -nP -iTCP -sTCP:LISTEN | grep ${port}`, {}, (err, stdout) => { - if (err) { - return reject('Problem occurred when listing active processes'); - } - resolve(stdout); - }); - }); - const processesForPort = stdout.split('\n'); - if (processesForPort.length >= 1) { - const capturePid = /\s+(\d+)\s+/; - const processId = processesForPort[0].match(capturePid)?.[1]; - if (processId) { - await new Promise((resolve, reject) => { - exec(`kill ${processId}`, {}, (err, stdout) => { - if (err) { - return reject(`Problem occurred when killing the process with PID: ${processId}`); - } - resolve(stdout); - }); - result = { port, processId }; - }); + async freePortKillProcess(port: string): Promise<{ port: string; processId: string }> { + const stdout = await new Promise((resolve, reject) => { + exec(isWindows ? `netstat -ano | findstr "${port}"` : `lsof -nP -iTCP -sTCP:LISTEN | grep ${port}`, {}, (err, stdout) => { + if (err) { + return reject('Problem occurred when listing active processes'); } - } - } else { - const stdout = await new Promise((resolve, reject) => { - exec(`netstat -ano | findstr "${port}"`, {}, (err, stdout) => { - if (err) { - return reject('Problem occurred when listing active processes'); - } - resolve(stdout); - }); + resolve(stdout); }); - const processesForPort = stdout.split('\n'); - if (processesForPort.length >= 1) { - const capturePid = /LISTENING\s+(\d+)/; - const processId = processesForPort[0].match(capturePid)?.[1]; - if (processId) { - await new Promise((resolve, reject) => { - exec(`Taskkill /F /PID ${processId}`, {}, (err, stdout) => { - if (err) { - return reject(`Problem occurred when killing the process with PID: ${processId}`); - } - resolve(stdout); - }); - result = { port, processId }; - }); - } + }); + const processesForPort = stdout.split('\n'); + if (processesForPort.length >= 1) { + const capturePid = /\s+(\d+)\s+/; + const processId = processesForPort[0].match(capturePid)?.[1]; + if (processId) { + try { + process.kill(Number.parseInt(processId)); + } catch { } + } else { + throw new Error(`Processes for port ${port} were not found`); } + return { port, processId }; } - - if (result) { - return result; - } - throw new Error(`Processes for port ${port} were not found`); + throw new Error(`Could not kill process with port ${port}`); } async serializeTerminalState(ids: number[]): Promise { diff --git a/src/vs/server/node/remoteTerminalChannel.ts b/src/vs/server/node/remoteTerminalChannel.ts index 457e31a4451..faa7048e384 100644 --- a/src/vs/server/node/remoteTerminalChannel.ts +++ b/src/vs/server/node/remoteTerminalChannel.ts @@ -147,7 +147,7 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< case '$refreshProperty': return this._ptyService.refreshProperty.apply(this._ptyService, args); case '$requestDetachInstance': return this._ptyService.requestDetachInstance(args[0], args[1]); case '$acceptDetachedInstance': return this._ptyService.acceptDetachInstanceReply(args[0], args[1]); - case '$freePortKillProcess': return this._ptyService.freePortKillProcess?.apply(args[0], args[1]); + case '$freePortKillProcess': return this._ptyService.freePortKillProcess?.apply(this._ptyService, args); } throw new Error(`IPC Command ${command} not found`); diff --git a/src/vs/workbench/contrib/terminal/browser/remotePty.ts b/src/vs/workbench/contrib/terminal/browser/remotePty.ts index 7b7ac69688f..98d5ca5aa11 100644 --- a/src/vs/workbench/contrib/terminal/browser/remotePty.ts +++ b/src/vs/workbench/contrib/terminal/browser/remotePty.ts @@ -111,7 +111,7 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { if (!this._remoteTerminalChannel.freePortKillProcess) { throw new Error('freePortKillProcess does not exist on the local pty service'); } - return this._remoteTerminalChannel.freePortKillProcess(this.id, port); + return this._remoteTerminalChannel.freePortKillProcess(port); } acknowledgeDataEvent(charCount: number): void { diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index 23d2d4552b1..9efd1de958c 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -237,8 +237,8 @@ export class RemoteTerminalChannelClient implements IPtyHostController { sendCommandResult(reqId: number, isError: boolean, payload: any): Promise { return this._channel.call('$sendCommandResult', [reqId, isError, payload]); } - freePortKillProcess(id: number, port: string): Promise<{ port: string; processId: string }> { - return this._channel.call('$freePortKillProcess', [id, port]); + freePortKillProcess(port: string): Promise<{ port: string; processId: string }> { + return this._channel.call('$freePortKillProcess', [port]); } installAutoReply(match: string, reply: string): Promise { return this._channel.call('$installAutoReply', [match, reply]); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index dea8aba884e..c8379fe51c8 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -80,7 +80,7 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { if (!this._localPtyService.freePortKillProcess) { throw new Error('freePortKillProcess does not exist on the local pty service'); } - return this._localPtyService.freePortKillProcess(this.id, port); + return this._localPtyService.freePortKillProcess(port); } async getInitialCwd(): Promise { return this._properties.initialCwd; From e42366e69eb3742793db422d6631356cb18c89e5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 16:21:27 +0200 Subject: [PATCH 360/599] #155990 add more logging (#162837) --- .../userDataSync/common/extensionsMerge.ts | 2 +- .../browser/webExtensionsScannerService.ts | 55 ++++++++++--------- .../common/webExtensionManagementService.ts | 2 +- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/vs/platform/userDataSync/common/extensionsMerge.ts b/src/vs/platform/userDataSync/common/extensionsMerge.ts index 6c046e61e8d..1b93b734b38 100644 --- a/src/vs/platform/userDataSync/common/extensionsMerge.ts +++ b/src/vs/platform/userDataSync/common/extensionsMerge.ts @@ -179,7 +179,7 @@ export function merge(localExtensions: ISyncExtensionWithVersion[], remoteExtens newRemoteExtensionsMap.set(key, merge(key, localExtension, remoteExtension, localExtension)); } - // Locally removed extensions => exist in base and does not exit in local + // Locally removed extensions => exist in base and does not exist in local for (const key of baseToLocal.removed.values()) { // If updated in remote (already handled) if (baseToRemote.updated.has(key)) { diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index cfde0bbd984..bc0c3415950 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -137,6 +137,12 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten if (extensions.length) { extensions = await this.checkAdditionalBuiltinExtensions(extensions); } + if (extensions.length) { + this.logService.info('Found additional builtin gallery extensions in env', extensions); + } + if (extensionLocations.length) { + this.logService.info('Found additional builtin location extensions in env', extensionLocations.map(e => e.toString())); + } return { extensions, extensionsToMigrate, extensionLocations }; })(); } @@ -209,6 +215,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten const extension = await this.toScannedExtension(webExtension, true); if (extension.isValid || !scanOptions?.skipInvalidExtensions) { result.push(extension); + } else { + this.logService.info(`Skipping invalid additional builtin extension ${webExtension.identifier.id}`); } } catch (error) { this.logService.info(`Error while fetching the additional builtin extension ${location.toString()}.`, getErrorMessage(error)); @@ -218,15 +226,12 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } private async getCustomBuiltinExtensionsFromGallery(scanOptions?: ScanOptions): Promise { - const { extensions } = await this.readCustomBuiltinExtensionsInfoFromEnv(); - if (!extensions.length) { - return []; - } if (!this.galleryService.isEnabled()) { this.logService.info('Ignoring fetching additional builtin extensions from gallery as it is disabled.'); return []; } const result: IScannedExtension[] = []; + const { extensions } = await this.readCustomBuiltinExtensionsInfoFromEnv(); try { const useCache = this.storageService.get('additionalBuiltinExtensions', StorageScope.APPLICATION, '[]') === JSON.stringify(extensions); const webExtensions = await (useCache ? this.getCustomBuiltinExtensionsFromCache() : this.updateCustomBuiltinExtensionsCache()); @@ -236,6 +241,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten const extension = await this.toScannedExtension(webExtension, true); if (extension.isValid || !scanOptions?.skipInvalidExtensions) { result.push(extension); + } else { + this.logService.info(`Skipping invalid additional builtin gallery extension ${webExtension.identifier.id}`); } } catch (error) { this.logService.info(`Ignoring additional builtin extension ${webExtension.identifier.id} because there is an error while converting it into scanned extension`, getErrorMessage(error)); @@ -318,31 +325,23 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten private async updateCustomBuiltinExtensionsCache(): Promise { if (!this._updateCustomBuiltinExtensionsCachePromise) { this._updateCustomBuiltinExtensionsCachePromise = (async () => { - // Clear Cache - await this.writeCustomBuiltinExtensionsCache(() => []); - - const { extensions } = await this.readCustomBuiltinExtensionsInfoFromEnv(); - - if (!extensions.length) { - return []; - } - - const galleryExtensionsMap = await this.getExtensionsWithDependenciesAndPackedExtensions(extensions); - - const missingExtensions = extensions.filter(({ id }) => !galleryExtensionsMap.has(id.toLowerCase())); - if (missingExtensions.length) { - this.logService.info('Skipping the additional builtin extensions because their compatible versions are not found.', missingExtensions); - } - + this.logService.info('Updating additional builtin extensions cache'); const webExtensions: IWebExtension[] = []; - await Promise.all([...galleryExtensionsMap.values()].map(async gallery => { - try { - webExtensions.push(await this.toWebExtensionFromGallery(gallery, { isPreReleaseVersion: gallery.properties.isPreReleaseVersion, preRelease: gallery.properties.isPreReleaseVersion, isBuiltin: true })); - } catch (error) { - this.logService.info(`Ignoring additional builtin extension ${gallery.identifier.id} because there is an error while converting it into web extension`, getErrorMessage(error)); + const { extensions } = await this.readCustomBuiltinExtensionsInfoFromEnv(); + if (extensions.length) { + const galleryExtensionsMap = await this.getExtensionsWithDependenciesAndPackedExtensions(extensions); + const missingExtensions = extensions.filter(({ id }) => !galleryExtensionsMap.has(id.toLowerCase())); + if (missingExtensions.length) { + this.logService.info('Skipping the additional builtin extensions because their compatible versions are not found.', missingExtensions); } - })); - + await Promise.all([...galleryExtensionsMap.values()].map(async gallery => { + try { + webExtensions.push(await this.toWebExtensionFromGallery(gallery, { isPreReleaseVersion: gallery.properties.isPreReleaseVersion, preRelease: gallery.properties.isPreReleaseVersion, isBuiltin: true })); + } catch (error) { + this.logService.info(`Ignoring additional builtin extension ${gallery.identifier.id} because there is an error while converting it into web extension`, getErrorMessage(error)); + } + })); + } await this.writeCustomBuiltinExtensionsCache(() => webExtensions); return webExtensions; })(); @@ -534,6 +533,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten const extension = await this.toScannedExtension(webExtension, false); if (extension.isValid || !scanOptions?.skipInvalidExtensions) { result.set(extension.identifier.id.toLowerCase(), extension); + } else { + this.logService.info(`Skipping invalid installed extension ${webExtension.identifier.id}`); } } return [...result.values()]; diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index a0e3bcd903e..47c2436709c 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -93,7 +93,7 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe const userExtensions = await this.webExtensionsScannerService.scanUserExtensions(profileLocation ?? this.userDataProfileService.currentProfile.extensionsResource); extensions.push(...userExtensions); } - return Promise.all(extensions.map(e => toLocalExtension(e))); + return extensions.map(e => toLocalExtension(e)); } async install(location: URI, options: InstallOptions = {}): Promise { From a8772add23122b5139aebb9433f85105bb502162 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 16:45:41 +0200 Subject: [PATCH 361/599] Fix #162333 (#162843) --- .../browser/parts/activitybar/media/activityaction.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index a7b7e543420..62447ad2ad4 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -190,7 +190,7 @@ /* Right aligned */ -.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) { +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon):not(.profile-activity-item) { margin-left: 0; padding: 0 48px 0 0; background-position: calc(100% - 9px) center; From 159f94009bccf1f785032ff23cd1e5deadcd8af4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 16:57:08 +0200 Subject: [PATCH 362/599] Fix #162652 (#162845) --- .../workbench/contrib/extensions/browser/extensionsViewlet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index b986e34b545..06690aa5f9e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -812,13 +812,13 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution if (newBadgeNumber > 0) { let msg = ''; if (outdated) { - msg += outdated === 1 ? localize('extensionToUpdate', '{0} Extension requires update', outdated) : localize('extensionsToUpdate', '{0} Extensions require update', outdated); + msg += outdated === 1 ? localize('extensionToUpdate', '{0} requires update', outdated) : localize('extensionsToUpdate', '{0} require update', outdated); } if (outdated > 0 && extensionsReloadRequired.length > 0) { msg += ', '; } if (extensionsReloadRequired.length) { - msg += extensionsReloadRequired.length === 1 ? localize('extensionToReload', '{0} Extension requires reload', extensionsReloadRequired.length) : localize('extensionsToReload', '{0} Extensions require reload', extensionsReloadRequired.length); + msg += extensionsReloadRequired.length === 1 ? localize('extensionToReload', '{0} requires reload', extensionsReloadRequired.length) : localize('extensionsToReload', '{0} require reload', extensionsReloadRequired.length); } const badge = new NumberBadge(newBadgeNumber, () => msg); this.badgeHandle.value = this.activityService.showViewContainerActivity(VIEWLET_ID, { badge, clazz: 'extensions-badge count-badge' }); From e1244bacd8a20b55a6b3d5626d71802e50442a20 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 6 Oct 2022 08:00:38 -0700 Subject: [PATCH 363/599] Allow separators to have buttons (#162798) --- .../parts/quickinput/browser/quickInput.ts | 10 +- .../quickinput/browser/quickInputList.ts | 192 +++++++++++------- .../parts/quickinput/common/quickInput.ts | 11 + 3 files changed, 143 insertions(+), 70 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index ec55bbc810b..dcf07adcf63 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -29,7 +29,7 @@ import { isIOS } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { isString, withNullAsUndefined } from 'vs/base/common/types'; import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils'; -import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickInputHideEvent, IQuickInputToggle, IQuickNavigateConfiguration, IQuickPick, IQuickPickDidAcceptEvent, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickWillAcceptEvent, ItemActivation, NO_KEY_MODS, QuickInputHideReason, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput'; +import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickInputHideEvent, IQuickInputToggle, IQuickNavigateConfiguration, IQuickPick, IQuickPickDidAcceptEvent, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickSeparatorButtonEvent, IQuickPickWillAcceptEvent, ItemActivation, NO_KEY_MODS, QuickInputHideReason, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput'; import 'vs/css!./media/quickInput'; import { localize } from 'vs/nls'; import { QuickInputBox } from './quickInputBox'; @@ -465,6 +465,7 @@ class QuickPick extends QuickInput implements IQuickPi private selectedItemsToConfirm: T[] | null = []; private readonly onDidChangeSelectionEmitter = this._register(new Emitter()); private readonly onDidTriggerItemButtonEmitter = this._register(new Emitter>()); + private readonly onDidTriggerSeparatorButtonEmitter = this._register(new Emitter()); private _valueSelection: Readonly<[number, number]> | undefined; private valueSelectionUpdated = true; private _ok: boolean | 'default' = 'default'; @@ -753,6 +754,8 @@ class QuickPick extends QuickInput implements IQuickPi onDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event; + onDidTriggerSeparatorButton = this.onDidTriggerSeparatorButtonEmitter.event; + private trySelectFirst() { if (this.autoFocusOnList) { if (!this.canSelectMany) { @@ -892,6 +895,7 @@ class QuickPick extends QuickInput implements IQuickPi this.onDidChangeSelectionEmitter.fire(checkedItems as T[]); })); this.visibleDisposables.add(this.ui.list.onButtonTriggered(event => this.onDidTriggerItemButtonEmitter.fire(event as IQuickPickItemButtonEvent))); + this.visibleDisposables.add(this.ui.list.onSeparatorButtonTriggered(event => this.onDidTriggerSeparatorButtonEmitter.fire(event))); this.visibleDisposables.add(this.registerQuickNavigation()); this.valueSelectionUpdated = true; } @@ -1484,6 +1488,7 @@ export class QuickInputController extends Disposable { } } })), + input.onDidTriggerSeparatorButton(event => options.onDidTriggerSeparatorButton?.(event)), input.onDidChangeValue(value => { if (activeItem && !value && (input.activeItems.length !== 1 || input.activeItems[0] !== activeItem)) { input.activeItems = [activeItem]; @@ -1828,6 +1833,9 @@ export class QuickInputController extends Disposable { if (this.styles.list.pickerGroupForeground) { content.push(`.quick-input-list .quick-input-list-separator { color: ${this.styles.list.pickerGroupForeground}; }`); } + if (this.styles.list.pickerGroupForeground) { + content.push(`.quick-input-list .quick-input-list-separator-as-item { color: ${this.styles.list.pickerGroupForeground}; }`); + } if ( this.styles.keybindingLabel.keybindingLabelBackground || diff --git a/src/vs/base/parts/quickinput/browser/quickInputList.ts b/src/vs/base/parts/quickinput/browser/quickInputList.ts index 25058c9de25..ba66b6e4afa 100644 --- a/src/vs/base/parts/quickinput/browser/quickInputList.ts +++ b/src/vs/base/parts/quickinput/browser/quickInputList.ts @@ -25,7 +25,7 @@ import { ltrim } from 'vs/base/common/strings'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput'; import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils'; -import { QuickPickItem, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/base/parts/quickinput/common/quickInput'; +import { QuickPickItem, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickSeparatorButtonEvent } from 'vs/base/parts/quickinput/common/quickInput'; import 'vs/css!./media/quickInput'; import { localize } from 'vs/nls'; @@ -34,7 +34,7 @@ const $ = dom.$; interface IListElement { readonly hasCheckbox: boolean; readonly index: number; - readonly item: IQuickPickItem; + readonly item?: IQuickPickItem; readonly saneLabel: string; readonly saneSortLabel: string; readonly saneMeta?: string; @@ -47,12 +47,13 @@ interface IListElement { readonly checked: boolean; readonly separator?: IQuickPickSeparator; readonly fireButtonTriggered: (event: IQuickPickItemButtonEvent) => void; + readonly fireSeparatorButtonTriggered: (event: IQuickPickSeparatorButtonEvent) => void; } class ListElement implements IListElement, IDisposable { hasCheckbox!: boolean; index!: number; - item!: IQuickPickItem; + item?: IQuickPickItem; saneLabel!: string; saneSortLabel!: string; saneMeta!: string; @@ -77,6 +78,7 @@ class ListElement implements IListElement, IDisposable { descriptionHighlights?: IMatch[]; detailHighlights?: IMatch[]; fireButtonTriggered!: (event: IQuickPickItemButtonEvent) => void; + fireSeparatorButtonTriggered!: (event: IQuickPickSeparatorButtonEvent) => void; constructor(init: IListElement) { Object.assign(this, init); @@ -158,6 +160,8 @@ class ListElementRenderer implements IListRenderer data.checkbox.checked = checked)); @@ -168,13 +172,18 @@ class ListElementRenderer implements IListRenderer { let cssClasses = button.iconClass || (button.iconPath ? getIconClass(button.iconPath) : undefined); @@ -203,10 +215,15 @@ class ListElementRenderer implements IListRenderer { - element.fireButtonTriggered({ - button, - item: element.item - }); + mainItem.type !== 'separator' + ? element.fireButtonTriggered({ + button, + item: mainItem + }) + : element.fireSeparatorButtonTriggered({ + button, + separator: mainItem + }); }); action.tooltip = button.tooltip || ''; return action; @@ -230,6 +247,10 @@ class ListElementRenderer implements IListRenderer { getHeight(element: ListElement): number { + if (!element.item) { + // must be a separator + return 24; + } return element.saneDetail ? 44 : 22; } @@ -255,7 +276,7 @@ export class QuickInputList { private list: List; private inputElements: Array = []; private elements: ListElement[] = []; - private elementsToIndexes = new Map(); + private elementsToIndexes = new Map(); matchOnDescription = false; matchOnDetail = false; matchOnLabel = true; @@ -272,6 +293,8 @@ export class QuickInputList { onChangedCheckedElements: Event = this._onChangedCheckedElements.event; private readonly _onButtonTriggered = new Emitter>(); onButtonTriggered = this._onButtonTriggered.event; + private readonly _onSeparatorButtonTriggered = new Emitter(); + onSeparatorButtonTriggered = this._onSeparatorButtonTriggered.event; private readonly _onKeyDown = new Emitter(); onKeyDown: Event = this._onKeyDown.event; private readonly _onLeave = new Emitter(); @@ -359,6 +382,7 @@ export class QuickInputList { this._onChangedVisibleCount, this._onChangedCheckedElements, this._onButtonTriggered, + this._onSeparatorButtonTriggered, this._onLeave, this._onKeyDown ); @@ -439,48 +463,67 @@ export class QuickInputList { setElements(inputElements: Array): void { this.elementDisposables = dispose(this.elementDisposables); const fireButtonTriggered = (event: IQuickPickItemButtonEvent) => this.fireButtonTriggered(event); + const fireSeparatorButtonTriggered = (event: IQuickPickSeparatorButtonEvent) => this.fireSeparatorButtonTriggered(event); this.inputElements = inputElements; this.elements = inputElements.reduce((result, item, index) => { - if (item.type !== 'separator') { - const previous = index && inputElements[index - 1]; - const saneLabel = item.label && item.label.replace(/\r?\n/g, ' '); - const saneSortLabel = parseLabelWithIcons(saneLabel).text.trim(); - const saneMeta = item.meta && item.meta.replace(/\r?\n/g, ' '); - const saneDescription = item.description && item.description.replace(/\r?\n/g, ' '); - const saneDetail = item.detail && item.detail.replace(/\r?\n/g, ' '); - const saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail] - .map(s => getCodiconAriaLabel(s)) - .filter(s => !!s) - .join(', '); + const previous = index && inputElements[index - 1]; + const saneLabel = item.label ? item.label.replace(/\r?\n/g, ' ') : ''; + const saneSortLabel = parseLabelWithIcons(saneLabel).text.trim(); - const hasCheckbox = this.parent.classList.contains('show-checkboxes'); - result.push(new ListElement({ - hasCheckbox, - index, - item, - saneLabel, - saneSortLabel, - saneMeta, - saneAriaLabel, - saneDescription, - saneDetail, - labelHighlights: item.highlights?.label, - descriptionHighlights: item.highlights?.description, - detailHighlights: item.highlights?.detail, - checked: false, - separator: previous && previous.type === 'separator' ? previous : undefined, - fireButtonTriggered - })); + let saneMeta, saneDescription, saneDetail, labelHighlights, descriptionHighlights, detailHighlights; + if (item.type !== 'separator') { + saneMeta = item.meta && item.meta.replace(/\r?\n/g, ' '); + saneDescription = item.description && item.description.replace(/\r?\n/g, ' '); + saneDetail = item.detail && item.detail.replace(/\r?\n/g, ' '); + labelHighlights = item.highlights?.label; + descriptionHighlights = item.highlights?.description; + detailHighlights = item.highlights?.detail; } + const saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail] + .map(s => getCodiconAriaLabel(s)) + .filter(s => !!s) + .join(', '); + + const hasCheckbox = this.parent.classList.contains('show-checkboxes'); + + let separator: IQuickPickSeparator | undefined; + if (item.type === 'separator') { + if (!item.buttons) { + // This separator will be rendered as a part of the list item + return result; + } + separator = item; + } else if (previous && previous.type === 'separator' && !previous.buttons) { + separator = previous; + } + + result.push(new ListElement({ + hasCheckbox, + index, + item: item.type !== 'separator' ? item : undefined, + saneLabel, + saneSortLabel, + saneMeta, + saneAriaLabel, + saneDescription, + saneDetail, + labelHighlights, + descriptionHighlights, + detailHighlights, + checked: false, + separator, + fireButtonTriggered, + fireSeparatorButtonTriggered + })); return result; }, [] as ListElement[]); this.elementDisposables.push(...this.elements); this.elementDisposables.push(...this.elements.map(element => element.onChecked(() => this.fireCheckedEvents()))); this.elementsToIndexes = this.elements.reduce((map, element, index) => { - map.set(element.item, index); + map.set(element.item ?? element.separator!, index); return map; - }, new Map()); + }, new Map()); this.list.splice(0, this.list.length); // Clear focus and selection first, sending the events when the list is empty. this.list.splice(0, this.list.length, this.elements); this._onChangedVisibleCount.fire(this.elements.length); @@ -524,7 +567,8 @@ export class QuickInputList { getCheckedElements() { return this.elements.filter(e => e.checked) - .map(e => e.item); + .map(e => e.item) + .filter(e => !!e) as IQuickPickItem[]; } setCheckedElements(items: IQuickPickItem[]) { @@ -552,39 +596,44 @@ export class QuickInputList { return; } - if (what === QuickInputListFocus.Next && this.list.getFocus()[0] === this.list.length - 1) { - what = QuickInputListFocus.First; - } - - if (what === QuickInputListFocus.Previous && this.list.getFocus()[0] === 0) { - what = QuickInputListFocus.Last; - } - if (what === QuickInputListFocus.Second && this.list.length < 2) { what = QuickInputListFocus.First; } switch (what) { case QuickInputListFocus.First: - this.list.focusFirst(); + this.list.scrollTop = 0; + this.list.focusFirst(undefined, (e) => !!e.item); break; case QuickInputListFocus.Second: - this.list.focusNth(1); + this.list.scrollTop = 0; + this.list.focusNth(1, undefined, (e) => !!e.item); break; case QuickInputListFocus.Last: - this.list.focusLast(); + this.list.scrollTop = this.list.scrollHeight; + this.list.focusLast(undefined, (e) => !!e.item); break; - case QuickInputListFocus.Next: - this.list.focusNext(); + case QuickInputListFocus.Next: { + this.list.focusNext(undefined, true, undefined, (e) => !!e.item); + const index = this.list.getFocus()[0]; + if (index !== 0 && !this.elements[index - 1].item && this.list.firstVisibleIndex > index - 1) { + this.list.reveal(index - 1); + } break; - case QuickInputListFocus.Previous: - this.list.focusPrevious(); + } + case QuickInputListFocus.Previous: { + this.list.focusPrevious(undefined, true, undefined, (e) => !!e.item); + const index = this.list.getFocus()[0]; + if (index !== 0 && !this.elements[index - 1].item && this.list.firstVisibleIndex > index - 1) { + this.list.reveal(index - 1); + } break; + } case QuickInputListFocus.NextPage: - this.list.focusNextPage(); + this.list.focusNextPage(undefined, (e) => !!e.item); break; case QuickInputListFocus.PreviousPage: - this.list.focusPreviousPage(); + this.list.focusPreviousPage(undefined, (e) => !!e.item); break; } @@ -624,7 +673,9 @@ export class QuickInputList { element.detailHighlights = undefined; element.hidden = false; const previous = element.index && this.inputElements[element.index - 1]; - element.separator = previous && previous.type === 'separator' ? previous : undefined; + if (element.item) { + element.separator = previous && previous.type === 'separator' && !previous.buttons ? previous : undefined; + } }); } @@ -651,9 +702,8 @@ export class QuickInputList { element.labelHighlights = undefined; element.descriptionHighlights = undefined; element.detailHighlights = undefined; - element.hidden = !element.item.alwaysShow; + element.hidden = element.item ? !element.item.alwaysShow : true; } - element.separator = undefined; // we can show the separator unless the list gets sorted by match if (!this.sortByLabel) { @@ -678,9 +728,9 @@ export class QuickInputList { } this.elementsToIndexes = shownElements.reduce((map, element, index) => { - map.set(element.item, index); + map.set(element.item ?? element.separator!, index); return map; - }, new Map()); + }, new Map()); this.list.splice(0, this.list.length, shownElements); this.list.setFocus([]); this.list.layout(); @@ -730,6 +780,10 @@ export class QuickInputList { this._onButtonTriggered.fire(event); } + private fireSeparatorButtonTriggered(event: IQuickPickSeparatorButtonEvent) { + this._onSeparatorButtonTriggered.fire(event); + } + style(styles: IListStyles) { this.list.style(styles); } diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index f86a4c00817..ef88ef4eb4c 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -45,7 +45,10 @@ export interface IQuickPickItem { export interface IQuickPickSeparator { type: 'separator'; + id?: string; label?: string; + ariaLabel?: string; + buttons?: IQuickInputButton[]; } export interface IKeyMods { @@ -126,6 +129,7 @@ export interface IPickOptions { onKeyMods?: (keyMods: IKeyMods) => void; onDidFocus?: (entry: T) => void; onDidTriggerItemButton?: (context: IQuickPickItemButtonContext) => void; + onDidTriggerSeparatorButton?: (context: IQuickPickSeparatorButtonEvent) => void; } export interface IInputOptions { @@ -284,6 +288,8 @@ export interface IQuickPick extends IQuickInput { readonly onDidTriggerItemButton: Event>; + readonly onDidTriggerSeparatorButton: Event; + items: ReadonlyArray; canSelectMany: boolean; @@ -428,6 +434,11 @@ export interface IQuickPickItemButtonEvent { item: T; } +export interface IQuickPickSeparatorButtonEvent { + button: IQuickInputButton; + separator: IQuickPickSeparator; +} + export interface IQuickPickItemButtonContext extends IQuickPickItemButtonEvent { removeItem(): void; } From b1c1b3bd3be77d38f65950b1da3a87cc3fcf08a1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 17:09:40 +0200 Subject: [PATCH 364/599] Fix #162651 (#162848) --- src/vs/platform/extensions/common/extensions.ts | 1 + .../contrib/extensions/browser/extensionsWorkbenchService.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 267435d090a..1fb311969e8 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -268,6 +268,7 @@ export interface IRelaxedExtensionManifest { description?: string; main?: string; browser?: string; + preview?: boolean; // For now this only supports pointing to l10n bundle files // but it will be used for package.l10n.json files in the future l10n?: string; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 542534bada3..4c769923ad1 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -275,7 +275,7 @@ export class Extension implements IExtension { } get preview(): boolean { - return this.gallery ? this.gallery.preview : false; + return this.local?.manifest.preview ?? this.gallery?.preview ?? false; } get hasPreReleaseVersion(): boolean { From 1b8711a96b348fc22ad87644963c6e2aab4449ff Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 08:17:17 -0700 Subject: [PATCH 365/599] Include args in fixed git similar command Fixes #162841 --- .../terminal/browser/terminalQuickFixBuiltinActions.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 24cd302cf34..0cf63953bcf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -33,10 +33,6 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { if (!matchResult?.outputMatch) { return; } - // const fixedCommand = matchResult?.outputMatch?.[1]; - // if (!fixedCommand) { - // return; - // } const actions: TerminalQuickFixAction[] = []; const results = matchResult.outputMatch[0].split('\n').map(r => r.trim()); for (let i = 1; i < results.length; i++) { @@ -44,7 +40,7 @@ export function gitSimilarCommand(): ITerminalQuickFixOptions { if (fixedCommand) { actions.push({ type: 'command', - command: `git ${fixedCommand}`, + command: command.command.replace(/git\s+[^\s]+/, `git ${fixedCommand}`), addNewLine: true }); } From 643271a4872a41127d89243056ac4643c899cdca Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 08:19:37 -0700 Subject: [PATCH 366/599] Add test for passing args through --- .../terminal/test/browser/quickFixAddon.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 2b6d1203265..f9fb3a9cb36 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -23,7 +23,7 @@ import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/termi import { URI } from 'vs/base/common/uri'; import { Terminal } from 'xterm'; -suite('QuickFixAddon', () => { +suite.only('QuickFixAddon', () => { let quickFixAddon: TerminalQuickFixAddon; let terminalInstance: Pick; let commandDetection: CommandDetectionCapability; @@ -112,6 +112,19 @@ suite('QuickFixAddon', () => { }]; assertMatchOptions(getQuickFixes(createCommand('git pu', output, GitSimilarOutputRegex), expectedMap, openerService), actions); }); + test('passes any arguments through', () => { + output = `git: 'checkoutt' is not a git command. See 'git --help'. + + The most similar commands are + checkout`; + assertMatchOptions(getQuickFixes(createCommand('git checkoutt .', output, GitSimilarOutputRegex), expectedMap, openerService), [{ + id: `quickFix.command`, + enabled: true, + label: 'Run: git checkout .', + tooltip: 'Run: git checkout .', + command: 'git checkout .' + }]); + }); }); }); suite('gitTwoDashes', async () => { From c153237d7468d276d2db6e87c4213f78a33b3e76 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 08:30:18 -0700 Subject: [PATCH 367/599] Document remaining ITerminalInstance methods Fixes #162840 --- .../contrib/terminal/browser/terminal.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 61088d6dbf6..72a9442fd5f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -585,10 +585,23 @@ export interface ITerminalInstance { onDidFocusFindWidget: Event; + /** + * The exit code if the terminal process has exited, this will be undefined if the process has + * not yet exited or the exit code could not be determined. Use {@link exitReason} to see + * whether the process has exited. + */ readonly exitCode: number | undefined; + /** + * The reason the terminal process exited, this will be undefined if the process is still + * running. + */ readonly exitReason: TerminalExitReason | undefined; + /** + * Whether links in the terminal are ready, links are available until after the process is + * ready. + */ readonly areLinksReady: boolean; /** @@ -649,11 +662,21 @@ export interface ITerminalInstance { */ disableLayout: boolean; + /** + * Access to the navigation mode accessibility feature. + */ readonly navigationMode: INavigationMode | undefined; + /** + * The description of the terminal, this is typically displayed next to {@link title}. + */ description: string | undefined; + /** + * The remote-aware $HOME directory (or Windows equivalent) of the terminal. + */ userHome: string | undefined; + /** * Shows the environment information hover if the widget exists. */ @@ -854,8 +877,14 @@ export interface ITerminalInstance { */ toggleSizeToContentWidth(): Promise; + /** + * Toggles escape sequence logging in the devtools console. + */ toggleEscapeSequenceLogging(): Promise; + /** + * Sets whether escape seqeunce logging is enabled in the devtools console. + */ setEscapeSequenceLogging(enable: boolean): void; /** @@ -915,6 +944,9 @@ export interface ITerminalInstance { */ registerQuickFixProvider(...options: ITerminalQuickFixOptions[]): void; + /** + * Attempts to detect and kill the process listening on specified port. + */ freePortKillProcess(port: string): Promise; } From aef171d27896f1624a7ee4e2c123820cecd81829 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2022 17:44:06 +0200 Subject: [PATCH 368/599] fix #161558 (#162574) * fix #161558 * fix tests --- .../common/extensionGalleryService.ts | 4 -- .../browser/extensions.contribution.ts | 3 +- .../extensions/browser/extensionsViewlet.ts | 6 +-- .../browser/extensionsWorkbenchService.ts | 41 ++++++++++--------- .../contrib/extensions/common/extensions.ts | 1 + .../extensionsActions.test.ts | 1 + .../electron-browser/extensionsViews.test.ts | 1 + .../extensionsWorkbenchService.test.ts | 1 + 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index e523486bdbd..e9a3651cb50 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -713,10 +713,6 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi } async query(options: IQueryOptions, token: CancellationToken): Promise> { - if (!this.isEnabled()) { - throw new Error('No extension gallery service configured.'); - } - let text = options.text || ''; const pageSize = options.pageSize ?? 50; diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index c00311ba0d7..f5bb723e3b7 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -13,7 +13,7 @@ import { EnablementState, IExtensionManagementServerService, IWorkbenchExtension import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, OUTDATED_EXTENSIONS_VIEW_ID } from 'vs/workbench/contrib/extensions/common/extensions'; +import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, OUTDATED_EXTENSIONS_VIEW_ID, CONTEXT_HAS_GALLERY } from 'vs/workbench/contrib/extensions/common/extensions'; import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, SetColorThemeAction, SetFileIconThemeAction, SetProductIconThemeAction, ClearLanguageAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; @@ -434,7 +434,6 @@ overrideActionForActiveExtensionEditorWebview(CutAction, webview => webview.cut( overrideActionForActiveExtensionEditorWebview(PasteAction, webview => webview.paste()); // Contexts -export const CONTEXT_HAS_GALLERY = new RawContextKey('hasGallery', false); export const CONTEXT_HAS_LOCAL_SERVER = new RawContextKey('hasLocalServer', false); export const CONTEXT_HAS_REMOTE_SERVER = new RawContextKey('hasRemoteServer', false); export const CONTEXT_HAS_WEB_SERVER = new RawContextKey('hasWebServer', false); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 06690aa5f9e..20ca6f57e8f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -16,7 +16,7 @@ import { append, $, Dimension, hide, show, DragAndDropObserver } from 'vs/base/b import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, CloseExtensionDetailsOnViewChangeKey, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, AutoCheckUpdatesConfigurationKey, OUTDATED_EXTENSIONS_VIEW_ID } from '../common/extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, CloseExtensionDetailsOnViewChangeKey, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, WORKSPACE_RECOMMENDATIONS_VIEW_ID, AutoCheckUpdatesConfigurationKey, OUTDATED_EXTENSIONS_VIEW_ID, CONTEXT_HAS_GALLERY } from '../common/extensions'; import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -212,7 +212,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id: 'workbench.views.extensions.popular', name: localize('popularExtensions', "Popular"), ctorDescriptor: new SyncDescriptor(DefaultPopularExtensionsView, [{ hideBadge: true }]), - when: ContextKeyExpr.and(DefaultViewsContext, ContextKeyExpr.not('hasInstalledExtensions')), + when: ContextKeyExpr.and(DefaultViewsContext, ContextKeyExpr.not('hasInstalledExtensions'), CONTEXT_HAS_GALLERY), weight: 60, order: 2, canToggleVisibility: false @@ -227,7 +227,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id: 'extensions.recommendedList', name: localize('recommendedExtensions', "Recommended"), ctorDescriptor: new SyncDescriptor(DefaultRecommendedExtensionsView, [{ flexibleHeight: true }]), - when: ContextKeyExpr.and(DefaultViewsContext, SortByUpdateDateContext.negate(), ContextKeyExpr.not('config.extensions.showRecommendationsOnlyOnDemand')), + when: ContextKeyExpr.and(DefaultViewsContext, SortByUpdateDateContext.negate(), ContextKeyExpr.not('config.extensions.showRecommendationsOnlyOnDemand'), CONTEXT_HAS_GALLERY), weight: 40, order: 3, canToggleVisibility: true diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 4c769923ad1..49f40c5807f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -894,38 +894,38 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension queryGallery(token: CancellationToken): Promise>; queryGallery(options: IQueryOptions, token: CancellationToken): Promise>; async queryGallery(arg1: any, arg2?: any): Promise> { + if (!this.galleryService.isEnabled()) { + return singlePagePager([]); + } + const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1; const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2; options.text = options.text ? this.resolveQueryText(options.text) : options.text; options.includePreRelease = isUndefined(options.includePreRelease) ? this.preferPreReleases : options.includePreRelease; const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest(); - try { - const pager = await this.galleryService.query(options, token); - this.syncInstalledExtensionsWithGallery(pager.firstPage); - return { - firstPage: pager.firstPage.map(gallery => this.fromGallery(gallery, extensionsControlManifest)), - total: pager.total, - pageSize: pager.pageSize, - getPage: async (pageIndex, token) => { - const page = await pager.getPage(pageIndex, token); - this.syncInstalledExtensionsWithGallery(page); - return page.map(gallery => this.fromGallery(gallery, extensionsControlManifest)); - } - }; - } catch (error) { - if (/No extension gallery service configured/.test(error.message)) { - return Promise.resolve(singlePagePager([])); + const pager = await this.galleryService.query(options, token); + this.syncInstalledExtensionsWithGallery(pager.firstPage); + return { + firstPage: pager.firstPage.map(gallery => this.fromGallery(gallery, extensionsControlManifest)), + total: pager.total, + pageSize: pager.pageSize, + getPage: async (pageIndex, token) => { + const page = await pager.getPage(pageIndex, token); + this.syncInstalledExtensionsWithGallery(page); + return page.map(gallery => this.fromGallery(gallery, extensionsControlManifest)); } - throw error; - } + }; } getExtensions(extensionInfos: IExtensionInfo[], token: CancellationToken): Promise; getExtensions(extensionInfos: IExtensionInfo[], options: IExtensionQueryOptions, token: CancellationToken): Promise; async getExtensions(extensionInfos: IExtensionInfo[], arg1: any, arg2?: any): Promise { - extensionInfos.forEach(e => e.preRelease = e.preRelease ?? this.preferPreReleases); + if (!this.galleryService.isEnabled()) { + return []; + } + extensionInfos.forEach(e => e.preRelease = e.preRelease ?? this.preferPreReleases); const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest(); const galleryExtensions = await this.galleryService.getExtensions(extensionInfos, arg1, arg2); this.syncInstalledExtensionsWithGallery(galleryExtensions); @@ -1215,6 +1215,9 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } async checkForUpdates(onlyBuiltin?: boolean): Promise { + if (!this.galleryService.isEnabled()) { + return; + } const extensions: Extensions[] = []; if (this.localExtensions) { extensions.push(this.localExtensions); diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index e01cdeee918..9b0e6b6afc2 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -192,6 +192,7 @@ export const LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID = 'workbench.exten // Context Keys export const HasOutdatedExtensionsContext = new RawContextKey('hasOutdatedExtensions', false); +export const CONTEXT_HAS_GALLERY = new RawContextKey('hasGallery', false); // Context Menu Groups export const THEME_ACTIONS_GROUP = '_theme_'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 4b6b310e139..fc6df1e1d1a 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -136,6 +136,7 @@ function setupTest() { instantiationService.stub(IExtensionRecommendationsService, {}); instantiationService.stub(IURLService, NativeURLService); + instantiationService.stub(IExtensionGalleryService, 'isEnabled', true); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', []); instantiationService.stub(IExtensionService, >{ extensions: [], onDidChangeExtensions: Event.None, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false, whenInstalledExtensionsRegistered: () => Promise.resolve(true) }); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index e85ca87d7cd..ef14de7b97c 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -169,6 +169,7 @@ suite('ExtensionsViews Tests', () => { setup(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localEnabledTheme, localEnabledLanguage, localRandom, localDisabledTheme, localDisabledLanguage, builtInTheme, builtInBasic]); instantiationService.stubPromise(IExtensionManagementService, 'getExtensgetExtensionsControlManifestionsReport', {}); + instantiationService.stub(IExtensionGalleryService, 'isEnabled', true); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(galleryEnabledLanguage)); instantiationService.stubPromise(IExtensionGalleryService, 'getCompatibleExtension', galleryEnabledLanguage); instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', [galleryEnabledLanguage]); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index f862b70fb53..d3fa2255b1b 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -132,6 +132,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { setup(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stub(IExtensionGalleryService, 'isEnabled', true); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); instantiationService.stubPromise(IExtensionGalleryService, 'getExtensions', []); instantiationService.stubPromise(INotificationService, 'prompt', 0); From 66fdc1fdbee7ecc2bbe1a4eee4d6ac9b2fd27359 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 08:57:00 -0700 Subject: [PATCH 369/599] Update src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts Co-authored-by: Megan Rogge --- .../contrib/terminal/test/browser/quickFixAddon.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index f9fb3a9cb36..3e4fb039e8d 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -23,7 +23,7 @@ import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/termi import { URI } from 'vs/base/common/uri'; import { Terminal } from 'xterm'; -suite.only('QuickFixAddon', () => { +suite('QuickFixAddon', () => { let quickFixAddon: TerminalQuickFixAddon; let terminalInstance: Pick; let commandDetection: CommandDetectionCapability; From 2ac0bef53cf7513e06666c124829b3581ebdee9a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 09:07:24 -0700 Subject: [PATCH 370/599] Update src/vs/workbench/contrib/terminal/browser/terminal.ts Co-authored-by: Megan Rogge --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 72a9442fd5f..b0fb9f7f96d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -586,9 +586,9 @@ export interface ITerminalInstance { onDidFocusFindWidget: Event; /** - * The exit code if the terminal process has exited, this will be undefined if the process has - * not yet exited or the exit code could not be determined. Use {@link exitReason} to see - * whether the process has exited. + * The exit code or undefined when the terminal process hasn't yet exited or + * the process exit code could not be determined. Use {@link exitReason} to see + * why the process has exited. */ readonly exitCode: number | undefined; From 30be36af5bbe4bbc5977fbf6afa34f1552eb5073 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 6 Oct 2022 09:16:38 -0700 Subject: [PATCH 371/599] clear quick fix decoration appropriately (#162701) --- .../contrib/terminal/browser/terminal.ts | 2 + .../terminal/browser/terminalInstance.ts | 19 ++- .../browser/terminalRunRecentQuickPick.ts | 17 +-- .../terminal/browser/xterm/quickFixAddon.ts | 128 +++++++++++------- .../test/browser/quickFixAddon.test.ts | 50 +++---- 5 files changed, 123 insertions(+), 93 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 61088d6dbf6..703668c435e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -777,6 +777,8 @@ export interface ITerminalInstance { */ sendPath(originalPath: string, addNewLine: boolean): Promise; + runCommand(command: string, addNewLine?: boolean): void; + /** * Takes a path and returns the properly escaped path to send to a given shell. On Windows, this * includes trying to prepare the path for WSL if needed. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index f067e4088f9..a0396c822cd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -10,7 +10,7 @@ import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { AutoOpenBarrier, Promises } from 'vs/base/common/async'; +import { AutoOpenBarrier, Promises, timeout } from 'vs/base/common/async'; import { Codicon } from 'vs/base/common/codicons'; import { debounce } from 'vs/base/common/decorators'; import { ErrorNoTelemetry } from 'vs/base/common/errors'; @@ -731,7 +731,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._quickFixAddon = this._scopedInstantiationService.createInstance(TerminalQuickFixAddon, this.capabilities); this.xterm?.raw.loadAddon(this._quickFixAddon); this.registerQuickFixProvider(gitSimilarCommand(), gitTwoDashes(), gitCreatePr(), gitPushSetUpstream(), freePort(this)); - this._register(this._quickFixAddon.onDidRequestRerunCommand((e) => this.sendText(e.command, e.addNewLine || false))); + this._register(this._quickFixAddon.onDidRequestRerunCommand(async (e) => await this.runCommand(e.command, e.addNewLine || false))); const lineDataEventAddon = new LineDataEventAddon(); this.xterm.raw.loadAddon(lineDataEventAddon); this.updateAccessibilitySupport(); @@ -820,6 +820,21 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return xterm; } + async runCommand(commandLine: string, addNewLine: boolean): Promise { + // Determine whether to send ETX (ctrl+c) before running the command. This should always + // happen unless command detection can reliably say that a command is being entered and + // there is no content in the prompt + if (this.capabilities.get(TerminalCapability.CommandDetection)?.hasInput !== false) { + await this.sendText('\x03', false); + // Wait a little before running the command to avoid the sequences being echoed while the ^C + // is being evaluated + await timeout(100); + } + // Use bracketed paste mode only when not running the command + await this.sendText(commandLine, addNewLine, !addNewLine); + } + + private _loadTypeAheadAddon(xterm: XtermTerminal): void { const enabled = this._configHelper.config.localEchoEnabled; const isRemote = !!this.remoteAuthority; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts index 207ea0f8ba3..e56f75730b1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts @@ -26,7 +26,6 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { showWithPinnedItems } from 'vs/platform/quickinput/browser/quickPickPin'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { timeout } from 'vs/base/common/async'; export async function showRunRecentQuickPick( accessor: ServicesAccessor, @@ -266,7 +265,7 @@ export async function showRunRecentQuickPick( text = result.rawLabel; } quickPick.hide(); - runCommand(instance, text, !quickPick.keyMods.alt); + instance.runCommand(text, !quickPick.keyMods.alt); if (quickPick.keyMods.alt) { instance.focus(); } @@ -284,20 +283,6 @@ export async function showRunRecentQuickPick( }); } -async function runCommand(instance: ITerminalInstance, commandLine: string, addNewLine: boolean): Promise { - // Determine whether to send ETX (ctrl+c) before running the command. This should always - // happen unless command detection can reliably say that a command is being entered and - // there is no content in the prompt - if (instance.capabilities.get(TerminalCapability.CommandDetection)?.hasInput !== false) { - await instance.sendText('\x03', false); - // Wait a little before running the command to avoid the sequences being echoed while the ^C - // is being evaluated - await timeout(100); - } - // Use bracketed paste mode only when not running the command - await instance.sendText(commandLine, addNewLine, !addNewLine); -} - class TerminalOutputProvider implements ITextModelContentProvider { static scheme = 'TERMINAL_OUTPUT'; diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts index a81d5608c54..44ce6c7858f 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/quickFixAddon.ts @@ -27,6 +27,8 @@ import { IDecoration, Terminal } from 'xterm'; // eslint-disable-next-line local/code-import-patterns import type { ITerminalAddon } from 'xterm-headless'; + +const quickFixSelectors = [DecorationSelector.QuickFix, DecorationSelector.LightBulb, DecorationSelector.Codicon, DecorationSelector.CommandDecoration, DecorationSelector.XtermDecoration]; export interface ITerminalQuickFix { showMenu(): void; /** @@ -46,10 +48,6 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, private _terminal: Terminal | undefined; - private _currentQuickFixElement: HTMLElement | undefined; - - private _decorationMarkerIds = new Set(); - private _commandListeners: Map = new Map(); private _quickFixes: IAction[] | undefined; @@ -69,22 +67,23 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, super(); const commandDetectionCapability = this._capabilities.get(TerminalCapability.CommandDetection); if (commandDetectionCapability) { - this._registerCommandFinishedHandler(); + this._registerCommandHandlers(); } else { this._capabilities.onDidAddCapability(c => { if (c === TerminalCapability.CommandDetection) { - this._registerCommandFinishedHandler(); + this._registerCommandHandlers(); } }); } this._terminalDecorationHoverService = instantiationService.createInstance(TerminalDecorationHoverManager); } + activate(terminal: Terminal): void { this._terminal = terminal; } showMenu(): void { - this._currentQuickFixElement?.click(); + this._decoration?.element?.click(); } registerCommandFinishedListener(options: ITerminalQuickFixOptions): void { @@ -94,86 +93,110 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, this._commandListeners.set(matcherKey, currentOptions); } - private _registerCommandFinishedHandler(): void { + private _registerCommandHandlers(): void { const terminal = this._terminal; const commandDetection = this._capabilities.get(TerminalCapability.CommandDetection); if (!terminal || !commandDetection) { return; } - this._register(commandDetection.onCommandExecuted(() => { - this._decoration?.dispose(); - this._decoration = undefined; - })); - this._register(commandDetection.onCommandFinished(async command => { - this._decoration?.dispose(); - this._decoration = undefined; - this._quickFixes = getQuickFixes(command, this._commandListeners, this._openerService, this._onDidRequestRerunCommand); - })); + this._register(commandDetection.onCommandFinished(command => this._resolveQuickFixes(command))); // The buffer is not ready by the time command finish - // is called. Add the decoration on command start using the actions, if any, - // from the last command + // is called. Add the decoration on command start if there are corresponding quick fixes this._register(commandDetection.onCommandStarted(() => { - if (this._quickFixes) { - this._registerContextualDecoration(); - this._quickFixes = undefined; - } + this._registerQuickFixDecoration(); + this._quickFixes = undefined; })); } - private _registerContextualDecoration(): void { + /** + * Resolves quick fixes, if any, based on the + * @param command & its output + */ + private _resolveQuickFixes(command: ITerminalCommand): void { + if (command.command !== '') { + this._disposeQuickFix(); + } + const result = getQuickFixesForCommand(command, this._commandListeners, this._openerService, this._onDidRequestRerunCommand); + if (!result) { + return; + } + const { fixes, onDidRunQuickFix } = result; + this._quickFixes = fixes; + onDidRunQuickFix(() => this._disposeQuickFix()); + } + + private _disposeQuickFix(): void { + this._decoration?.dispose(); + this._decoration = undefined; + this._quickFixes = undefined; + } + + /** + * Registers a decoration with the quick fixes + */ + private _registerQuickFixDecoration(): void { if (!this._terminal) { return; } + if (!this._quickFixes) { + return; + } const marker = this._terminal.registerMarker(); if (!marker) { return; } - const actions = this._quickFixes; const decoration = this._terminal.registerDecoration({ marker, layer: 'top' }); + if (!decoration) { + return; + } this._decoration = decoration; const kb = this._keybindingService.lookupKeybinding(TerminalCommandId.QuickFix); const hoverLabel = kb ? localize('terminalQuickFixWithKb', "Show Quick Fixes ({0})", kb.getLabel()) : ''; + const fixes = this._quickFixes; + if (!fixes) { + decoration.dispose(); + return; + } decoration?.onRender((e: HTMLElement) => { - if (!this._decorationMarkerIds.has(decoration.marker.id)) { - this._currentQuickFixElement = e; - e.classList.add(DecorationSelector.QuickFix, DecorationSelector.LightBulb, DecorationSelector.Codicon, DecorationSelector.CommandDecoration, DecorationSelector.XtermDecoration); - updateLayout(this._configurationService, e); - this._audioCueService.playAudioCue(AudioCue.terminalQuickFix); - if (actions) { - this._decorationMarkerIds.add(decoration.marker.id); - this._register(dom.addDisposableListener(e, dom.EventType.CLICK, () => { - this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => actions, autoSelectFirstItem: true }); - })); - this._register(this._terminalDecorationHoverService.createHover(e, undefined, hoverLabel)); - } + if (e.classList.contains(DecorationSelector.QuickFix)) { + return; } + e.classList.add(...quickFixSelectors); + updateLayout(this._configurationService, e); + this._audioCueService.playAudioCue(AudioCue.terminalQuickFix); + this._register(dom.addDisposableListener(e, dom.EventType.CLICK, () => { + this._contextMenuService.showContextMenu({ getAnchor: () => e, getActions: () => fixes, autoSelectFirstItem: true }); + })); + this._register(this._terminalDecorationHoverService.createHover(e, undefined, hoverLabel)); }); } } -export function getQuickFixes( +export function getQuickFixesForCommand( command: ITerminalCommand, - actionOptions: Map, + quickFixOptions: Map, openerService: IOpenerService, onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }> -): IAction[] | undefined { - const actions: IAction[] = []; +): { fixes: IAction[]; onDidRunQuickFix: Event } | undefined { + const onDidRunQuickFixEmitter = new Emitter(); + const onDidRunQuickFix = onDidRunQuickFixEmitter.event; + const fixes: IAction[] = []; const newCommand = command.command; - for (const options of actionOptions.values()) { - for (const actionOption of options) { - if (actionOption.exitStatus !== undefined && actionOption.exitStatus !== (command.exitCode === 0)) { + for (const options of quickFixOptions.values()) { + for (const option of options) { + if (option.exitStatus !== undefined && option.exitStatus !== (command.exitCode === 0)) { continue; } - const commandLineMatch = newCommand.match(actionOption.commandLineMatcher); + const commandLineMatch = newCommand.match(option.commandLineMatcher); if (!commandLineMatch) { continue; } - const outputMatcher = actionOption.outputMatcher; + const outputMatcher = option.outputMatcher; let outputMatch; if (outputMatcher) { outputMatch = command.getOutputMatch(outputMatcher); } - const quickFixes = actionOption.getQuickFixes({ commandLineMatch, outputMatch }, command); + const quickFixes = option.getQuickFixes({ commandLineMatch, outputMatch }, command); if (quickFixes) { for (const quickFix of asArray(quickFixes)) { let action: IAction | undefined; @@ -204,7 +227,12 @@ export function getQuickFixes( label, class: undefined, enabled: true, - run: () => openerService.open(quickFix.uri), + run: () => { + openerService.open(quickFix.uri); + // since no command gets run here, need to + // clear the decoration and quick fix + onDidRunQuickFixEmitter.fire(); + }, tooltip: label, uri: quickFix.uri } as IAction; @@ -222,13 +250,13 @@ export function getQuickFixes( }; } if (action) { - actions.push(action); + fixes.push(action); } } } } } - return actions.length === 0 ? undefined : actions; + return fixes.length > 0 ? { fixes, onDidRunQuickFix } : undefined; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index 3e4fb039e8d..abc0ee55e1a 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -19,7 +19,7 @@ import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabili import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilarCommand, GitSimilarOutputRegex, gitTwoDashes, GitTwoDashesRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions'; -import { TerminalQuickFixAddon, getQuickFixes } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; +import { TerminalQuickFixAddon, getQuickFixesForCommand } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon'; import { URI } from 'vs/base/common/uri'; import { Terminal } from 'xterm'; @@ -72,23 +72,23 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, `invalid output`, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(`gt sttatus`, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns undefined when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitSimilarOutputRegex, exitCode), expectedMap, openerService)?.fixes, actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitSimilarOutputRegex, 2), expectedMap, openerService)?.fixes, actions); }); }); suite('returns match', () => { test('returns match', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitSimilarOutputRegex), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitSimilarOutputRegex), expectedMap, openerService)?.fixes, actions); }); test('returns multiple match', () => { @@ -110,7 +110,7 @@ suite('QuickFixAddon', () => { tooltip: 'Run: git push', command: 'git push' }]; - assertMatchOptions(getQuickFixes(createCommand('git pu', output, GitSimilarOutputRegex), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand('git pu', output, GitSimilarOutputRegex), expectedMap, openerService)?.fixes, actions); }); test('passes any arguments through', () => { output = `git: 'checkoutt' is not a git command. See 'git --help'. @@ -146,18 +146,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitTwoDashesRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, `invalid output`, GitTwoDashesRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`gt sttatus`, output, GitTwoDashesRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(`gt sttatus`, output, GitTwoDashesRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns undefined when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitTwoDashesRegex, exitCode), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitTwoDashesRegex, exitCode), expectedMap, openerService)?.fixes, actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitTwoDashesRegex, 2), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitTwoDashesRegex, 2), expectedMap, openerService)?.fixes, actions); }); }); }); @@ -193,11 +193,11 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected, openerService), undefined); }); }); test('returns actions', () => { - assertMatchOptions(getQuickFixes(createCommand(portCommand, output, FreePortOutputRegex), expected, openerService), actionOptions); + assertMatchOptions(getQuickFixesForCommand(createCommand(portCommand, output, FreePortOutputRegex), expected, openerService)?.fixes, actionOptions); }); }); } @@ -224,18 +224,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService)?.fixes, actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService)?.fixes, actions); }); }); }); @@ -265,18 +265,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, `invalid output`, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(`git status`, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('failure exit status', () => { - strictEqual(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, output, GitCreatePrOutputRegex, 2), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitCreatePrOutputRegex, exitCode), expectedMap, openerService)?.fixes, actions); }); }); }); @@ -305,18 +305,18 @@ suite('QuickFixAddon', () => { }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixes(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(command, `invalid output`, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); test('command does not match', () => { - strictEqual(getQuickFixes(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(`git status`, output, GitPushOutputRegex, exitCode), expectedMap, openerService), undefined); }); }); suite('returns actions when', () => { test('expected unix exit code', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitPushOutputRegex, exitCode), expectedMap, openerService)?.fixes, actions); }); test('matching exit status', () => { - assertMatchOptions(getQuickFixes(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService), actions); + assertMatchOptions(getQuickFixesForCommand(createCommand(command, output, GitPushOutputRegex, 2), expectedMap, openerService)?.fixes, actions); }); }); }); From d3e41d26ed97cebec27cbe9ee5be5d2addc413ea Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 09:18:33 -0700 Subject: [PATCH 372/599] Update xterm.js - Bump copyright year xtermjs/xterm.js#4176 - Share texture atlas cache code between webgl and canvas renderers xtermjs/xterm.js#4170 - Add willReadFrequently to canvas renderer too xtermjs/xterm.js#4169 - Ensure texture atlas comparison uses rgba not object xtermjs/xterm.js#4168 - Create new event with emitter object to simplify code xtermjs/xterm.js#4166 - Define all events and emitters consistently xtermjs/xterm.js#4165 - Inline dirty row service into input handler xtermjs/xterm.js#4163 - Move w objects to $ prefix variables xtermjs/xterm.js#4162 Fixes #158984 Fixes #158874 --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 8 ++++---- remote/web/yarn.lock | 32 ++++++++++++++++---------------- remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index e741661bd4a..160946cc14d 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.15", - "xterm-addon-canvas": "0.3.0-beta.1", - "xterm-addon-search": "0.11.0-beta.1", + "xterm": "5.1.0-beta.23", + "xterm-addon-canvas": "0.3.0-beta.7", + "xterm-addon-search": "0.11.0-beta.2", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.15", + "xterm-addon-webgl": "0.14.0-beta.15", + "xterm-headless": "5.1.0-beta.23", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index 5a2b2bb40a5..cd151f8c386 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.15", - "xterm-addon-canvas": "0.3.0-beta.1", - "xterm-addon-search": "0.11.0-beta.1", + "xterm": "5.1.0-beta.23", + "xterm-addon-canvas": "0.3.0-beta.7", + "xterm-addon-search": "0.11.0-beta.2", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.8", - "xterm-headless": "5.1.0-beta.15", + "xterm-addon-webgl": "0.14.0-beta.15", + "xterm-headless": "5.1.0-beta.23", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 090bd1fb4ce..1df7943d167 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,10 +11,10 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.15", - "xterm-addon-canvas": "0.3.0-beta.1", - "xterm-addon-search": "0.11.0-beta.1", + "xterm": "5.1.0-beta.23", + "xterm-addon-canvas": "0.3.0-beta.7", + "xterm-addon-search": "0.11.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.8" + "xterm-addon-webgl": "0.14.0-beta.15" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 246b60bc896..eacd1082eff 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,27 +68,27 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-canvas@0.3.0-beta.1: - version "0.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.1.tgz#17a65f5da65416b01d620ddef6247ff5013ffc15" - integrity sha512-34PKhrkvK1RtlOOmni4i5GUIyoFKGMph8fWFvA2d52IDTKmX9YoLzZfU73D/sUAx+/GKobCE8sr14CuBZctgNw== +xterm-addon-canvas@0.3.0-beta.7: + version "0.3.0-beta.7" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" + integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== -xterm-addon-search@0.11.0-beta.1: - version "0.11.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.1.tgz#fe7178d70246cde73550447c5524672575467499" - integrity sha512-fKj8KnnhH1nC4oZpKsgnhtgxkTctoa9kGLMpTJjsNzFu0VvXvLGIRezTPI75UEIQdEdaxcwB7/aKelQTO+72LA== +xterm-addon-search@0.11.0-beta.2: + version "0.11.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" + integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== xterm-addon-unicode11@0.5.0-beta.1: version "0.5.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.8: - version "0.14.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" - integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== +xterm-addon-webgl@0.14.0-beta.15: + version "0.14.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" + integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== -xterm@5.1.0-beta.15: - version "5.1.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" - integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== +xterm@5.1.0-beta.23: + version "5.1.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" + integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== diff --git a/remote/yarn.lock b/remote/yarn.lock index 09e066c08c8..6ed33bc70e7 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -788,15 +788,15 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.3.0-beta.1: - version "0.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.1.tgz#17a65f5da65416b01d620ddef6247ff5013ffc15" - integrity sha512-34PKhrkvK1RtlOOmni4i5GUIyoFKGMph8fWFvA2d52IDTKmX9YoLzZfU73D/sUAx+/GKobCE8sr14CuBZctgNw== +xterm-addon-canvas@0.3.0-beta.7: + version "0.3.0-beta.7" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" + integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== -xterm-addon-search@0.11.0-beta.1: - version "0.11.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.1.tgz#fe7178d70246cde73550447c5524672575467499" - integrity sha512-fKj8KnnhH1nC4oZpKsgnhtgxkTctoa9kGLMpTJjsNzFu0VvXvLGIRezTPI75UEIQdEdaxcwB7/aKelQTO+72LA== +xterm-addon-search@0.11.0-beta.2: + version "0.11.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" + integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -808,20 +808,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.8: - version "0.14.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" - integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== +xterm-addon-webgl@0.14.0-beta.15: + version "0.14.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" + integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== -xterm-headless@5.1.0-beta.15: - version "5.1.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.15.tgz#fba76c8e95b552e922354409864c0f55d3b499f7" - integrity sha512-LVtB+KkHs1R2RG8ug3IfOOU0J+qEGttfXagGxfzNq8zxxoSsgoY4D0YvLpM7M/5FK6eGK5K8/yol9XAK63ENog== +xterm-headless@5.1.0-beta.23: + version "5.1.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.23.tgz#f45e0eab9768451df12212d0d5ad313ecfee2f56" + integrity sha512-jF1wYNAt2uqR/UVsxgHE8kxk/xU816MJqKcxSQLZn5kO2e3n6vEwv++hGWgnN4sDb8R2mSWHOCHVdTk/vE9SrA== -xterm@5.1.0-beta.15: - version "5.1.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" - integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== +xterm@5.1.0-beta.23: + version "5.1.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" + integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index ebf28175131..c599a4d84ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11628,15 +11628,15 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-canvas@0.3.0-beta.1: - version "0.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.1.tgz#17a65f5da65416b01d620ddef6247ff5013ffc15" - integrity sha512-34PKhrkvK1RtlOOmni4i5GUIyoFKGMph8fWFvA2d52IDTKmX9YoLzZfU73D/sUAx+/GKobCE8sr14CuBZctgNw== +xterm-addon-canvas@0.3.0-beta.7: + version "0.3.0-beta.7" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" + integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== -xterm-addon-search@0.11.0-beta.1: - version "0.11.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.1.tgz#fe7178d70246cde73550447c5524672575467499" - integrity sha512-fKj8KnnhH1nC4oZpKsgnhtgxkTctoa9kGLMpTJjsNzFu0VvXvLGIRezTPI75UEIQdEdaxcwB7/aKelQTO+72LA== +xterm-addon-search@0.11.0-beta.2: + version "0.11.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" + integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -11648,20 +11648,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.8: - version "0.14.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.8.tgz#486ae22b2eb88a12ebded366c4019ee26409cbb8" - integrity sha512-G0F70f6zGWtXuZxKiTn9BQswaVz85wcCuadnWRdPFDBlgdEfcboCvVZgQetklOIkluVpt8tYYK013/25iMRKTA== +xterm-addon-webgl@0.14.0-beta.15: + version "0.14.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" + integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== -xterm-headless@5.1.0-beta.15: - version "5.1.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.15.tgz#fba76c8e95b552e922354409864c0f55d3b499f7" - integrity sha512-LVtB+KkHs1R2RG8ug3IfOOU0J+qEGttfXagGxfzNq8zxxoSsgoY4D0YvLpM7M/5FK6eGK5K8/yol9XAK63ENog== +xterm-headless@5.1.0-beta.23: + version "5.1.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.23.tgz#f45e0eab9768451df12212d0d5ad313ecfee2f56" + integrity sha512-jF1wYNAt2uqR/UVsxgHE8kxk/xU816MJqKcxSQLZn5kO2e3n6vEwv++hGWgnN4sDb8R2mSWHOCHVdTk/vE9SrA== -xterm@5.1.0-beta.15: - version "5.1.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.15.tgz#146b70c81fd286dbb003d18449918326fa355b6b" - integrity sha512-fO87pEPFMr+h7eo51+6+ew3OhzLm2wwSYz6w/y5lH986rD1lgAeEqFuzjr64pjBzwAihnoaTpumYg5lTZDQpSA== +xterm@5.1.0-beta.23: + version "5.1.0-beta.23" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" + integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== y18n@^3.2.1: version "3.2.2" From d08c3c2c6f6eca4262bf19639c28378d7db76720 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 6 Oct 2022 09:28:33 -0700 Subject: [PATCH 373/599] Add subtle border radius to inputs and dropdowns to match buttons (#162795) * Add border radius to text inputs and dropdowns * Update input and dropdown padding * Update rename input border-radius * Update SCM input styles --- src/vs/base/browser/ui/inputbox/inputBox.css | 3 ++- src/vs/base/browser/ui/selectBox/selectBox.css | 1 + .../contrib/rename/browser/renameInputField.css | 1 + .../suggestEnabledInput/suggestEnabledInput.css | 3 ++- .../browser/media/settingsEditor2.css | 2 +- .../workbench/contrib/scm/browser/media/scm.css | 16 +++++++++++++++- 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css index b3dba065a19..55b552b724f 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.css +++ b/src/vs/base/browser/ui/inputbox/inputBox.css @@ -8,6 +8,7 @@ display: block; padding: 0; box-sizing: border-box; + border-radius: 2px; /* Customizable */ font-size: inherit; @@ -21,7 +22,7 @@ .monaco-inputbox > .ibwrapper > .mirror { /* Customizable */ - padding: 4px; + padding: 4px 6px; } .monaco-inputbox > .ibwrapper { diff --git a/src/vs/base/browser/ui/selectBox/selectBox.css b/src/vs/base/browser/ui/selectBox/selectBox.css index c0a54d83b27..d4a46f25f86 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.css +++ b/src/vs/base/browser/ui/selectBox/selectBox.css @@ -6,6 +6,7 @@ .monaco-select-box { width: 100%; cursor: pointer; + border-radius: 2px; } .monaco-select-box-dropdown-container { diff --git a/src/vs/editor/contrib/rename/browser/renameInputField.css b/src/vs/editor/contrib/rename/browser/renameInputField.css index 99757bf38a4..9000a713ec2 100644 --- a/src/vs/editor/contrib/rename/browser/renameInputField.css +++ b/src/vs/editor/contrib/rename/browser/renameInputField.css @@ -15,6 +15,7 @@ .monaco-editor .rename-box .rename-input { padding: 3px; width: calc(100% - 6px); + border-radius: 2px; } .monaco-editor .rename-box .rename-label { diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css index b025d4b2528..299f2e37e3a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ .suggest-input-container { - padding: 2px 4px; + padding: 2px 6px; + border-radius: 2px; } .suggest-input-container .monaco-editor-background, diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index 11f242b2646..188004eb718 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -561,7 +561,7 @@ width: initial; font: inherit; height: 26px; - padding: 2px 8px; + padding: 2px 6px; } .settings-editor > .settings-body .settings-tree-container .setting-item-new-extensions { diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index b040001c0c6..7116d4ba6e7 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -194,6 +194,19 @@ .scm-view .scm-input { height: 100%; padding-left: 11px; + border-radius: 2px; +} + +.scm-view .scm-input .margin { + width: 6px !important; +} + +.scm-input .monaco-scrollable-element { + left: 6px !important; +} + +.scm-view .scm-editor-container .monaco-editor { + border-radius: 2px !important; } .scm-view .scm-editor { @@ -285,6 +298,7 @@ box-sizing: border-box; padding: 1px; outline-offset: -1px; + border-radius: 2px; } .scm-editor-validation-container { @@ -324,7 +338,7 @@ position: absolute; pointer-events: none; z-index: 1; - padding: 2px 4px 3px 4px; + padding: 2px 6px 3px 6px; box-sizing: border-box; width: 100%; overflow: hidden; From 1eeb8b5e3470923bfd1d4f449357f1857674e5ff Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Thu, 6 Oct 2022 09:40:32 -0700 Subject: [PATCH 374/599] replace registerWorkbenchAction with registerAction2 in search (#162778) replace registerWorkbenchAction with registerAction2 --- .../search/browser/search.contribution.ts | 123 +++++++++++++++--- .../contrib/search/browser/searchActions.ts | 122 +++++------------ .../contrib/search/common/constants.ts | 13 ++ 3 files changed, 144 insertions(+), 114 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 6762eea280e..90afe040b3b 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { ToggleCaseSensitiveKeybinding, TogglePreserveCaseKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/browser/findModel'; import { AbstractGotoLineQuickAccessProvider } from 'vs/editor/contrib/quickAccess/browser/gotoLineQuickAccess'; import * as nls from 'vs/nls'; -import { Action2, MenuId, MenuRegistry, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandAction } from 'vs/platform/action/common/action'; import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -30,7 +30,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { defaultQuickAccessContextKeyValue } from 'vs/workbench/browser/quickaccess'; -import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Extensions as ViewExtensions, IViewContainersRegistry, IViewDescriptor, IViewDescriptorService, IViewsRegistry, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; import { GotoSymbolQuickAccessProvider } from 'vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess'; @@ -39,7 +38,7 @@ import { getMultiSelectedResources, IExplorerService } from 'vs/workbench/contri import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition, VIEWLET_ID as VIEWLET_ID_FILES } from 'vs/workbench/contrib/files/common/files'; import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess'; import { registerContributions as replaceContributions } from 'vs/workbench/contrib/search/browser/replaceContributions'; -import { cancelSearch, clearHistoryCommand, clearSearchResults, CloseReplaceAction, collapseDeepestExpandedLevel, copyAllCommand, copyMatchCommand, copyPathCommand, expandAll, FindInFilesCommand, FocusNextInputAction, FocusNextSearchResultAction, FocusPreviousInputAction, FocusPreviousSearchResultAction, focusSearchListCommand, getSearchView, openSearchView, refreshSearch, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceInFilesAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, ToggleSearchOnTypeAction, toggleWholeWordCommand } from 'vs/workbench/contrib/search/browser/searchActions'; +import { cancelSearch, clearHistoryCommand, clearSearchResults, CloseReplaceAction, collapseDeepestExpandedLevel, copyAllCommand, copyMatchCommand, copyPathCommand, expandAll, FindInFilesCommand, findOrReplaceInFiles, FocusNextInputAction, focusNextSearchResult, FocusPreviousInputAction, focusPreviousSearchResult, focusSearchListCommand, getSearchView, openSearchView, refreshSearch, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, toggleWholeWordCommand } from 'vs/workbench/contrib/search/browser/searchActions'; import { searchClearIcon, searchCollapseAllIcon, searchExpandAllIcon, searchRefreshIcon, searchStopIcon, searchShowAsTree, searchViewIcon, searchShowAsList } from 'vs/workbench/contrib/search/browser/searchIcons'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; import { registerContributions as searchWidgetContributions } from 'vs/workbench/contrib/search/browser/searchWidget'; @@ -66,7 +65,7 @@ searchWidgetContributions(); const category = { value: nls.localize('search', "Search"), original: 'Search' }; KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'workbench.action.search.toggleQueryDetails', + id: Constants.ToggleQueryDetailsActionId, weight: KeybindingWeight.WorkbenchContrib, when: ContextKeyExpr.or(Constants.SearchViewFocusedKey, SearchEditorConstants.InSearchEditor), primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyJ, @@ -369,7 +368,7 @@ CommandsRegistry.registerCommand({ registerAction2(class CancelSearchAction extends Action2 { constructor() { super({ - id: 'search.action.cancel', + id: Constants.CancelSearchActionId, title: { value: nls.localize('CancelSearchAction.label', "Cancel Search"), original: 'Cancel Search' @@ -399,7 +398,7 @@ registerAction2(class CancelSearchAction extends Action2 { registerAction2(class RefreshAction extends Action2 { constructor() { super({ - id: 'search.action.refreshSearchResults', + id: Constants.RefreshSearchResultsActionId, title: { value: nls.localize('RefreshAction.label', "Refresh"), original: 'Refresh' @@ -424,7 +423,7 @@ registerAction2(class RefreshAction extends Action2 { registerAction2(class CollapseDeepestExpandedLevelAction extends Action2 { constructor() { super({ - id: 'search.action.collapseSearchResults', + id: Constants.CollapseSearchResultsActionId, title: { value: nls.localize('CollapseDeepestExpandedLevelAction.label', "Collapse All"), original: 'Collapse All' @@ -449,7 +448,7 @@ registerAction2(class CollapseDeepestExpandedLevelAction extends Action2 { registerAction2(class ExpandAllAction extends Action2 { constructor() { super({ - id: 'search.action.expandSearchResults', + id: Constants.ExpandSearchResultsActionId, title: { value: nls.localize('ExpandAllAction.label', "Expand All"), original: 'Expand All' @@ -474,7 +473,7 @@ registerAction2(class ExpandAllAction extends Action2 { registerAction2(class ClearSearchResultsAction extends Action2 { constructor() { super({ - id: 'search.action.clearSearchResults', + id: Constants.ClearSearchResultsActionId, title: { value: nls.localize('ClearSearchResultsAction.label', "Clear Search Results"), original: 'Clear Search Results' @@ -499,7 +498,7 @@ registerAction2(class ClearSearchResultsAction extends Action2 { registerAction2(class ViewAsTreeAction extends Action2 { constructor() { super({ - id: 'search.action.viewAsTree', + id: Constants.ViewAsTreeActionId, title: { value: nls.localize('ViewAsTreeAction.label', "View as Tree"), original: 'View as Tree' @@ -528,7 +527,7 @@ registerAction2(class ViewAsTreeAction extends Action2 { registerAction2(class ViewAsListAction extends Action2 { constructor() { super({ - id: 'search.action.viewAsList', + id: Constants.ViewAsListActionId, title: { value: nls.localize('ViewAsListAction.label', "View as List"), original: 'View as List' @@ -678,7 +677,7 @@ class ShowAllSymbolsAction extends Action2 { constructor( ) { super({ - id: 'workbench.action.showAllSymbols', + id: Constants.ShowAllSymbolsActionId, title: { value: nls.localize('showTriggerActions', "Go to Symbol in Workspace..."), original: 'Go to Symbol in Workspace...' @@ -748,9 +747,6 @@ class RegisterSearchViewContribution implements IWorkbenchContribution { } Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterSearchViewContribution, LifecyclePhase.Starting); -// Actions -const registry = Registry.as(ActionExtensions.WorkbenchActions); - // Find in Files by default is the same as View: Show Search, but can be configured to open a search editor instead with the `search.mode` binding KeybindingsRegistry.registerCommandAndKeybindingRule({ description: { @@ -793,14 +789,77 @@ MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, { order: 1 }); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextSearchResultAction, { primary: KeyCode.F4 }), 'Search: Focus Next Search Result', category.value, ContextKeyExpr.or(Constants.HasSearchResults, SearchEditorConstants.InSearchEditor)); -registry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousSearchResultAction, { primary: KeyMod.Shift | KeyCode.F4 }), 'Search: Focus Previous Search Result', category.value, ContextKeyExpr.or(Constants.HasSearchResults, SearchEditorConstants.InSearchEditor)); +registerAction2(class FocusNextSearchResultAction extends Action2 { + constructor() { + super({ + id: Constants.FocusNextSearchResultActionId, + title: { + value: nls.localize('FocusNextSearchResult.label', 'Focus Next Search Result'), + original: 'Focus Next Search Result' + }, + keybinding: [{ + primary: KeyCode.F4, + weight: KeybindingWeight.WorkbenchContrib, + }], + category: category.value, + + precondition: ContextKeyExpr.or(Constants.HasSearchResults, SearchEditorConstants.InSearchEditor), + }); + } + + override async run(accessor: ServicesAccessor): Promise { + return focusNextSearchResult(accessor); + } +}); + +registerAction2(class FocusPreviousSearchResultAction extends Action2 { + constructor() { + super({ + id: Constants.FocusPreviousSearchResultActionId, + title: { + value: nls.localize('FocusPreviousSearchResult.label', 'Search: Focus Previous Search Result'), + original: 'Search: Focus Previous Search Result' + }, + keybinding: [{ + primary: KeyMod.Shift | KeyCode.F4, + weight: KeybindingWeight.WorkbenchContrib, + }], + category: category.value, + + precondition: ContextKeyExpr.or(Constants.HasSearchResults, SearchEditorConstants.InSearchEditor), + }); + } + + override async run(accessor: ServicesAccessor): Promise { + return focusPreviousSearchResult(accessor); + } +}); + +registerAction2(class ReplaceInFilesAction extends Action2 { + constructor() { + super({ + id: Constants.ReplaceInFilesActionId, + title: { + value: nls.localize('replaceInFiles', 'Search: Replace in Files'), + original: 'Search: Replace in Files' + }, + keybinding: [{ + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyH, + weight: KeybindingWeight.WorkbenchContrib, + }], + category: category.value, + }); + } + + override async run(accessor: ServicesAccessor): Promise { + return findOrReplaceInFiles(accessor, true); + } +}); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ReplaceInFilesAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyH }), 'Search: Replace in Files', category.value); MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, { group: '4_find_global', command: { - id: ReplaceInFilesAction.ID, + id: Constants.ReplaceInFilesActionId, title: nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files") }, order: 2 @@ -857,8 +916,30 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } } }); +// --- Toggle Search On Type -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleSearchOnTypeAction), 'Search: Toggle Search on Type', category.value); +registerAction2(class ToggleSearchOnTypeAction extends Action2 { + private static readonly searchOnTypeKey = 'search.searchOnType'; + + constructor( + ) { + super({ + id: Constants.ToggleSearchOnTypeActionId, + title: { + value: nls.localize('toggleTabs', 'Toggle Search on Type'), + original: 'Toggle Search on Type' + }, + category: category.value, + }); + + } + + override async run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + const searchOnType = configurationService.getValue(ToggleSearchOnTypeAction.searchOnTypeKey); + return configurationService.updateValue(ToggleSearchOnTypeAction.searchOnTypeKey, !searchOnType); + } +}); // Register Quick Access Handler const quickAccessRegistry = Registry.as(QuickAccessExtensions.Quickaccess); @@ -1128,7 +1209,7 @@ CommandsRegistry.registerCommand('_executeWorkspaceSymbolProvider', async functi MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '3_global_nav', command: { - id: 'workbench.action.showAllSymbols', + id: Constants.ShowAllSymbolsActionId, title: nls.localize({ key: 'miGotoSymbolInWorkspace', comment: ['&& denotes a mnemonic'] }, "Go to Symbol in &&Workspace...") }, order: 2 diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 6f121ec4d6f..b93bb92007c 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -129,26 +129,6 @@ export class FocusPreviousInputAction extends Action { } } -export abstract class FindOrReplaceInFilesAction extends Action { - - constructor(id: string, label: string, protected viewsService: IViewsService, - private expandSearchReplaceWidget: boolean - ) { - super(id, label); - } - - override run(): Promise { - return openSearchView(this.viewsService, false).then(openedView => { - if (openedView) { - const searchAndReplaceWidget = openedView.searchAndReplaceWidget; - searchAndReplaceWidget.toggleReplace(this.expandSearchReplaceWidget); - - const updatedText = openedView.updateTextFromFindWidgetOrSelection({ allowUnselectedWord: !this.expandSearchReplaceWidget }); - openedView.searchAndReplaceWidget.focus(undefined, updatedText, updatedText); - } - }); - } -} export interface IFindInFilesArgs { query?: string; replace?: string; @@ -197,17 +177,6 @@ export const FindInFilesCommand: ICommandHandler = (accessor, args: IFindInFiles } }; -export class ReplaceInFilesAction extends FindOrReplaceInFilesAction { - - static readonly ID = 'workbench.action.replaceInFiles'; - static readonly LABEL = nls.localize('replaceInFiles', "Replace in Files"); - - constructor(id: string, label: string, - @IViewsService viewsService: IViewsService) { - super(id, label, viewsService, /*expandSearchReplaceWidget=*/true); - } -} - export class CloseReplaceAction extends Action { constructor(id: string, label: string, @@ -226,29 +195,6 @@ export class CloseReplaceAction extends Action { } } -// --- Toggle Search On Type - -export class ToggleSearchOnTypeAction extends Action { - - static readonly ID = 'workbench.action.toggleSearchOnType'; - static readonly LABEL = nls.localize('toggleTabs', "Toggle Search on Type"); - - private static readonly searchOnTypeKey = 'search.searchOnType'; - - constructor( - id: string, - label: string, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); - } - - override run(): Promise { - const searchOnType = this.configurationService.getValue(ToggleSearchOnTypeAction.searchOnTypeKey); - return this.configurationService.updateValue(ToggleSearchOnTypeAction.searchOnTypeKey, !searchOnType); - } -} - export function expandAll(accessor: ServicesAccessor) { const viewsService = accessor.get(IViewsService); const searchView = getSearchView(viewsService); @@ -357,52 +303,42 @@ export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { } } -export class FocusNextSearchResultAction extends Action { - static readonly ID = 'search.action.focusNextSearchResult'; - static readonly LABEL = nls.localize('FocusNextSearchResult.label', "Focus Next Search Result"); - - constructor(id: string, label: string, - @IViewsService private readonly viewsService: IViewsService, - @IEditorService private readonly editorService: IEditorService, - ) { - super(id, label); +export async function focusNextSearchResult(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const input = editorService.activeEditor; + if (input instanceof SearchEditorInput) { + // cast as we cannot import SearchEditor as a value b/c cyclic dependency. + return (editorService.activeEditorPane as SearchEditor).focusNextResult(); } - override async run(): Promise { - const input = this.editorService.activeEditor; - if (input instanceof SearchEditorInput) { - // cast as we cannot import SearchEditor as a value b/c cyclic dependency. - return (this.editorService.activeEditorPane as SearchEditor).focusNextResult(); - } - - return openSearchView(this.viewsService).then(searchView => { - searchView?.selectNextMatch(); - }); - } + return openSearchView(accessor.get(IViewsService)).then(searchView => { + searchView?.selectNextMatch(); + }); } -export class FocusPreviousSearchResultAction extends Action { - static readonly ID = 'search.action.focusPreviousSearchResult'; - static readonly LABEL = nls.localize('FocusPreviousSearchResult.label', "Focus Previous Search Result"); - - constructor(id: string, label: string, - @IViewsService private readonly viewsService: IViewsService, - @IEditorService private readonly editorService: IEditorService, - ) { - super(id, label); +export async function focusPreviousSearchResult(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const input = editorService.activeEditor; + if (input instanceof SearchEditorInput) { + // cast as we cannot import SearchEditor as a value b/c cyclic dependency. + return (editorService.activeEditorPane as SearchEditor).focusPreviousResult(); } - override async run(): Promise { - const input = this.editorService.activeEditor; - if (input instanceof SearchEditorInput) { - // cast as we cannot import SearchEditor as a value b/c cyclic dependency. - return (this.editorService.activeEditorPane as SearchEditor).focusPreviousResult(); + return openSearchView(accessor.get(IViewsService)).then(searchView => { + searchView?.selectPreviousMatch(); + }); +} + +export async function findOrReplaceInFiles(accessor: ServicesAccessor, expandSearchReplaceWidget: boolean): Promise { + return openSearchView(accessor.get(IViewsService), false).then(openedView => { + if (openedView) { + const searchAndReplaceWidget = openedView.searchAndReplaceWidget; + searchAndReplaceWidget.toggleReplace(expandSearchReplaceWidget); + + const updatedText = openedView.updateTextFromFindWidgetOrSelection({ allowUnselectedWord: !expandSearchReplaceWidget }); + openedView.searchAndReplaceWidget.focus(undefined, updatedText, updatedText); } - - return openSearchView(this.viewsService).then(searchView => { - searchView?.selectPreviousMatch(); - }); - } + }); } export abstract class AbstractSearchAndReplaceAction extends Action { diff --git a/src/vs/workbench/contrib/search/common/constants.ts b/src/vs/workbench/contrib/search/common/constants.ts index 5a4dfd6ed45..e1306326def 100644 --- a/src/vs/workbench/contrib/search/common/constants.ts +++ b/src/vs/workbench/contrib/search/common/constants.ts @@ -28,6 +28,19 @@ export const ToggleRegexCommandId = 'toggleSearchRegex'; export const TogglePreserveCaseId = 'toggleSearchPreserveCase'; export const AddCursorsAtSearchResults = 'addCursorsAtSearchResults'; export const RevealInSideBarForSearchResults = 'search.action.revealInSideBar'; +export const ReplaceInFilesActionId = 'workbench.action.replaceInFiles'; +export const ShowAllSymbolsActionId = 'workbench.action.showAllSymbols'; +export const CancelSearchActionId = 'search.action.cancel'; +export const RefreshSearchResultsActionId = 'search.action.refreshSearchResults'; +export const FocusNextSearchResultActionId = 'search.action.focusNextSearchResult'; +export const FocusPreviousSearchResultActionId = 'search.action.focusPreviousSearchResult'; +export const ToggleSearchOnTypeActionId = 'workbench.action.toggleSearchOnType'; +export const CollapseSearchResultsActionId = 'search.action.collapseSearchResults'; +export const ExpandSearchResultsActionId = 'search.action.expandSearchResults'; +export const ClearSearchResultsActionId = 'search.action.clearSearchResults'; +export const ViewAsTreeActionId = 'search.action.viewAsTree'; +export const ViewAsListActionId = 'search.action.viewAsList'; +export const ToggleQueryDetailsActionId = 'workbench.action.search.toggleQueryDetails'; export const SearchViewVisibleKey = new RawContextKey('searchViewletVisible', true); export const SearchViewFocusedKey = new RawContextKey('searchViewletFocus', false); From c8ea6c85ef737d11f79b4248d0702b6f2c281087 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 09:55:35 -0700 Subject: [PATCH 375/599] Fix compile error on main (#162859) --- .../contrib/terminal/test/browser/quickFixAddon.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index abc0ee55e1a..a2904a8151a 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -117,7 +117,7 @@ suite('QuickFixAddon', () => { The most similar commands are checkout`; - assertMatchOptions(getQuickFixes(createCommand('git checkoutt .', output, GitSimilarOutputRegex), expectedMap, openerService), [{ + assertMatchOptions(getQuickFixesForCommand(createCommand('git checkoutt .', output, GitSimilarOutputRegex), expectedMap, openerService)?.fixes, [{ id: `quickFix.command`, enabled: true, label: 'Run: git checkout .', From d47ee39e9bd74faff9d0efa4d71bc82b762a8354 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 10:03:41 -0700 Subject: [PATCH 376/599] are -> aren't --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index b0fb9f7f96d..b1909b7d9db 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -586,7 +586,7 @@ export interface ITerminalInstance { onDidFocusFindWidget: Event; /** - * The exit code or undefined when the terminal process hasn't yet exited or + * The exit code or undefined when the terminal process hasn't yet exited or * the process exit code could not be determined. Use {@link exitReason} to see * why the process has exited. */ @@ -599,7 +599,7 @@ export interface ITerminalInstance { readonly exitReason: TerminalExitReason | undefined; /** - * Whether links in the terminal are ready, links are available until after the process is + * Whether links in the terminal are ready, links aren't available until after the process is * ready. */ readonly areLinksReady: boolean; From 6fba44510b9b357baea20fc7804edbb94d91a8ab Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Thu, 6 Oct 2022 16:30:01 +0200 Subject: [PATCH 377/599] Update column names in 'Feature Contributions' - Use "ID" for the setting. "ID" is the term used in the settings editor. - Use "ID" / "Title" instead of "Name" / "Description" for commands. They are the terms used in the keybinding editor and other places. - Use "ID" instead of "Id" everywhere for consistency --- .../contrib/extensions/browser/extensionEditor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 65d0cc03d7e..f9c660594e0 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -1197,7 +1197,7 @@ export class ExtensionEditor extends EditorPane { $('summary', { tabindex: '0' }, localize('settings', "Settings ({0})", contrib.length)), $('table', undefined, $('tr', undefined, - $('th', undefined, localize('setting name', "Name")), + $('th', undefined, localize('setting name', "ID")), $('th', undefined, localize('description', "Description")), $('th', undefined, localize('default', "Default")) ), @@ -1378,7 +1378,7 @@ export class ExtensionEditor extends EditorPane { $('table', undefined, $('tr', undefined, $('th', undefined, localize('authentication.label', "Label")), - $('th', undefined, localize('authentication.id', "Id")) + $('th', undefined, localize('authentication.id', "ID")) ), ...authentication.map(action => $('tr', undefined, @@ -1460,7 +1460,7 @@ export class ExtensionEditor extends EditorPane { $('summary', { tabindex: '0' }, localize('colors', "Colors ({0})", colors.length)), $('table', undefined, $('tr', undefined, - $('th', undefined, localize('colorId', "Id")), + $('th', undefined, localize('colorId', "ID")), $('th', undefined, localize('description', "Description")), $('th', undefined, localize('defaultDark', "Dark Default")), $('th', undefined, localize('defaultLight', "Light Default")), @@ -1566,8 +1566,8 @@ export class ExtensionEditor extends EditorPane { $('summary', { tabindex: '0' }, localize('commands', "Commands ({0})", commands.length)), $('table', undefined, $('tr', undefined, - $('th', undefined, localize('command name', "Name")), - $('th', undefined, localize('description', "Description")), + $('th', undefined, localize('command name', "ID")), + $('th', undefined, localize('description', "Title")), $('th', undefined, localize('keyboard shortcuts', "Keyboard Shortcuts")), $('th', undefined, localize('menuContexts', "Menu Contexts")) ), @@ -1677,7 +1677,7 @@ export class ExtensionEditor extends EditorPane { $('summary', { tabindex: '0' }, localize('Notebooks', "Notebooks ({0})", contrib.length)), $('table', undefined, $('tr', undefined, - $('th', undefined, localize('Notebook id', "Id")), + $('th', undefined, localize('Notebook id', "ID")), $('th', undefined, localize('Notebook name', "Name")), ), ...contrib.map(d => $('tr', undefined, From 25e8bbbdc924dd2de929cd85869cd69a0a0b6821 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Thu, 6 Oct 2022 18:30:25 +0200 Subject: [PATCH 378/599] update localize info to fix linter issue --- src/vs/workbench/contrib/extensions/browser/extensionEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index f9c660594e0..ba6774dd3f9 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -1567,7 +1567,7 @@ export class ExtensionEditor extends EditorPane { $('table', undefined, $('tr', undefined, $('th', undefined, localize('command name', "ID")), - $('th', undefined, localize('description', "Title")), + $('th', undefined, localize('command title', "Title")), $('th', undefined, localize('keyboard shortcuts', "Keyboard Shortcuts")), $('th', undefined, localize('menuContexts', "Menu Contexts")) ), From c3aee94a0ea5f7f8f3dea174adc1d6e7e95d7ad1 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 6 Oct 2022 10:18:42 -0700 Subject: [PATCH 379/599] Update src/vs/workbench/contrib/terminal/browser/terminalInstance.ts --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 578fad10a06..dc34e423554 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1208,7 +1208,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } override dispose(reason?: TerminalExitReason): void { - if (this._isDisposed) { + if (this._isDisposed) { return; } this._isDisposed = true; From 9ff5a9aaa9d9e4c2c518951abf03ffa9643efd42 Mon Sep 17 00:00:00 2001 From: Dongcai Huang Date: Fri, 7 Oct 2022 01:31:27 +0800 Subject: [PATCH 380/599] Fix FreePortOutputRegex (#162323) --- .../terminal/browser/terminalQuickFixBuiltinActions.ts | 4 ++-- .../contrib/terminal/test/browser/quickFixAddon.test.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts index 0cf63953bcf..04fc6eb724a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions.ts @@ -13,7 +13,7 @@ export const GitPushCommandLineRegex = /git\s+push/; export const GitTwoDashesRegex = /error: did you mean `--(.+)` \(with two dashes\)\?/; export const AnyCommandLineRegex = /.+/; export const GitSimilarOutputRegex = /(?:(most similar (command|commands) (is|are)))((\n\s*[^\s]+)+)/m; -export const FreePortOutputRegex = /address already in use \d+\.\d+\.\d+\.\d+:(\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; +export const FreePortOutputRegex = /address already in use (0\.0\.0\.0|127\.0\.0\.1|localhost|::):(?\d{4,5})|Unable to bind [^ ]*:(\d{4,5})|can't listen on port (\d{4,5})|listen EADDRINUSE [^ ]*:(\d{4,5})/; export const GitPushOutputRegex = /git push --set-upstream origin ([^\s]+)/; // The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*" // it's safe to assume it's a github pull request if the URL includes `/pull/` @@ -83,7 +83,7 @@ export function freePort(terminalInstance?: Partial): ITermin }, exitStatus: false, getQuickFixes: (matchResult: TerminalQuickFixMatchResult, command: ITerminalCommand) => { - const port = matchResult?.outputMatch?.[1]; + const port = matchResult?.outputMatch?.groups?.portNumber; if (!port) { return; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts index a2904a8151a..0f0ae6bdf57 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/quickFixAddon.test.ts @@ -163,7 +163,7 @@ suite('QuickFixAddon', () => { }); if (!isWindows) { suite('freePort', () => { - const expected = new Map(); + const expectedMap = new Map(); const portCommand = `yarn start dev`; const output = `yarn run v1.22.17 warning ../../package.json: No license field @@ -188,16 +188,16 @@ suite('QuickFixAddon', () => { }]; setup(() => { const command = freePort(terminalInstance); - expected.set(command.commandLineMatcher.toString(), [command]); + expectedMap.set(command.commandLineMatcher.toString(), [command]); quickFixAddon.registerCommandFinishedListener(command); }); suite('returns undefined when', () => { test('output does not match', () => { - strictEqual(getQuickFixesForCommand(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expected, openerService), undefined); + strictEqual(getQuickFixesForCommand(createCommand(portCommand, `invalid output`, FreePortOutputRegex), expectedMap, openerService)?.fixes, undefined); }); }); test('returns actions', () => { - assertMatchOptions(getQuickFixesForCommand(createCommand(portCommand, output, FreePortOutputRegex), expected, openerService)?.fixes, actionOptions); + assertMatchOptions(getQuickFixesForCommand(createCommand(portCommand, output, FreePortOutputRegex), expectedMap, openerService)?.fixes, actionOptions); }); }); } From c6aca1b2307c3030ce1c1eb7737a9eb5ff676cbe Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 6 Oct 2022 10:36:11 -0700 Subject: [PATCH 381/599] Fix space->tab --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index dc34e423554..540c770e19f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1208,7 +1208,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } override dispose(reason?: TerminalExitReason): void { - if (this._isDisposed) { + if (this._isDisposed) { return; } this._isDisposed = true; From ae4926234561a8619c5359d9574b3dd9e6153f53 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 6 Oct 2022 10:38:05 -0700 Subject: [PATCH 382/599] Update xterm again This includes a revert to event refactor which will fix vscode's internal access. It was going to be reverted anyway. --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 8 ++++---- remote/web/yarn.lock | 32 ++++++++++++++++---------------- remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 160946cc14d..16c805d445f 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.23", - "xterm-addon-canvas": "0.3.0-beta.7", - "xterm-addon-search": "0.11.0-beta.2", + "xterm": "5.1.0-beta.25", + "xterm-addon-canvas": "0.3.0-beta.8", + "xterm-addon-search": "0.11.0-beta.3", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.15", - "xterm-headless": "5.1.0-beta.23", + "xterm-addon-webgl": "0.14.0-beta.16", + "xterm-headless": "5.1.0-beta.25", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index cd151f8c386..c241260d8d9 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.23", - "xterm-addon-canvas": "0.3.0-beta.7", - "xterm-addon-search": "0.11.0-beta.2", + "xterm": "5.1.0-beta.25", + "xterm-addon-canvas": "0.3.0-beta.8", + "xterm-addon-search": "0.11.0-beta.3", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.15", - "xterm-headless": "5.1.0-beta.23", + "xterm-addon-webgl": "0.14.0-beta.16", + "xterm-headless": "5.1.0-beta.25", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 1df7943d167..953d7a08983 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,10 +11,10 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.23", - "xterm-addon-canvas": "0.3.0-beta.7", - "xterm-addon-search": "0.11.0-beta.2", + "xterm": "5.1.0-beta.25", + "xterm-addon-canvas": "0.3.0-beta.8", + "xterm-addon-search": "0.11.0-beta.3", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.15" + "xterm-addon-webgl": "0.14.0-beta.16" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index eacd1082eff..438b1bcdb37 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,27 +68,27 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-canvas@0.3.0-beta.7: - version "0.3.0-beta.7" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" - integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== +xterm-addon-canvas@0.3.0-beta.8: + version "0.3.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" + integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== -xterm-addon-search@0.11.0-beta.2: - version "0.11.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" - integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== +xterm-addon-search@0.11.0-beta.3: + version "0.11.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" + integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== xterm-addon-unicode11@0.5.0-beta.1: version "0.5.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.15: - version "0.14.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" - integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== +xterm-addon-webgl@0.14.0-beta.16: + version "0.14.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" + integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== -xterm@5.1.0-beta.23: - version "5.1.0-beta.23" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" - integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== +xterm@5.1.0-beta.25: + version "5.1.0-beta.25" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" + integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== diff --git a/remote/yarn.lock b/remote/yarn.lock index 6ed33bc70e7..53709b74a0a 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -788,15 +788,15 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.3.0-beta.7: - version "0.3.0-beta.7" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" - integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== +xterm-addon-canvas@0.3.0-beta.8: + version "0.3.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" + integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== -xterm-addon-search@0.11.0-beta.2: - version "0.11.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" - integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== +xterm-addon-search@0.11.0-beta.3: + version "0.11.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" + integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -808,20 +808,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.15: - version "0.14.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" - integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== +xterm-addon-webgl@0.14.0-beta.16: + version "0.14.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" + integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== -xterm-headless@5.1.0-beta.23: - version "5.1.0-beta.23" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.23.tgz#f45e0eab9768451df12212d0d5ad313ecfee2f56" - integrity sha512-jF1wYNAt2uqR/UVsxgHE8kxk/xU816MJqKcxSQLZn5kO2e3n6vEwv++hGWgnN4sDb8R2mSWHOCHVdTk/vE9SrA== +xterm-headless@5.1.0-beta.25: + version "5.1.0-beta.25" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.25.tgz#9c9e117caa7c5fb56e4518e6ca14549c3d64d974" + integrity sha512-NsEsf/tGdIuoi7Ey/jIPFbRVWgNFhlmw9PKibW8GsudfAZkbbgggLe/gCHFlOYXpa+vYNGr8cDmDqGT86mFvvw== -xterm@5.1.0-beta.23: - version "5.1.0-beta.23" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" - integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== +xterm@5.1.0-beta.25: + version "5.1.0-beta.25" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" + integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index c599a4d84ab..1d201909084 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11628,15 +11628,15 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-canvas@0.3.0-beta.7: - version "0.3.0-beta.7" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.7.tgz#3e18dbc97e1bd37d625b182ab049cc0e78035b82" - integrity sha512-H03GaciEG9tlsJunPjganFQP9RPAaLV6fJPeEEdEWEdDBjdx2C9TkK/HBodSj8LTOddzGWg4mSJriitqWKlZmA== +xterm-addon-canvas@0.3.0-beta.8: + version "0.3.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" + integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== -xterm-addon-search@0.11.0-beta.2: - version "0.11.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.2.tgz#cb9287b65bdadf69bd32058a9fd61b99743ecae7" - integrity sha512-Y97igBlO4wRdSLxjYxKeZPoM6byyyzy+/xEeyCwMp/oy26CSFS9xmynQBrDdE15abSsVX+qy+MYRajTjDmVo8A== +xterm-addon-search@0.11.0-beta.3: + version "0.11.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" + integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -11648,20 +11648,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.15: - version "0.14.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.15.tgz#bb67c59ed6c0773da20eb12301eee85c776cdc75" - integrity sha512-zNnM0CRLWpBALbjcagxSGs9cgVG57xi7s6SI4pW6i8bKMebd06Ls0/o+rxC2Frwp1WxfAFjF5yKIO1T0GUEl/w== +xterm-addon-webgl@0.14.0-beta.16: + version "0.14.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" + integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== -xterm-headless@5.1.0-beta.23: - version "5.1.0-beta.23" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.23.tgz#f45e0eab9768451df12212d0d5ad313ecfee2f56" - integrity sha512-jF1wYNAt2uqR/UVsxgHE8kxk/xU816MJqKcxSQLZn5kO2e3n6vEwv++hGWgnN4sDb8R2mSWHOCHVdTk/vE9SrA== +xterm-headless@5.1.0-beta.25: + version "5.1.0-beta.25" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.25.tgz#9c9e117caa7c5fb56e4518e6ca14549c3d64d974" + integrity sha512-NsEsf/tGdIuoi7Ey/jIPFbRVWgNFhlmw9PKibW8GsudfAZkbbgggLe/gCHFlOYXpa+vYNGr8cDmDqGT86mFvvw== -xterm@5.1.0-beta.23: - version "5.1.0-beta.23" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.23.tgz#6722997e99b2a4d937bec69d34c71dae1c263cdc" - integrity sha512-RHhewoIwE5X5cq/1rAuoJfd4Nk5hKn4ISSdPs/OXZyCXPZ65DGz9f/H2JwLlxqcCjwjzLiKgnTfaJTOD2xbAbg== +xterm@5.1.0-beta.25: + version "5.1.0-beta.25" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" + integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== y18n@^3.2.1: version "3.2.2" From bc4bf747c980e639b399f21d387d087c6f64ed03 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 11:31:27 -0700 Subject: [PATCH 383/599] Bump version (#162864) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e741661bd4a..00872bd146c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.72.0", + "version": "1.73.0", "distro": "d4b1b117d224d627ec65bb0fd0b02fdee65303aa", "author": { "name": "Microsoft Corporation" From 99e126b0b287ce093eb31248133052e06262e140 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 12:08:45 -0700 Subject: [PATCH 384/599] Pick up latest TS version for building VS Code (#162786) Pick up latest TS for building VS Code --- build/lib/layersChecker.js | 3 ++- build/lib/layersChecker.ts | 3 ++- build/yarn.lock | 6 +++--- package.json | 2 +- .../server/node/remoteExtensionHostAgentServer.ts | 8 ++++---- src/vs/server/node/webClientServer.ts | 14 +++++++------- test/automation/package.json | 2 +- test/automation/yarn.lock | 6 +++--- test/integration/browser/yarn.lock | 6 +++--- test/smoke/yarn.lock | 6 +++--- yarn.lock | 14 +++++++------- 11 files changed, 36 insertions(+), 34 deletions(-) diff --git a/build/lib/layersChecker.js b/build/lib/layersChecker.js index cbc1f95b979..e766756d9f3 100644 --- a/build/lib/layersChecker.js +++ b/build/lib/layersChecker.js @@ -56,7 +56,8 @@ const CORE_TYPES = [ 'MessageChannel', 'MessagePort', 'URL', - 'URLSearchParams' + 'URLSearchParams', + 'ReadonlyArray', ]; // Types that are defined in a common layer but are known to be only // available in native environments should not be allowed in browser diff --git a/build/lib/layersChecker.ts b/build/lib/layersChecker.ts index 12b900162aa..44490b6f1f9 100644 --- a/build/lib/layersChecker.ts +++ b/build/lib/layersChecker.ts @@ -57,7 +57,8 @@ const CORE_TYPES = [ 'MessageChannel', 'MessagePort', 'URL', - 'URLSearchParams' + 'URLSearchParams', + 'ReadonlyArray', ]; // Types that are defined in a common layer but are known to be only diff --git a/build/yarn.lock b/build/yarn.lock index bd5fcfac717..27bc4dd9a10 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -502,9 +502,9 @@ integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== "@types/node@16.x": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/p-limit@^2.2.0": version "2.2.0" diff --git a/package.json b/package.json index 00872bd146c..e43a6b890e3 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "ts-loader": "^9.2.7", "ts-node": "^10.9.1", "tsec": "0.1.4", - "typescript": "^4.9.0-dev.20220921", + "typescript": "^4.9.0-dev.20221005", "typescript-formatter": "7.1.0", "underscore": "^1.12.1", "util": "^0.12.4", diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index 7168172c47a..e503b753a52 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -91,7 +91,7 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe this._logService.info(`Extension host agent started.`); } - public async handleRequest(req: http.IncomingMessage, res: http.ServerResponse) { + public async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise { // Only serve GET requests if (req.method !== 'GET') { return serveError(req, res, 405, `Unsupported method ${req.method}`); @@ -116,14 +116,14 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe // Version if (pathname === '/version') { res.writeHead(200, { 'Content-Type': 'text/plain' }); - return res.end(this._productService.commit || ''); + return void res.end(this._productService.commit || ''); } // Delay shutdown if (pathname === '/delay-shutdown') { this._delayShutdown(); res.writeHead(200); - return res.end('OK'); + return void res.end('OK'); } if (!httpRequestHasValidConnectionToken(this._connectionToken, req, parsedUrl)) { @@ -171,7 +171,7 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe } res.writeHead(404, { 'Content-Type': 'text/plain' }); - return res.end('Not found'); + return void res.end('Not found'); } public handleUpgrade(req: http.IncomingMessage, socket: net.Socket) { diff --git a/src/vs/server/node/webClientServer.ts b/src/vs/server/node/webClientServer.ts index e57259fc731..35cdf1e9590 100644 --- a/src/vs/server/node/webClientServer.ts +++ b/src/vs/server/node/webClientServer.ts @@ -61,7 +61,7 @@ export async function serveFile(filePath: string, cacheControl: CacheControl, lo const etag = `W/"${[stat.ino, stat.size, stat.mtime.getTime()].join('-')}"`; // weak validator (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) if (req.headers['if-none-match'] === etag) { res.writeHead(304); - return res.end(); + return void res.end(); } responseHeaders['Etag'] = etag; @@ -86,7 +86,7 @@ export async function serveFile(filePath: string, cacheControl: CacheControl, lo } res.writeHead(404, { 'Content-Type': 'text/plain' }); - return res.end('Not found'); + return void res.end('Not found'); } } @@ -232,7 +232,7 @@ export class WebClientServer { setResponseHeader('Content-Type'); res.writeHead(200, responseHeaders); const buffer = await streamToBuffer(context.stream); - return res.end(buffer.buffer); + return void res.end(buffer.buffer); } /** @@ -264,7 +264,7 @@ export class WebClientServer { responseHeaders['Location'] = newLocation; res.writeHead(302, responseHeaders); - return res.end(); + return void res.end(); } const getFirstHeader = (headerName: string) => { @@ -336,7 +336,7 @@ export class WebClientServer { data = workbenchTemplate.replace(/\{\{([^}]+)\}\}/g, (_, key) => values[key] ?? 'undefined'); } catch (e) { res.writeHead(404, { 'Content-Type': 'text/plain' }); - return res.end('Not found'); + return void res.end('Not found'); } const cspDirectives = [ @@ -372,7 +372,7 @@ export class WebClientServer { } res.writeHead(200, headers); - return res.end(data); + return void res.end(data); } private _getScriptCspHashes(content: string): string[] { @@ -413,6 +413,6 @@ export class WebClientServer { 'Content-Type': 'text/html', 'Content-Security-Policy': cspDirectives }); - return res.end(data); + return void res.end(data); } } diff --git a/test/automation/package.json b/test/automation/package.json index 239844d7df5..4ff47338bab 100644 --- a/test/automation/package.json +++ b/test/automation/package.json @@ -33,4 +33,4 @@ "npm-run-all": "^4.1.5", "watch": "^1.0.2" } -} \ No newline at end of file +} diff --git a/test/automation/yarn.lock b/test/automation/yarn.lock index 97df3a29fb2..3cfb4e7b414 100644 --- a/test/automation/yarn.lock +++ b/test/automation/yarn.lock @@ -22,9 +22,9 @@ integrity sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw== "@types/node@16.x": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/tmp@0.2.2": version "0.2.2" diff --git a/test/integration/browser/yarn.lock b/test/integration/browser/yarn.lock index b3498682cd8..1056ba89b05 100644 --- a/test/integration/browser/yarn.lock +++ b/test/integration/browser/yarn.lock @@ -34,9 +34,9 @@ integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ== "@types/node@16.x": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/optimist@0.0.29": version "0.0.29" diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index e73fb8b7865..42f75ad058a 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -59,9 +59,9 @@ integrity sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ== "@types/node@16.x": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/rimraf@3.0.2": version "3.0.2" diff --git a/yarn.lock b/yarn.lock index ebf28175131..f740fc6af04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1011,9 +1011,9 @@ integrity sha512-LXRap3bb4AjtLZ5NOFc4ssVZrQPTgdPcNm++0SEJuJZaOA+xHkojJNYqy33A5q/94BmG5tA6yaMeD4VdCv5aSA== "@types/node@16.x": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== + version "16.11.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.64.tgz#9171f327298b619e2c52238b120c19056415d820" + integrity sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q== "@types/node@^10.11.7": version "10.12.21" @@ -10817,10 +10817,10 @@ typescript@^2.6.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= -typescript@^4.9.0-dev.20220921: - version "4.9.0-dev.20220921" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.0-dev.20220921.tgz#ad0a24dcc94a29ee8d3845ad025ced94fe732d82" - integrity sha512-0WdiNgM0YfgPURswuah1JJfnDwa6e7Ki0DJcfAEruw17mACMCJw2F7vK/4jLcd1uIl4La3ZIPnA7dOyM7y5Skg== +typescript@^4.9.0-dev.20221005: + version "4.9.0-dev.20221005" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.0-dev.20221005.tgz#ebfb29da9c5b054736ba1e00b3d6aaad49e0228e" + integrity sha512-uKa1ioEqENveT1YE90O1PoX27pdr+wWvKOcpGJaDNninks4m2Ygjj5ZcHb+AKuqdc1b8A39EvSZDWSxXky9F2Q== typical@^4.0.0: version "4.0.0" From 518b9d9c8a70845c389c007a1466a826bc35259d Mon Sep 17 00:00:00 2001 From: Huiwen Date: Fri, 7 Oct 2022 03:20:48 +0800 Subject: [PATCH 385/599] Fix #161565 (#161567) Fix https://github.com/microsoft/vscode/issues/161565 --- src/vs/platform/telemetry/common/telemetryService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index bfe90f7fed7..3a9107bead0 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -203,7 +203,7 @@ export class TelemetryService implements ITelemetryService { { label: 'Google API Key', regex: /AIza[A-Za-z0-9_\\\-]{35}/ }, { label: 'Slack Token', regex: /xox[pbar]\-[A-Za-z0-9]/ }, { label: 'Generic Secret', regex: /(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]/ }, - { label: 'Email', regex: /@[a-zA-Z0-9-.]+/ } // Regex which matches @*.site + { label: 'Email', regex: /@[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+/ } // Regex which matches *@*.site ]; // Check for common user data in the telemetry events From 9051852b73c03144556d2b0011b03584d02f6ca1 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 6 Oct 2022 12:32:48 -0700 Subject: [PATCH 386/599] log more info when tasks to terminate is not found (#162839) --- src/vs/workbench/api/browser/mainThreadTask.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index be081d8e61f..18163ed9261 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -33,6 +33,7 @@ import { } from 'vs/workbench/api/common/shared/tasks'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ErrorNoTelemetry } from 'vs/base/common/errors'; namespace TaskExecutionDTO { export function from(value: ITaskExecution): ITaskExecutionDTO { @@ -649,7 +650,7 @@ export class MainThreadTask implements MainThreadTaskShape { return; } } - reject(new Error('Task to terminate not found')); + reject(new ErrorNoTelemetry('Task to terminate not found')); }); }); } From 9b063a81c9619f8c7bb0cae4cb1a14f0fdb3aa55 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 6 Oct 2022 12:51:33 -0700 Subject: [PATCH 387/599] Developer command for reloading notebook webview (#162872) --- .../browser/controller/layoutActions.ts | 41 ++++++++++++++++++- .../notebook/browser/notebookBrowser.ts | 4 +- .../notebook/browser/notebookEditorWidget.ts | 4 +- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts index 48ecba090de..8a168cc34e1 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Codicon } from 'vs/base/common/codicons'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -12,9 +13,12 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; -import { NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; +import { getNotebookEditorFromEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService'; import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; registerAction2(class NotebookConfigureLayoutAction extends Action2 { @@ -218,3 +222,38 @@ registerAction2(class SaveMimeTypeDisplayOrder extends Action2 { qp.show(); } }); + +registerAction2(class NotebookWebviewResetAction extends Action2 { + constructor() { + super({ + id: 'workbench.notebook.layout.webview.reset', + title: { + value: localize('workbench.notebook.layout.webview.reset.label', "Reset Notebook Webview"), + original: 'Reset Notebook Webview' + }, + f1: false, + category: NOTEBOOK_ACTIONS_CATEGORY + }); + } + run(accessor: ServicesAccessor, args?: UriComponents): void { + const editorService = accessor.get(IEditorService); + + if (args) { + const uri = URI.revive(args); + const notebookEditorService = accessor.get(INotebookEditorService); + const widgets = notebookEditorService.listNotebookEditors().filter(widget => widget.hasModel() && widget.textModel.uri.toString() === uri.toString()); + for (const widget of widgets) { + if (widget.hasModel()) { + widget.getInnerWebview()?.reload(); + } + } + } else { + const editor = getNotebookEditorFromEditorPane(editorService.activeEditorPane); + if (!editor) { + return; + } + + editor.getInnerWebview()?.reload(); + } + } +}); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index b95a790cc6d..9befc5ed2c3 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -25,7 +25,7 @@ import { isCompositeNotebookEditorInput } from 'vs/workbench/contrib/notebook/co import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; 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 { IWebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; //#region Shared commands @@ -441,7 +441,7 @@ export interface INotebookEditor { hasModel(): this is IActiveNotebookEditor; dispose(): void; getDomNode(): HTMLElement; - getInnerWebview(): IWebview | undefined; + getInnerWebview(): IWebviewElement | undefined; getSelectionViewModels(): ICellViewModel[]; /** diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index e7b2dc19892..21474118da4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -78,7 +78,7 @@ import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; -import { IWebview } from 'vs/workbench/contrib/webview/browser/webview'; +import { IWebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { NotebookPerfMarks } from 'vs/workbench/contrib/notebook/common/notebookPerformance'; @@ -992,7 +992,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD return this._overflowContainer; } - getInnerWebview(): IWebview | undefined { + getInnerWebview(): IWebviewElement | undefined { return this._webview?.webview; } From 5ab910f16f033fd196ca0961efebb00fb757f203 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 6 Oct 2022 13:41:49 -0700 Subject: [PATCH 388/599] no telemetry needed when task end event gets fired twice (#162861) fix #160572 --- src/vs/workbench/api/common/extHostTask.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index bf122d3ab2c..033b98d338f 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -25,7 +25,7 @@ import * as Platform from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; import { USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/tasks'; -import { NotSupportedError } from 'vs/base/common/errors'; +import { ErrorNoTelemetry, NotSupportedError } from 'vs/base/common/errors'; export interface IExtHostTask extends ExtHostTaskShape { @@ -631,7 +631,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask if (typeof execution === 'string') { const taskExecution = this._taskExecutionPromises.get(execution); if (!taskExecution) { - throw new Error('Unexpected: The specified task is missing an execution'); + throw new ErrorNoTelemetry('Unexpected: The specified task is missing an execution'); } return taskExecution; } From 908450a0212393c58edb085127f4d3246a11b9f1 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 6 Oct 2022 13:48:07 -0700 Subject: [PATCH 389/599] Update Get Started `h2` font weight (#162883) Update Get Started h2 font weight --- .../welcomeGettingStarted/browser/media/gettingStarted.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css index 7ca7220f167..fb3d9439dec 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css @@ -66,7 +66,7 @@ } .monaco-workbench .part.editor>.content .gettingStartedContainer h2 { - font-weight: 200; + font-weight: 400; margin-top: 0; margin-bottom: 5px; font-size: 1.5em; From 1a5101ff736f763216533e59de7e5c589d63cb83 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 14:19:28 -0700 Subject: [PATCH 390/599] Mark arguments to `WorkspaceEdit.set` readonly (#162888) These values are not modified. Mark these readonly to allow using these apis in more cases --- src/vs/workbench/api/common/extHostTypes.ts | 76 ++++++++++----------- src/vscode-dts/vscode.d.ts | 14 ++-- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 7f44f88a23e..f7b89d987a9 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -696,11 +696,11 @@ export class SnippetTextEdit implements vscode.SnippetTextEdit { } export interface IFileOperationOptions { - overwrite?: boolean; - ignoreIfExists?: boolean; - ignoreIfNotExists?: boolean; - recursive?: boolean; - contents?: Uint8Array; + readonly overwrite?: boolean; + readonly ignoreIfExists?: boolean; + readonly ignoreIfNotExists?: boolean; + readonly recursive?: boolean; + readonly contents?: Uint8Array; } export const enum FileEditType { @@ -712,43 +712,43 @@ export const enum FileEditType { } export interface IFileOperation { - _type: FileEditType.File; - from?: URI; - to?: URI; - options?: IFileOperationOptions; - metadata?: vscode.WorkspaceEditEntryMetadata; + readonly _type: FileEditType.File; + readonly from?: URI; + readonly to?: URI; + readonly options?: IFileOperationOptions; + readonly metadata?: vscode.WorkspaceEditEntryMetadata; } export interface IFileTextEdit { - _type: FileEditType.Text; - uri: URI; - edit: TextEdit; - metadata?: vscode.WorkspaceEditEntryMetadata; + readonly _type: FileEditType.Text; + readonly uri: URI; + readonly edit: TextEdit; + readonly metadata?: vscode.WorkspaceEditEntryMetadata; } export interface IFileSnippetTextEdit { - _type: FileEditType.Snippet; - uri: URI; - range: vscode.Range; - edit: vscode.SnippetString; - metadata?: vscode.WorkspaceEditEntryMetadata; + readonly _type: FileEditType.Snippet; + readonly uri: URI; + readonly range: vscode.Range; + readonly edit: vscode.SnippetString; + readonly metadata?: vscode.WorkspaceEditEntryMetadata; } export interface IFileCellEdit { - _type: FileEditType.Cell; - uri: URI; - edit?: ICellPartialMetadataEdit | IDocumentMetadataEdit; - notebookMetadata?: Record; - metadata?: vscode.WorkspaceEditEntryMetadata; + readonly _type: FileEditType.Cell; + readonly uri: URI; + readonly edit?: ICellPartialMetadataEdit | IDocumentMetadataEdit; + readonly notebookMetadata?: Record; + readonly metadata?: vscode.WorkspaceEditEntryMetadata; } export interface ICellEdit { - _type: FileEditType.CellReplace; - metadata?: vscode.WorkspaceEditEntryMetadata; - uri: URI; - index: number; - count: number; - cells: vscode.NotebookCellData[]; + readonly _type: FileEditType.CellReplace; + readonly metadata?: vscode.WorkspaceEditEntryMetadata; + readonly uri: URI; + readonly index: number; + readonly count: number; + readonly cells: vscode.NotebookCellData[]; } @@ -766,15 +766,15 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { // --- file - renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void { + renameFile(from: vscode.Uri, to: vscode.Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void { this._edits.push({ _type: FileEditType.File, from, to, options, metadata }); } - createFile(uri: vscode.Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean; contents?: Uint8Array }, metadata?: vscode.WorkspaceEditEntryMetadata): void { + createFile(uri: vscode.Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean; readonly contents?: Uint8Array }, metadata?: vscode.WorkspaceEditEntryMetadata): void { this._edits.push({ _type: FileEditType.File, from: undefined, to: uri, options, metadata }); } - deleteFile(uri: vscode.Uri, options?: { recursive?: boolean; ignoreIfNotExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void { + deleteFile(uri: vscode.Uri, options?: { readonly recursive?: boolean; readonly ignoreIfNotExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void { this._edits.push({ _type: FileEditType.File, from: uri, to: undefined, options, metadata }); } @@ -817,12 +817,12 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { return this._edits.some(edit => edit._type === FileEditType.Text && edit.uri.toString() === uri.toString()); } - set(uri: URI, edits: (TextEdit | SnippetTextEdit)[]): void; - set(uri: URI, edits: [TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata][]): void; - set(uri: URI, edits: NotebookEdit[]): void; - set(uri: URI, edits: [NotebookEdit, vscode.WorkspaceEditEntryMetadata][]): void; + set(uri: URI, edits: ReadonlyArray): void; + set(uri: URI, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata]>): void; + set(uri: URI, edits: readonly NotebookEdit[]): void; + set(uri: URI, edits: ReadonlyArray<[NotebookEdit, vscode.WorkspaceEditEntryMetadata]>): void; - set(uri: URI, edits: null | undefined | (TextEdit | SnippetTextEdit | NotebookEdit | [NotebookEdit, vscode.WorkspaceEditEntryMetadata] | [TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata])[]): void { + set(uri: URI, edits: null | undefined | ReadonlyArray): void { if (!edits) { // remove all text, snippet, or notebook edits for `uri` for (let i = 0; i < this._edits.length; i++) { diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 9939daa9e5c..c250e81aa67 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -3645,7 +3645,7 @@ declare module 'vscode' { * @param uri A resource identifier. * @param edits An array of edits. */ - set(uri: Uri, edits: NotebookEdit[]): void; + set(uri: Uri, edits: readonly NotebookEdit[]): void; /** * Set (and replace) notebook edits with metadata for a resource. @@ -3653,7 +3653,7 @@ declare module 'vscode' { * @param uri A resource identifier. * @param edits An array of edits. */ - set(uri: Uri, edits: [NotebookEdit, WorkspaceEditEntryMetadata][]): void; + set(uri: Uri, edits: ReadonlyArray<[NotebookEdit, WorkspaceEditEntryMetadata]>): void; /** * Set (and replace) text edits or snippet edits for a resource. @@ -3661,7 +3661,7 @@ declare module 'vscode' { * @param uri A resource identifier. * @param edits An array of edits. */ - set(uri: Uri, edits: (TextEdit | SnippetTextEdit)[]): void; + set(uri: Uri, edits: ReadonlyArray): void; /** * Set (and replace) text edits or snippet edits with metadata for a resource. @@ -3669,7 +3669,7 @@ declare module 'vscode' { * @param uri A resource identifier. * @param edits An array of edits. */ - set(uri: Uri, edits: [TextEdit | SnippetTextEdit, WorkspaceEditEntryMetadata][]): void; + set(uri: Uri, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, WorkspaceEditEntryMetadata]>): void; /** * Get the text edits for a resource. @@ -3690,7 +3690,7 @@ declare module 'vscode' { * the file is being created with. * @param metadata Optional metadata for the entry. */ - createFile(uri: Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean; contents?: Uint8Array }, metadata?: WorkspaceEditEntryMetadata): void; + createFile(uri: Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean; readonly contents?: Uint8Array }, metadata?: WorkspaceEditEntryMetadata): void; /** * Delete a file or folder. @@ -3698,7 +3698,7 @@ declare module 'vscode' { * @param uri The uri of the file that is to be deleted. * @param metadata Optional metadata for the entry. */ - deleteFile(uri: Uri, options?: { recursive?: boolean; ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; + deleteFile(uri: Uri, options?: { readonly recursive?: boolean; readonly ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; /** * Rename a file or folder. @@ -3709,7 +3709,7 @@ declare module 'vscode' { * ignored. When overwrite and ignoreIfExists are both set overwrite wins. * @param metadata Optional metadata for the entry. */ - renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; + renameFile(oldUri: Uri, newUri: Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void; /** * Get all text edits grouped by resource. From 4803d07197cd1f8f7e80e840488bb8f7803b106f Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 6 Oct 2022 14:31:49 -0700 Subject: [PATCH 391/599] Align "Show welcome page on startup" checkbox elements (#162887) * Align "Show welcome page on startup" checkbox elements * Adjust value --- .../welcomeGettingStarted/browser/media/gettingStarted.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css index fb3d9439dec..7537aa9a1e6 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css @@ -751,6 +751,8 @@ text-align: center; display: flex; justify-content: center; + align-items: center; + gap: 8px; } .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { From 4affcdb07c275abdf9944180e7c6e3e82ad3edb2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 15:00:49 -0700 Subject: [PATCH 392/599] Add documentation and clean up IWebviewWorkbenchService (#162792) --- .../api/browser/mainThreadWebviewPanels.ts | 6 +- .../update/browser/releaseNotesEditor.ts | 2 +- .../browser/webviewEditorInputSerializer.ts | 2 +- .../browser/webviewWorkbenchService.ts | 118 ++++++++++-------- 4 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index 79a0765ef3e..c3a2a739715 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -15,7 +15,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; import { WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; -import { ICreateWebViewShowOptions, IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { IWebViewShowOptions, IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { GroupLocation, GroupsOrder, IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP, IEditorService, PreferredGroup, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; @@ -158,14 +158,14 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc showOptions: extHostProtocol.WebviewPanelShowOptions, ): void { const targetGroup = this.getTargetGroupFromShowOptions(showOptions); - const mainThreadShowOptions: ICreateWebViewShowOptions = showOptions ? { + const mainThreadShowOptions: IWebViewShowOptions = showOptions ? { preserveFocus: !!showOptions.preserveFocus, group: targetGroup } : {}; const extension = reviveWebviewExtension(extensionData); - const webview = this._webviewWorkbenchService.createWebview({ + const webview = this._webviewWorkbenchService.openWebview({ id: handle, providedViewType: viewType, options: reviveWebviewOptions(initData.panelOptions), diff --git a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index 8b83776c6b7..b31141ebf75 100644 --- a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -74,7 +74,7 @@ export class ReleaseNotesManager { this._currentReleaseNotes.webview.html = html; this._webviewWorkbenchService.revealWebview(this._currentReleaseNotes, activeEditorPane ? activeEditorPane.group : this._editorGroupService.activeGroup, false); } else { - this._currentReleaseNotes = this._webviewWorkbenchService.createWebview( + this._currentReleaseNotes = this._webviewWorkbenchService.openWebview( { id: generateUuid(), options: { diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts index 9adca06119c..5e0aa8c5be8 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts @@ -77,7 +77,7 @@ export class WebviewEditorInputSerializer implements IEditorSerializer { serializedEditorInput: string ): WebviewInput { const data = this.fromJson(JSON.parse(serializedEditorInput)); - return this._webviewWorkbenchService.reviveWebview({ + return this._webviewWorkbenchService.openRevivedWebview({ webviewInitInfo: { id: data.id, providedViewType: data.providedId, diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts index 97e206c6ec9..ff558a0c806 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts @@ -24,26 +24,45 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; import { WebviewInput, WebviewInputInitInfo } from './webviewEditorInput'; -export const IWebviewWorkbenchService = createDecorator('webviewEditorService'); - -export interface ICreateWebViewShowOptions { +export interface IWebViewShowOptions { readonly group?: IEditorGroup | GroupIdentifier | ACTIVE_GROUP_TYPE | SIDE_GROUP_TYPE; readonly preserveFocus?: boolean; } +export const IWebviewWorkbenchService = createDecorator('webviewEditorService'); + +/** + * Service responsible for showing and managing webview editors in the workbench. + */ export interface IWebviewWorkbenchService { readonly _serviceBrand: undefined; + /** + * Manages setting the icons show for a given webview. + */ readonly iconManager: WebviewIconManager; - createWebview( + /** + * Event fired when focus switches to a different webview editor. + * + * Fires `undefined` if focus switches to a non-webview editor. + */ + readonly onDidChangeActiveWebviewEditor: Event; + + /** + * Create a new webview editor and open it in the workbench. + */ + openWebview( webviewInitInfo: WebviewInitInfo, viewType: string, title: string, - showOptions: ICreateWebViewShowOptions, + showOptions: IWebViewShowOptions, ): WebviewInput; - reviveWebview(options: { + /** + * Open a webview that is being restored from serialization. + */ + openRevivedWebview(options: { webviewInitInfo: WebviewInitInfo; viewType: string; title: string; @@ -52,49 +71,57 @@ export interface IWebviewWorkbenchService { group: number | undefined; }): WebviewInput; + /** + * Reveal an already opened webview editor in the workbench. + */ revealWebview( webview: WebviewInput, group: IEditorGroup | GroupIdentifier | ACTIVE_GROUP_TYPE | SIDE_GROUP_TYPE, preserveFocus: boolean ): void; - registerResolver( - resolver: WebviewResolver - ): IDisposable; + /** + * Register a new {@link WebviewResolver}. + * + * If there are any webviews awaiting revival that this resolver can handle, they will be resolved by it. + */ + registerResolver(resolver: WebviewResolver): IDisposable; - shouldPersist( - input: WebviewInput - ): boolean; + /** + * Check if a webview should be serialized across window reloads. + */ + shouldPersist(input: WebviewInput): boolean; - resolveWebview( - webview: WebviewInput, - ): CancelablePromise; - - readonly onDidChangeActiveWebviewEditor: Event; + /** + * Try to resolve a webview. This will block until a resolver is registered for the webview. + */ + resolveWebview(webview: WebviewInput, token: CancellationToken): Promise; } +/** + * Handles filling in the content of webview before it can be shown to the user. + */ export interface WebviewResolver { - canResolve( - webview: WebviewInput, - ): boolean; + /** + * Returns true if the resolver can resolve the given webview. + */ + canResolve(webview: WebviewInput): boolean; - resolveWebview( - webview: WebviewInput, - cancellation: CancellationToken, - ): Promise; + /** + * Resolves the webview. + */ + resolveWebview(webview: WebviewInput, token: CancellationToken): Promise; } function canRevive(reviver: WebviewResolver, webview: WebviewInput): boolean { return reviver.canResolve(webview); } - export class LazilyResolvedWebviewEditorInput extends WebviewInput { #resolved = false; #resolvePromise?: CancelablePromise; - constructor( init: WebviewInputInitInfo, webview: IOverlayWebview, @@ -113,7 +140,7 @@ export class LazilyResolvedWebviewEditorInput extends WebviewInput { public override async resolve() { if (!this.#resolved) { this.#resolved = true; - this.#resolvePromise = this._webviewWorkbenchService.resolveWebview(this); + this.#resolvePromise = createCancelablePromise(token => this._webviewWorkbenchService.resolveWebview(this, token)); try { await this.#resolvePromise; } catch (e) { @@ -248,11 +275,11 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc } } - public createWebview( + public openWebview( webviewInitInfo: WebviewInitInfo, viewType: string, title: string, - showOptions: ICreateWebViewShowOptions, + showOptions: IWebViewShowOptions, ): WebviewInput { const webview = this._webviewService.createWebviewOverlay(webviewInitInfo); const webviewInput = this._instantiationService.createInstance(WebviewInput, { id: webviewInitInfo.id, viewType, name: title, providedId: webviewInitInfo.providedViewType }, webview, this.iconManager); @@ -295,7 +322,7 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc return webview; } - public reviveWebview(options: { + public openRevivedWebview(options: { webviewInitInfo: WebviewInitInfo; viewType: string; title: string; @@ -315,9 +342,7 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc return webviewInput; } - public registerResolver( - reviver: WebviewResolver - ): IDisposable { + public registerResolver(reviver: WebviewResolver): IDisposable { this._revivers.add(reviver); const cts = new CancellationTokenSource(); @@ -329,10 +354,8 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc }); } - public shouldPersist( - webview: WebviewInput - ): boolean { - // Revived webviews may not have an actively registered reviver but we still want to presist them + public shouldPersist(webview: WebviewInput): boolean { + // Revived webviews may not have an actively registered reviver but we still want to persist them // since a reviver should exist when it is actually needed. if (webview instanceof LazilyResolvedWebviewEditorInput) { return true; @@ -341,27 +364,22 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc return Iterable.some(this._revivers.values(), reviver => canRevive(reviver, webview)); } - private async tryRevive( - webview: WebviewInput, - cancellation: CancellationToken, - ): Promise { + private async tryRevive(webview: WebviewInput, token: CancellationToken): Promise { for (const reviver of this._revivers.values()) { if (canRevive(reviver, webview)) { - await reviver.resolveWebview(webview, cancellation); + await reviver.resolveWebview(webview, token); return true; } } return false; } - public resolveWebview(webview: WebviewInput): CancelablePromise { - return createCancelablePromise(async (cancellation) => { - const didRevive = await this.tryRevive(webview, cancellation); - if (!didRevive) { - // A reviver may not be registered yet. Put into pool and resolve promise when we can revive - return this._revivalPool.enqueueForRestoration(webview, cancellation); - } - }); + public async resolveWebview(webview: WebviewInput, token: CancellationToken): Promise { + const didRevive = await this.tryRevive(webview, token); + if (!didRevive && !token.isCancellationRequested) { + // A reviver may not be registered yet. Put into pool and resolve promise when we can revive + return this._revivalPool.enqueueForRestoration(webview, token); + } } public setIcons(id: string, iconPath: WebviewIcons | undefined): void { From ef0bf16e87c70823477b6f94a5deac53e53bf951 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 6 Oct 2022 15:19:17 -0700 Subject: [PATCH 393/599] testing: focus to file when diff is opened (#162894) Fixes #155559 --- .../contrib/testing/browser/testingExplorerView.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index fac697c8f62..6f3b60c0027 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -46,6 +46,7 @@ import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platfor import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { HierarchicalByLocationProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation'; import { ByNameTestItemElement, HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName'; @@ -602,7 +603,12 @@ export class TestingExplorerViewModel extends Disposable { })); const onEditorChange = () => { - this.filter.filterToDocumentUri(editorService.activeEditor?.resource); + if (editorService.activeEditor instanceof DiffEditorInput) { + this.filter.filterToDocumentUri(editorService.activeEditor.primary.resource); + } else { + this.filter.filterToDocumentUri(editorService.activeEditor?.resource); + } + if (this.filterState.isFilteringFor(TestFilterTerm.CurrentDoc)) { this.tree.refilter(); } From 7ef53c918afdbbb0e094f9517ec3bf2715fcf268 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 6 Oct 2022 15:21:52 -0700 Subject: [PATCH 394/599] testing: make sure actionbar is visible on list row focus (#162891) Fixes #162759 --- src/vs/workbench/contrib/testing/browser/media/testing.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/media/testing.css b/src/vs/workbench/contrib/testing/browser/media/testing.css index 504ecb13ac7..2b6cbe6dbb2 100644 --- a/src/vs/workbench/contrib/testing/browser/media/testing.css +++ b/src/vs/workbench/contrib/testing/browser/media/testing.css @@ -43,8 +43,8 @@ .test-explorer .monaco-list-row:hover .monaco-action-bar, .test-output-peek-tree .monaco-list-row:hover .monaco-action-bar, -.test-explorer .monaco-list-row:focus .monaco-action-bar, -.test-output-peek-tree .monaco-list-row:focus .monaco-action-bar { +.test-explorer .monaco-list-row.focused .monaco-action-bar, +.test-output-peek-tree .monaco-list-row.focused .monaco-action-bar { display: initial; } @@ -54,7 +54,7 @@ } .test-explorer .monaco-list-row:hover .codicon-testing-hidden, -.test-explorer .monaco-list-row:focus .codicon-testing-hidden { +.test-explorer .monaco-list-row.focused .codicon-testing-hidden { display: none; } From e6765420459e838c6dc57c471906c9ad67f009c9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 15:27:34 -0700 Subject: [PATCH 395/599] Fix Webview find widget animation and restore (#162895) Fixes #162457 --- .../browser/find/simpleFindWidget.css | 4 ++ .../browser/find/simpleFindWidget.ts | 17 ++++++-- .../contrib/webview/browser/overlayWebview.ts | 42 ++++++++----------- .../contrib/webview/browser/webview.ts | 4 +- .../contrib/webview/browser/webviewElement.ts | 8 ++-- .../webview/browser/webviewFindWidget.ts | 4 +- 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css index 50fde909c9f..74b3d08aebd 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css @@ -38,6 +38,10 @@ visibility: visible; } +.monaco-workbench .simple-find-part.suppress-transition { + transition: none; +} + .monaco-workbench .simple-find-part.visible-transition { top: 0; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index fbb881c8f56..10d1756462d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -254,7 +254,7 @@ export abstract class SimpleFindWidget extends Widget { return this._domNode; } - public reveal(initialInput?: string): void { + public reveal(initialInput?: string, animated = true): void { if (initialInput) { this._findInput.setValue(initialInput); } @@ -269,9 +269,16 @@ export abstract class SimpleFindWidget extends Widget { this.layout(); setTimeout(() => { + this._innerDomNode.classList.toggle('suppress-transition', !animated); this._innerDomNode.classList.add('visible', 'visible-transition'); this._innerDomNode.setAttribute('aria-hidden', 'false'); this._findInput.select(); + + if (!animated) { + setTimeout(() => { + this._innerDomNode.classList.remove('suppress-transition'); + }, 0); + } }, 0); } @@ -285,20 +292,22 @@ export abstract class SimpleFindWidget extends Widget { setTimeout(() => { this._innerDomNode.classList.add('visible', 'visible-transition'); + this._innerDomNode.setAttribute('aria-hidden', 'false'); }, 0); } - public hide(): void { + public hide(animated = true): void { if (this._isVisible) { + this._innerDomNode.classList.toggle('suppress-transition', !animated); this._innerDomNode.classList.remove('visible-transition'); this._innerDomNode.setAttribute('aria-hidden', 'true'); // Need to delay toggling visibility until after Transition, then visibility hidden - removes from tabIndex list setTimeout(() => { this._isVisible = false; this.updateButtons(this._foundMatch); - this._innerDomNode.classList.remove('visible'); - }, 200); + this._innerDomNode.classList.remove('visible', 'suppress-transition'); + }, animated ? 200 : 0); } } diff --git a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts index 24aeee9cfa7..b3d0e5afd70 100644 --- a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts +++ b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts @@ -42,8 +42,7 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { private readonly _scopedContextKeyService = this._register(new MutableDisposable()); private _findWidgetVisible: IContextKey | undefined; private _findWidgetEnabled: IContextKey | undefined; - // This isn't associated with an editor action so doesn't need to be a context key - private _findActiveWhenHidden: boolean | undefined = false; + private _shouldShowFindWidgetOnRestore = false; public readonly id: string; public readonly providedViewType?: string; @@ -127,8 +126,10 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { this._scopedContextKeyService.clear(); this._scopedContextKeyService.value = contextKeyService.createScoped(this.container); + const wasFindVisible = this._findWidgetVisible?.get(); this._findWidgetVisible?.reset(); this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(contextKeyService); + this._findWidgetVisible.set(!!wasFindVisible); this._findWidgetEnabled?.reset(); this._findWidgetEnabled = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_ENABLED.bindTo(contextKeyService); @@ -149,10 +150,12 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { if (this._container) { this._container.style.visibility = 'hidden'; } + if (this._options.retainContextWhenHidden) { // https://github.com/microsoft/vscode/issues/157424 // We need to record the current state when retaining context so we can try to showFind() when showing webview again - this.hideFind(); + this._shouldShowFindWidgetOnRestore = !!this._findWidgetVisible?.get(); + this.hideFind(false); } else { this._webview.clear(); this._webviewEvents.clear(); @@ -213,9 +216,6 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { this._webview.value.setContextKeyService(this._scopedContextKeyService.value); } - // https://github.com/microsoft/vscode/issues/157424 - this.tryShowFind(); - if (this._html) { webview.html = this._html; } @@ -257,6 +257,13 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { this._firstLoadPendingMessages.clear(); } + // https://github.com/microsoft/vscode/issues/157424 + if (this.options.retainContextWhenHidden && this._shouldShowFindWidgetOnRestore) { + this.showFind(false); + // Reset + this._shouldShowFindWidgetOnRestore = false; + } + this.container.style.visibility = 'visible'; } @@ -345,31 +352,16 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { undo(): void { this._webview.value?.undo(); } redo(): void { this._webview.value?.redo(); } - /** - * Only meant to be used when we're showing webview as an attempt to reload the previously hidden - * find widget when retaining context - */ - tryShowFind() { - const shouldShowFind: boolean | undefined = ( - (this.options.retainContextWhenHidden && this._findActiveWhenHidden) - ); - - if (shouldShowFind) { - this.showFind(); - } - } - - showFind() { + showFind(animated = true) { if (this._webview.value) { - this._webview.value.showFind(); + this._webview.value.showFind(animated); this._findWidgetVisible?.set(true); } } - hideFind() { - this._findActiveWhenHidden = this._findWidgetVisible?.get(); + hideFind(animated = true) { this._findWidgetVisible?.reset(); - this._webview.value?.hideFind(); + this._webview.value?.hideFind(animated); } runFindAction(previous: boolean): void { this._webview.value?.runFindAction(previous); } diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index 83296c95ac4..801cdae6d56 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -192,8 +192,8 @@ export interface IWebview extends IDisposable { focus(): void; reload(): void; - showFind(): void; - hideFind(): void; + showFind(animated?: boolean): void; + hideFind(animated?: boolean): void; runFindAction(previous: boolean): void; selectAll(): void; diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 2d7cb9c0866..bb38d8b1756 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -950,12 +950,12 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this._onDidStopFind.fire(); } - public showFind() { - this._webviewFindWidget?.reveal(); + public showFind(animated = true) { + this._webviewFindWidget?.reveal(undefined, animated); } - public hideFind() { - this._webviewFindWidget?.hide(); + public hideFind(animated = true) { + this._webviewFindWidget?.hide(animated); } public runFindAction(previous: boolean) { diff --git a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts index e75d7ed26cd..29de5c74126 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts @@ -53,8 +53,8 @@ export class WebviewFindWidget extends SimpleFindWidget { } } - public override hide() { - super.hide(); + public override hide(animated = true) { + super.hide(animated); this._delegate.stopFind(true); this._delegate.focus(); } From a4c9ea968db6c90a8bee3e349850df98eb7940f1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 6 Oct 2022 15:37:27 -0700 Subject: [PATCH 396/599] Pick up latest versions of eslint (#162896) --- .eslintignore | 2 + package.json | 6 +- yarn.lock | 168 ++++++++++++++++++-------------------------------- 3 files changed, 66 insertions(+), 110 deletions(-) diff --git a/.eslintignore b/.eslintignore index e3aedfea0d6..af5f9a4940b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,6 +6,7 @@ **/extensions/css-language-features/server/test/pathCompletionFixtures/** **/extensions/html-language-features/server/lib/jquery.d.ts **/extensions/html-language-features/server/src/test/pathCompletionFixtures/** +**/extensions/ipynb/notebook-out/** **/extensions/markdown-language-features/media/** **/extensions/markdown-language-features/notebook-out/** **/extensions/markdown-math/notebook-out/** @@ -27,4 +28,5 @@ **/src/vs/base/test/common/filters.perf.data.js **/src/vs/loader.js **/test/unit/assert.js +**/test/automation/out/** **/typings/** diff --git a/package.json b/package.json index 3b5fe22114b..176e0a7ccb0 100644 --- a/package.json +++ b/package.json @@ -125,9 +125,9 @@ "@types/winreg": "^1.2.30", "@types/yauzl": "^2.9.1", "@types/yazl": "^2.4.2", - "@typescript-eslint/eslint-plugin": "^5.10.0", - "@typescript-eslint/experimental-utils": "^5.10.0", - "@typescript-eslint/parser": "^5.10.0", + "@typescript-eslint/eslint-plugin": "^5.39.0", + "@typescript-eslint/experimental-utils": "^5.39.0", + "@typescript-eslint/parser": "^5.39.0", "@vscode/telemetry-extractor": "^1.9.8", "@vscode/test-web": "^0.0.29", "ansi-colors": "^3.2.3", diff --git a/yarn.lock b/yarn.lock index 4b2a6e357c0..eef5ad9c708 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1156,137 +1156,91 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz#e90afea96dff8620892ad216b0e4ccdf8ee32d3a" - integrity sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ== +"@typescript-eslint/eslint-plugin@^5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.39.0.tgz#778b2d9e7f293502c7feeea6c74dca8eb3e67511" + integrity sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A== dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/type-utils" "5.10.0" - "@typescript-eslint/utils" "5.10.0" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" + "@typescript-eslint/scope-manager" "5.39.0" + "@typescript-eslint/type-utils" "5.39.0" + "@typescript-eslint/utils" "5.39.0" + debug "^4.3.4" + ignore "^5.2.0" regexpp "^3.2.0" - semver "^7.3.5" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@^5.10.0": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.35.1.tgz#4ec46ad8cd04001e44536f427c553f120a262c9b" - integrity sha512-nF7JD9alMkhEx50QYDUdP8koeHtldnm7EfZkr68ikkc87ffFBIPkH3dqoWyOeQeIiJicB0uHzpMXKR6PP+1Jbg== +"@typescript-eslint/experimental-utils@^5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.39.0.tgz#9263bb72b57449cc2f07ffb7fd4e12d0160b7f5e" + integrity sha512-n5N9kG/oGu2xXhHzsWzn94s6CWoiUj59FPU2dF2IQZxPftw+q6Jm5sV2vj5qTgAElRooHhrgtl2gxBQDCPt6WA== dependencies: - "@typescript-eslint/utils" "5.35.1" + "@typescript-eslint/utils" "5.39.0" -"@typescript-eslint/parser@^5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.0.tgz#8f59e036f5f1cffc178cacbd5ccdd02aeb96c91c" - integrity sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw== +"@typescript-eslint/parser@^5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.39.0.tgz#93fa0bc980a3a501e081824f6097f7ca30aaa22b" + integrity sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA== dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" - debug "^4.3.2" + "@typescript-eslint/scope-manager" "5.39.0" + "@typescript-eslint/types" "5.39.0" + "@typescript-eslint/typescript-estree" "5.39.0" + debug "^4.3.4" -"@typescript-eslint/scope-manager@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz#bb5d872e8b9e36203908595507fbc4d3105329cb" - integrity sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg== +"@typescript-eslint/scope-manager@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz#873e1465afa3d6c78d8ed2da68aed266a08008d0" + integrity sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw== dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" + "@typescript-eslint/types" "5.39.0" + "@typescript-eslint/visitor-keys" "5.39.0" -"@typescript-eslint/scope-manager@5.35.1": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.35.1.tgz#ccb69d54b7fd0f2d0226a11a75a8f311f525ff9e" - integrity sha512-kCYRSAzIW9ByEIzmzGHE50NGAvAP3wFTaZevgWva7GpquDyFPFcmvVkFJGWJJktg/hLwmys/FZwqM9EKr2u24Q== +"@typescript-eslint/type-utils@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.39.0.tgz#0a8c00f95dce4335832ad2dc6bc431c14e32a0a6" + integrity sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA== dependencies: - "@typescript-eslint/types" "5.35.1" - "@typescript-eslint/visitor-keys" "5.35.1" - -"@typescript-eslint/type-utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz#8524b9479c19c478347a7df216827e749e4a51e5" - integrity sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ== - dependencies: - "@typescript-eslint/utils" "5.10.0" - debug "^4.3.2" + "@typescript-eslint/typescript-estree" "5.39.0" + "@typescript-eslint/utils" "5.39.0" + debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.0.tgz#beb3cb345076f5b088afe996d57bcd1dfddaa75c" - integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== +"@typescript-eslint/types@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.39.0.tgz#f4e9f207ebb4579fd854b25c0bf64433bb5ed78d" + integrity sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw== -"@typescript-eslint/types@5.35.1": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.35.1.tgz#af355fe52a0cc88301e889bc4ada72f279b63d61" - integrity sha512-FDaujtsH07VHzG0gQ6NDkVVhi1+rhq0qEvzHdJAQjysN+LHDCKDKCBRlZFFE0ec0jKxiv0hN63SNfExy0KrbQQ== - -"@typescript-eslint/typescript-estree@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz#4be24a3dea0f930bb1397c46187d0efdd955a224" - integrity sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA== +"@typescript-eslint/typescript-estree@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz#c0316aa04a1a1f4f7f9498e3c13ef1d3dc4cf88b" + integrity sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA== dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@5.35.1": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.35.1.tgz#db878a39a0dbdc9bb133f11cdad451770bfba211" - integrity sha512-JUqE1+VRTGyoXlDWWjm6MdfpBYVq+hixytrv1oyjYIBEOZhBCwtpp5ZSvBt4wIA1MKWlnaC2UXl2XmYGC3BoQA== - dependencies: - "@typescript-eslint/types" "5.35.1" - "@typescript-eslint/visitor-keys" "5.35.1" + "@typescript-eslint/types" "5.39.0" + "@typescript-eslint/visitor-keys" "5.39.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.0.tgz#c3d152a85da77c400e37281355561c72fb1b5a65" - integrity sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg== +"@typescript-eslint/utils@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.39.0.tgz#b7063cca1dcf08d1d21b0d91db491161ad0be110" + integrity sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" + "@typescript-eslint/scope-manager" "5.39.0" + "@typescript-eslint/types" "5.39.0" + "@typescript-eslint/typescript-estree" "5.39.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/utils@5.35.1": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.35.1.tgz#ae1399afbfd6aa7d0ed1b7d941e9758d950250eb" - integrity sha512-v6F8JNXgeBWI4pzZn36hT2HXXzoBBBJuOYvoQiaQaEEjdi5STzux3Yj8v7ODIpx36i/5s8TdzuQ54TPc5AITQQ== +"@typescript-eslint/visitor-keys@5.39.0": + version "5.39.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz#8f41f7d241b47257b081ddba5d3ce80deaae61e2" + integrity sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg== dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.35.1" - "@typescript-eslint/types" "5.35.1" - "@typescript-eslint/typescript-estree" "5.35.1" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz#770215497ad67cd15a572b52089991d5dfe06281" - integrity sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ== - dependencies: - "@typescript-eslint/types" "5.10.0" - eslint-visitor-keys "^3.0.0" - -"@typescript-eslint/visitor-keys@5.35.1": - version "5.35.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.35.1.tgz#285e9e34aed7c876f16ff646a3984010035898e6" - integrity sha512-cEB1DvBVo1bxbW/S5axbGPE6b7FIMAbo3w+AGq6zNDA7+NYJOIkKj/sInfTv4edxd4PxJSgdN4t6/pbvgA+n5g== - dependencies: - "@typescript-eslint/types" "5.35.1" + "@typescript-eslint/types" "5.39.0" eslint-visitor-keys "^3.3.0" "@ungap/promise-all-settled@1.1.2": @@ -4242,7 +4196,7 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: +eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== @@ -5291,7 +5245,7 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" -globby@^11.0.4, globby@^11.1.0: +globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -5921,7 +5875,7 @@ ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== From b9ebb059dbf78156c22326f77c090aeb2186e359 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 6 Oct 2022 15:56:37 -0700 Subject: [PATCH 397/599] testing: use real test item instances if available in command args (#162898) Fixes https://github.com/microsoft/vscode/issues/154659 (for realsies) --- src/vs/workbench/api/common/extHostTesting.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index bf44c8939d4..e6f7569b906 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -23,7 +23,7 @@ import * as Convert from 'vs/workbench/api/common/extHostTypeConverters'; import { TestRunProfileKind, TestRunRequest } from 'vs/workbench/api/common/extHostTypes'; import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId'; import { InvalidTestItemError } from 'vs/workbench/contrib/testing/common/testItemCollection'; -import { AbstractIncrementalTestCollection, CoverageDetails, IFileCoverage, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, ITestItem, RunTestForControllerRequest, RunTestForControllerResult, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes'; +import { AbstractIncrementalTestCollection, CoverageDetails, IFileCoverage, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, ITestItem, ITestItemContext, RunTestForControllerRequest, RunTestForControllerResult, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes'; import type * as vscode from 'vscode'; interface ControllerInfo { @@ -52,8 +52,16 @@ export class ExtHostTesting implements ExtHostTestingShape { this.runTracker = new TestRunCoordinator(this.proxy); commands.registerArgumentProcessor({ - processArgument: arg => - arg?.$mid === MarshalledId.TestItemContext ? toItemFromContext(arg) : arg, + processArgument: arg => { + if (arg?.$mid !== MarshalledId.TestItemContext) { + return arg; + } + + const cast = arg as ITestItemContext; + const targetTest = cast.tests[cast.tests.length - 1].item.extId; + const controller = this.controllers.get(TestId.root(targetTest)); + return controller?.collection.tree.get(targetTest)?.actual ?? toItemFromContext(arg); + } }); } From fad3a77833b9249158dfd88477114a06435e46a2 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 6 Oct 2022 16:02:09 -0700 Subject: [PATCH 398/599] debug: remove timeout connecting to renderer (#162899) Fixes #159835 --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d0c0ed97f49..3bf8c67198f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -230,7 +230,7 @@ "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" }, "port": 9222, - "timeout": 20000, + "timeout": 0, "env": { "VSCODE_EXTHOST_WILL_SEND_SOCKET": null, "VSCODE_SKIP_PRELAUNCH": "1" From 6c4c53813d8b7340d44f4722536206a6473b7146 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 7 Oct 2022 00:28:52 -0700 Subject: [PATCH 399/599] Small cleanup of dispose (#162906) * Skip dispose if there's nothing to dispose of * Dispose should take an Iterable, not an IterableIterator We can use `for of` on any iterable, not just on iterable iterators --- src/vs/base/common/iterator.ts | 2 +- src/vs/base/common/lifecycle.ts | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 2771802f1de..7d6e1da0c0d 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -5,7 +5,7 @@ export namespace Iterable { - export function is(thing: any): thing is IterableIterator { + export function is(thing: any): thing is Iterable { return thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function'; } diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index da910eb4e77..e36513cfbfc 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -118,10 +118,10 @@ export function isDisposable(thing: E): thing is E & IDisposab export function dispose(disposable: T): T; export function dispose(disposable: T | undefined): T | undefined; -export function dispose = IterableIterator>(disposables: IterableIterator): A; +export function dispose = Iterable>(disposables: A): A; export function dispose(disposables: Array): Array; export function dispose(disposables: ReadonlyArray): ReadonlyArray; -export function dispose(arg: T | IterableIterator | undefined): any { +export function dispose(arg: T | Iterable | undefined): any { if (Iterable.is(arg)) { const errors: any[] = []; @@ -177,7 +177,7 @@ export class DisposableStore implements IDisposable { static DISABLE_DISPOSED_WARNING = false; - private _toDispose = new Set(); + private readonly _toDispose = new Set(); private _isDisposed = false; constructor() { @@ -210,8 +210,12 @@ export class DisposableStore implements IDisposable { * Dispose of all registered disposables but do not mark this object as disposed. */ public clear(): void { + if (this._toDispose.size === 0) { + return; + } + try { - dispose(this._toDispose.values()); + dispose(this._toDispose); } finally { this._toDispose.clear(); } From f91b3ac8ca669c68a4532990265b83ecc628678c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 7 Oct 2022 09:31:05 +0200 Subject: [PATCH 400/599] Fix #162502 (#162912) --- .../browser/extensionsWorkbenchService.ts | 4 +- .../extensionsActions.test.ts | 83 +++++++++++++++++-- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 49f40c5807f..adc6daaa487 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -1030,12 +1030,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension const extensionInOtherServer = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier) && e.server !== extension!.server)[0]; if (extensionInOtherServer) { // This extension prefers to run on UI/Local side but is running in remote - if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local!.manifest)) { + if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local!.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.localExtensionManagementServer) { return nls.localize('enable locally', "Please reload Visual Studio Code to enable this extension locally."); } // This extension prefers to run on Workspace/Remote side but is running in local - if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local!.manifest)) { + if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local!.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.remoteExtensionManagementServer) { return nls.localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label); } } diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index fc6df1e1d1a..bc185062083 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -1647,6 +1647,62 @@ suite('ReloadAction', () => { assert.ok(testObject.extension); assert.ok(testObject.enabled); }); + + test('Test ReloadAction when ui+workspace+web extension is installed in web and remote and running in remote', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const webExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeUserData }) }); + const remoteExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, null, createExtensionManagementService([remoteExtension]), createExtensionManagementService([webExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + instantiationService.stub(IExtensionService, >{ + extensions: [toExtensionDescription(remoteExtension)], + onDidChangeExtensions: Event.None, + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) + }); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when workspace+ui+web extension is installed in web and local and running in local', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const webExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeUserData }) }); + const localExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'], 'browser': 'browser.js' }, { location: URI.file('pub.a') }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), null, createExtensionManagementService([webExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + instantiationService.stub(IExtensionService, >{ + extensions: [toExtensionDescription(localExtension)], + onDidChangeExtensions: Event.None, + canAddExtension: (extension) => false, + whenInstalledExtensionsRegistered: () => Promise.resolve(true) + }); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); }); suite('RemoteInstallAction', () => { @@ -2520,22 +2576,27 @@ function aSingleRemoteExtensionManagementServerService(instantiationService: Tes }; } -function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IProfileAwareExtensionManagementService, remoteExtensionManagementService?: IProfileAwareExtensionManagementService): IExtensionManagementServerService { - const localExtensionManagementServer: IExtensionManagementServer = { +function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IProfileAwareExtensionManagementService | null, remoteExtensionManagementService?: IProfileAwareExtensionManagementService | null, webExtensionManagementService?: IProfileAwareExtensionManagementService): IExtensionManagementServerService { + const localExtensionManagementServer: IExtensionManagementServer | null = localExtensionManagementService === null ? null : { id: 'vscode-local', label: 'local', extensionManagementService: localExtensionManagementService || createExtensionManagementService(), }; - const remoteExtensionManagementServer: IExtensionManagementServer = { + const remoteExtensionManagementServer: IExtensionManagementServer | null = remoteExtensionManagementService === null ? null : { id: 'vscode-remote', label: 'remote', extensionManagementService: remoteExtensionManagementService || createExtensionManagementService(), }; + const webExtensionManagementServer: IExtensionManagementServer | null = webExtensionManagementService ? { + id: 'vscode-web', + label: 'web', + extensionManagementService: webExtensionManagementService, + } : null; return { _serviceBrand: undefined, localExtensionManagementServer, remoteExtensionManagementServer, - webExtensionManagementServer: null, + webExtensionManagementServer, getExtensionManagementServer: (extension: IExtension) => { if (extension.location.scheme === Schemas.file) { return localExtensionManagementServer; @@ -2543,11 +2604,23 @@ function aMultiExtensionManagementServerService(instantiationService: TestInstan if (extension.location.scheme === Schemas.vscodeRemote) { return remoteExtensionManagementServer; } + if (extension.location.scheme === Schemas.vscodeUserData) { + return webExtensionManagementServer; + } throw new Error(''); }, getExtensionInstallLocation(extension: IExtension): ExtensionInstallLocation | null { const server = this.getExtensionManagementServer(extension); - return server === remoteExtensionManagementServer ? ExtensionInstallLocation.Remote : ExtensionInstallLocation.Local; + if (server === null) { + return null; + } + if (server === remoteExtensionManagementServer) { + return ExtensionInstallLocation.Remote; + } + if (server === webExtensionManagementServer) { + return ExtensionInstallLocation.Web; + } + return ExtensionInstallLocation.Local; } }; } From d23eca8c900bfb9aa2732add402587262da06212 Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 7 Oct 2022 09:47:16 +0200 Subject: [PATCH 401/599] align setting to search collapse/expand setting --- .../browser/outline/documentSymbolsOutline.ts | 6 +++--- .../outline/browser/outline.contribution.ts | 14 +++++++------- .../workbench/services/outline/browser/outline.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index 5dc1430ba00..0446e776815 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -104,8 +104,8 @@ class DocumentSymbolBreadcrumbsSource implements IBreadcrumbsDataSource { @@ -161,7 +161,7 @@ class DocumentSymbolsOutline implements IOutline { } }; const comparator = new DocumentSymbolComparator(); - const initialState = textResourceConfigurationService.getValue(_editor.getModel()?.uri, OutlineConfigKeys.initialState); + const initialState = textResourceConfigurationService.getValue(_editor.getModel()?.uri, OutlineConfigKeys.collapseItems); const options = { collapseByDefault: target === OutlineTarget.Breadcrumbs || (target === OutlineTarget.OutlinePane && initialState === DocumentSymbolsOutlineInitialState.Collapsed), expandOnlyOnTwistieClick: true, diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index d4620a4d3b4..3492875c13d 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -44,19 +44,19 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'type': 'boolean', 'default': true }, - [OutlineConfigKeys.initialState]: { - 'description': localize('outline.initialState', "Initial state of outline."), + [OutlineConfigKeys.collapseItems]: { + 'description': localize('outline.initialState', "Controls whether outline items are collapsed or expanded."), 'type': 'string', scope: ConfigurationScope.LANGUAGE_OVERRIDABLE, 'enum': [ - 'collapsed', - 'expanded' + 'alwaysCollapse', + 'alwaysExpand' ], 'enumDescriptions': [ - localize('outline.initialState.collapsed', "Collapse all nodes upon loading."), - localize('outline.initialState.expanded', "Expand all nodes upon loading.") + localize('outline.initialState.collapsed', "Collapse all items."), + localize('outline.initialState.expanded', "Expand all items.") ], - 'default': 'expanded' + 'default': 'alwaysExpand' }, [OutlineConfigKeys.problemsEnabled]: { 'description': localize('outline.showProblem', "Show errors and warnings on outline elements."), diff --git a/src/vs/workbench/services/outline/browser/outline.ts b/src/vs/workbench/services/outline/browser/outline.ts index e0ca0de4f6a..be7a8ecb9f6 100644 --- a/src/vs/workbench/services/outline/browser/outline.ts +++ b/src/vs/workbench/services/outline/browser/outline.ts @@ -92,7 +92,7 @@ export interface IOutline { export const enum OutlineConfigKeys { 'icons' = 'outline.icons', - 'initialState' = 'outline.initialState', + 'collapseItems' = 'outline.collapseItems', 'problemsEnabled' = 'outline.problems.enabled', 'problemsColors' = 'outline.problems.colors', 'problemsBadges' = 'outline.problems.badges' From 83720bca0fed68666e1d40986b7fefefdc989a0c Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Fri, 7 Oct 2022 10:03:29 +0200 Subject: [PATCH 402/599] Add spaces to required fields (#162875) --- .github/ISSUE_TEMPLATE/bug_report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8a44ce8c7ac..ce9e17c1c96 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,10 +13,10 @@ Does this issue occur when all extensions are disabled?: Yes/No -- VS Code Version: -- OS Version: +- VS Code Version: +- OS Version: Steps to Reproduce: -1. -2. +1. +2. From b64e2d11cc24293e60b2240bfa57e1199154bf2c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 7 Oct 2022 10:21:11 +0200 Subject: [PATCH 403/599] remove microtask delay when refiltering suggestions (#162744) It seems now safe to read the editor position at the time of a document change event. This removes nasty faulty completion insertion for fast typists fixes https://github.com/microsoft/vscode/issues/161883 --- .../contrib/suggest/browser/suggestModel.ts | 24 ++--- .../test/browser/suggestController.test.ts | 102 ++++++++++++++++++ .../suggest/test/browser/suggestModel.test.ts | 35 ++++-- 3 files changed, 133 insertions(+), 28 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index b31ba921faf..e1c6778e15f 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -29,6 +29,7 @@ import { CompletionDurations, CompletionItem, CompletionOptions, getSnippetSugge import { IWordAtPosition } from 'vs/editor/common/core/wordHelper'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { FuzzyScoreOptions } from 'vs/base/common/filters'; +import { assertType } from 'vs/base/common/types'; export interface ICancelEvent { readonly retrigger: boolean; @@ -424,23 +425,12 @@ export class SuggestModel implements IDisposable { } private _refilterCompletionItems(): void { - // Re-filter suggestions. This MUST run async because filtering/scoring - // uses the model content AND the cursor position. The latter is NOT - // updated when the document has changed (the event which drives this method) - // and therefore a little pause (next mirco task) is needed. See: - // https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#25933985 - Promise.resolve().then(() => { - if (this._state === State.Idle) { - return; - } - if (!this._editor.hasModel()) { - return; - } - const model = this._editor.getModel(); - const position = this._editor.getPosition(); - const ctx = new LineContext(model, position, this._state === State.Auto, false, false); - this._onNewContext(ctx); - }); + assertType(this._editor.hasModel()); + + const model = this._editor.getModel(); + const position = this._editor.getPosition(); + const ctx = new LineContext(model, position, this._state === State.Auto, false, false); + this._onNewContext(ctx); } trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set, existing?: { items: CompletionItem[]; clipboardText: string | undefined }, noFilter?: boolean): void { diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestController.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestController.test.ts index cfde37e9e3d..fce75a30b85 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestController.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestController.test.ts @@ -462,4 +462,106 @@ suite('SuggestController', function () { assert.strictEqual(editor.getValue(), 'import "my_class.txt";\nMyClassName'); }); + + test('Pressing enter on autocomplete should always apply the selected dropdown completion, not a different, hidden one #161883', async function () { + disposables.add(languageFeaturesService.completionProvider.register({ scheme: 'test-ctrl' }, { + provideCompletionItems(doc, pos) { + + const word = doc.getWordUntilPosition(pos); + const range = new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn); + + return { + suggestions: [{ + kind: CompletionItemKind.Text, + label: 'filterBankSize', + insertText: 'filterBankSize', + sortText: 'a', + range + }, { + kind: CompletionItemKind.Text, + label: 'filter', + insertText: 'filter', + sortText: 'b', + range + }] + }; + } + })); + + editor.setValue('filte'); + editor.setSelection(new Selection(1, 6, 1, 6)); + + const p1 = Event.toPromise(controller.model.onDidSuggest); + controller.triggerSuggest(); + + const { completionModel } = await p1; + assert.strictEqual(completionModel.items.length, 2); + + const [first, second] = completionModel.items; + assert.strictEqual(first.textLabel, 'filterBankSize'); + assert.strictEqual(second.textLabel, 'filter'); + + assert.deepStrictEqual(editor.getSelection(), new Selection(1, 6, 1, 6)); + editor.trigger('keyboard', 'type', { text: 'r' }); // now filter "overtakes" filterBankSize because it is fully matched + assert.deepStrictEqual(editor.getSelection(), new Selection(1, 7, 1, 7)); + + controller.acceptSelectedSuggestion(false, false); + assert.strictEqual(editor.getValue(), 'filter'); + }); + + test('Fast autocomple typing selects the previous autocomplete suggestion, #71795', async function () { + disposables.add(languageFeaturesService.completionProvider.register({ scheme: 'test-ctrl' }, { + provideCompletionItems(doc, pos) { + + const word = doc.getWordUntilPosition(pos); + const range = new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn); + + return { + suggestions: [{ + kind: CompletionItemKind.Text, + label: 'false', + insertText: 'false', + range + }, { + kind: CompletionItemKind.Text, + label: 'float', + insertText: 'float', + range + }, { + kind: CompletionItemKind.Text, + label: 'for', + insertText: 'for', + range + }, { + kind: CompletionItemKind.Text, + label: 'foreach', + insertText: 'foreach', + range + }] + }; + } + })); + + editor.setValue('f'); + editor.setSelection(new Selection(1, 2, 1, 2)); + + const p1 = Event.toPromise(controller.model.onDidSuggest); + controller.triggerSuggest(); + + const { completionModel } = await p1; + assert.strictEqual(completionModel.items.length, 4); + + const [first, second, third, fourth] = completionModel.items; + assert.strictEqual(first.textLabel, 'false'); + assert.strictEqual(second.textLabel, 'float'); + assert.strictEqual(third.textLabel, 'for'); + assert.strictEqual(fourth.textLabel, 'foreach'); + + assert.deepStrictEqual(editor.getSelection(), new Selection(1, 2, 1, 2)); + editor.trigger('keyboard', 'type', { text: 'o' }); // filters`false` and `float` + assert.deepStrictEqual(editor.getSelection(), new Selection(1, 3, 1, 3)); + + controller.acceptSelectedSuggestion(false, false); + assert.strictEqual(editor.getValue(), 'for'); + }); }); diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index 0a1b3dda2de..d60987964ca 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -407,9 +407,9 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { model.setValue(''); - return withOracle((model, editor) => { + return withOracle(async (model, editor) => { - return assertEvent(model.onDidSuggest, () => { + await assertEvent(model.onDidSuggest, () => { editor.setPosition({ lineNumber: 1, column: 1 }); editor.trigger('keyboard', Handler.Type, { text: 'foo' }); @@ -419,16 +419,29 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { const [first] = event.completionModel.items; assert.strictEqual(first.completion.label, 'foo.bar'); - return assertEvent(model.onDidSuggest, () => { - editor.trigger('keyboard', Handler.Type, { text: '.' }); + }); - }, event => { - assert.strictEqual(event.auto, true); - assert.strictEqual(event.completionModel.items.length, 2); - const [first, second] = event.completionModel.items; - assert.strictEqual(first.completion.label, 'foo.bar'); - assert.strictEqual(second.completion.label, 'boom'); - }); + await assertEvent(model.onDidSuggest, () => { + editor.trigger('keyboard', Handler.Type, { text: '.' }); + + }, event => { + // SYNC + assert.strictEqual(event.auto, true); + assert.strictEqual(event.completionModel.items.length, 1); + const [first] = event.completionModel.items; + assert.strictEqual(first.completion.label, 'foo.bar'); + }); + + await assertEvent(model.onDidSuggest, () => { + // nothing -> triggered by the trigger character typing (see above) + + }, event => { + // ASYNC + assert.strictEqual(event.auto, true); + assert.strictEqual(event.completionModel.items.length, 2); + const [first, second] = event.completionModel.items; + assert.strictEqual(first.completion.label, 'foo.bar'); + assert.strictEqual(second.completion.label, 'boom'); }); }); }); From 49605ab0ec51acd6df2c5d7d0a42350fcb9abac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 7 Oct 2022 01:23:18 -0700 Subject: [PATCH 404/599] avoid :hover styling when dragging from a list (#162918) Fixes: #153977 --- src/vs/base/browser/ui/list/listView.ts | 3 +++ src/vs/base/browser/ui/list/listWidget.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 345ce1af0b6..82fb5b18639 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -1035,6 +1035,7 @@ export class ListView implements ISpliceable, IDisposable { setTimeout(() => document.body.removeChild(dragImage), 0); } + this.domNode.classList.add('dragging'); this.currentDragData = new ElementsDragAndDropData(elements); StaticDND.CurrentDragAndDropData = new ExternalElementsDragAndDropData(elements); @@ -1150,6 +1151,7 @@ export class ListView implements ISpliceable, IDisposable { const dragData = this.currentDragData; this.teardownDragAndDropScrollTopAnimation(); this.clearDragOverFeedback(); + this.domNode.classList.remove('dragging'); this.currentDragData = undefined; StaticDND.CurrentDragAndDropData = undefined; @@ -1166,6 +1168,7 @@ export class ListView implements ISpliceable, IDisposable { this.canDrop = false; this.teardownDragAndDropScrollTopAnimation(); this.clearDragOverFeedback(); + this.domNode.classList.remove('dragging'); this.currentDragData = undefined; StaticDND.CurrentDragAndDropData = undefined; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 8ed5f2d8602..a0d02b2c621 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -869,11 +869,11 @@ export class DefaultStyleController implements IStyleController { } if (styles.listHoverBackground) { - content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); + content.push(`.monaco-list${suffix}:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); } if (styles.listHoverForeground) { - content.push(`.monaco-list${suffix} .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`); + content.push(`.monaco-list${suffix}:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`); } if (styles.listSelectionOutline) { From e8ccdd7dbea3f61876788c629da58a575a91fd79 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 7 Oct 2022 13:23:38 +0200 Subject: [PATCH 405/599] delayed service shouldn't be created by early listeners (#162928) Injected service proxies can be created via event listeners. We can be smart about that because these proxies won't ever fire aways --- .../common/instantiationService.ts | 40 ++++++++++++ .../test/common/instantiationService.test.ts | 65 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 3840b1bec11..bf9deb002c5 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -4,11 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IdleValue } from 'vs/base/common/async'; +import { Event } from 'vs/base/common/event'; import { illegalState } from 'vs/base/common/errors'; +import { toDisposable } from 'vs/base/common/lifecycle'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Graph } from 'vs/platform/instantiation/common/graph'; import { IInstantiationService, ServiceIdentifier, ServicesAccessor, _util } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { LinkedList } from 'vs/base/common/linkedList'; // TRACING const _enableAllTracing = false @@ -246,15 +249,52 @@ export class InstantiationService implements IInstantiationService { // Return a proxy object that's backed by an idle value. That // strategy is to instantiate services in our idle time or when actually // needed but not when injected into a consumer + + // return "empty events" when the service isn't instantiated yet + const earlyListeners = new Map>>>(); + const idle = new IdleValue(() => { const result = child._createInstance(ctor, args, _trace); + + // early listeners that we kept are now being subscribed to + // the real service + for (const [key, values] of earlyListeners) { + const candidate = >(result)[key]; + if (typeof candidate === 'function') { + for (const listener of values) { + candidate.apply(result, listener); + } + } + } + earlyListeners.clear(); + return result; }); return new Proxy(Object.create(null), { get(target: any, key: PropertyKey): any { + + if (!idle.isInitialized) { + // looks like an event + if (typeof key === 'string' && (key.startsWith('onDid') || key.startsWith('onWill'))) { + let list = earlyListeners.get(key); + if (!list) { + list = new LinkedList(); + earlyListeners.set(key, list); + } + const event: Event = (callback, thisArg, disposables) => { + const rm = list!.push([callback, thisArg, disposables]); + return toDisposable(rm); + }; + return event; + } + } + + // value already exists if (key in target) { return target[key]; } + + // create value const obj = idle.value; let prop = obj[key]; if (typeof prop !== 'function') { diff --git a/src/vs/platform/instantiation/test/common/instantiationService.test.ts b/src/vs/platform/instantiation/test/common/instantiationService.test.ts index a737b46533c..fabe3100318 100644 --- a/src/vs/platform/instantiation/test/common/instantiationService.test.ts +++ b/src/vs/platform/instantiation/test/common/instantiationService.test.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { Emitter, Event } from 'vs/base/common/event'; +import { dispose } from 'vs/base/common/lifecycle'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; @@ -459,4 +461,67 @@ suite('Instantiation Service', () => { assert.strictEqual(cycle, 'A -> B -> A'); } }); + + test('Delayed and events', function () { + const A = createDecorator('A'); + interface A { + _serviceBrand: undefined; + onDidDoIt: Event; + doIt(): void; + } + + let created = false; + class AImpl implements A { + _serviceBrand: undefined; + _doIt = 0; + + _onDidDoIt = new Emitter(); + onDidDoIt: Event = this._onDidDoIt.event; + + constructor() { + created = true; + } + + doIt(): void { + this._doIt += 1; + this._onDidDoIt.fire(this); + } + } + + const insta = new InstantiationService(new ServiceCollection( + [A, new SyncDescriptor(AImpl, undefined, true)], + ), true, undefined, true); + + class Consumer { + constructor(@A readonly a: A) { + // eager subscribe -> NO service instance + } + } + + const c: Consumer = insta.createInstance(Consumer); + let eventCount = 0; + + // subscribing to event doesn't trigger instantiation + const listener = (e: any) => { + assert.ok(e instanceof AImpl); + eventCount++; + }; + const d1 = c.a.onDidDoIt(listener); + const d2 = c.a.onDidDoIt(listener); + assert.strictEqual(created, false); + assert.strictEqual(eventCount, 0); + d2.dispose(); + + // instantiation happens on first call + c.a.doIt(); + assert.strictEqual(created, true); + assert.strictEqual(eventCount, 1); + + + const d3 = c.a.onDidDoIt(listener); + c.a.doIt(); + assert.strictEqual(eventCount, 3); + + dispose([d1, d3]); + }); }); From f4fb3f3e58c886461239452c34b1de1543a521df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 7 Oct 2022 05:00:58 -0700 Subject: [PATCH 406/599] update inno_updater to 0.9.0 (#162933) --- build/win32/Cargo.lock | 371 +++++++++++++++++++++-------------- build/win32/inno_updater.exe | Bin 403456 -> 443904 bytes 2 files changed, 222 insertions(+), 149 deletions(-) diff --git a/build/win32/Cargo.lock b/build/win32/Cargo.lock index e27f58bf455..0601c70fb9e 100644 --- a/build/win32/Cargo.lock +++ b/build/win32/Cargo.lock @@ -1,258 +1,331 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "build_const" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = 3 [[package]] -name = "byteorder" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.0" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] -name = "crc" -version = "1.7.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "build_const" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" dependencies = [ - "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "build_const", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", ] [[package]] name = "inno_updater" -version = "0.8.2" +version = "0.9.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "crc", + "slog", + "slog-async", + "slog-term", + "winapi", ] [[package]] -name = "isatty" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" +name = "itoa" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "libc" -version = "0.2.36" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] -name = "num" -version = "0.1.41" +name = "num_threads" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "num-integer" -version = "0.1.35" +name = "once_cell" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident", ] [[package]] -name = "num-iter" -version = "0.1.34" +name = "quote" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] -[[package]] -name = "num-traits" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "redox_syscall" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] -name = "slog" -version = "2.1.1" +name = "redox_users" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "rustversion" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" [[package]] name = "slog-async" -version = "2.2.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" dependencies = [ - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", ] [[package]] name = "slog-term" -version = "2.3.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c" dependencies = [ - "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "slog", + "term", + "thread_local", + "time", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "take_mut" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "term" -version = "0.4.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-next", + "rustversion", + "winapi", ] [[package]] -name = "termion" -version = "1.5.1" +name = "thiserror" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thread_local" -version = "0.3.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", ] [[package]] name = "time" -version = "0.1.39" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "libc", + "num_threads", + "time-macros", ] [[package]] -name = "unreachable" -version = "1.0.0" +name = "time-macros" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" [[package]] -name = "void" -version = "1.0.2" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" -"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" -"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" -"checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" -"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9936036cc70fe4a8b2d338ab665900323290efb03983c86cbe235ae800ad8017" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6b13b17f4225771f7f15cece704a4e68d3a5f31278ed26367f497133398a18" -"checksum slog-async 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e319a30c08b004618d5f7ca2f2b1dad7b4623ba7fcb1a12846fc3b01e9eaa10" -"checksum slog-term 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bb5d9360b2b279b326824b3b4ca2402ead8a8138f0e5ec1900605c861bb6671" -"checksum take_mut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50b910a1174df4aeb5738e8a0e7253883cf7801de40d094175a5a557e487f4c5" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index 8c532b9eb5eab2fe843d29b8d488676263e4c1d7..fea47a59c9dae3b351f96a05c4d4d1e9040fe9df 100644 GIT binary patch literal 443904 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°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%0A9)8TdoI|6;GG3~5i)v%cQ8QBLt|FyQov;x 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 VWWM(w1v!UrE)o16{~!PFe*tpjB0>NF literal 403456 zcmeFa3wTw<)&GAI4tT`Cjv6&;ln6%+N;OfcM56`>7Zo)K22{KjX+)|BCyGina8BB6 z52vLqZEdC1)?Tb_-xmvV5i1GU1kh4Y%he)kt8+YF5Ut#l{6F8>d!Hm+dVAmJ|NNfk z_saukuRXJ7X3d(l)~s1Gd+#f*n;q&B3WdV_Z)*#M7IW2KrTzWKKareJsAsQddxjPq z{>M`m=ZyH{DWhv|pISV5%3WWca?4kWzjVu;cit5%zV)`^DRp-i-+pIt)m5X4zjD|3 z+s^9IqkGh^`pIo?J@?*>)Q7?UzwJKx!?(GAK0WJ$5A3z^gI)IOez476zwyDlT-|qO zeegG~@6DL?;asjU<9_hIy-$6pa`%`iAL{-d^G%z6_3dA(RU3!uQT32eXhcre(4$v9 zc|(A+Ez~>bh@77Jp`XH?nRJ%Fr+*Hd56~ozReEr4DAbKR{RP+1%|M{^db?XFH&i*p zBC4DU+iUis#L)DsyM|s9Fu7}J#6ki4{grkL<()>eS9A@H-Y-kHi?8e&D&$(owNeSe zA9TLzkshRUx}FugZCZ?!oj>vWrM{|b9sY_#p_|W|GX9p>EuqlKKPE$cf1K+tIwMxX zkh46r&@5%$+%-h!L!qHuJN#8r!&y_NPWcjPwy*Tr3f}Mo@G8%ma@(Z4KvdsD@E}y8 zinw<8s|U?spF?Sn-nnt{F9^X2yF7YDoSjI#-uj(MNO{ z5_&SL;A^4hS|@HsaZ<)0o3xtrpfLe9*qk+artl!VX(rS`m%!`jYd_^^{KU;U{@y z^3rfwTPhJ1DNe6?enak>=5*Nk+4`dTHy!tt#tro^me#k9so&GxS@?>x@O5X<=3(xR z!`C#9ZA(?Q)va5iLVb77*o^{*oVd(~n|@aMG^RQ;&i$b5{nT@Q^?rXhHD{>5xhU$m z%NtwjSC`heoL@oh%bkVmok44dxGN9e)HtRs^-x>gD_-sCp!RR6_K$4s*NmB%Tbns% zNGLODnfOW19_;HZTIsHAHo3PqS+1EQ?^rv&?>aaYFvqeb-nuWotNT|E50^GpRdl&3 zlkY4_gv7cDZdFAtxzDRYzZa>hig4e3HPsAK)#XD%=J(yYgyJvc&v-$-x$&m!Z&>kc zJ&-x(^e!Rih^%}lEf9=EbdK(h{B$|;(JHX;)8)mUbl9e5?A7=?Gl#=Ao3P~C;})$8 z#$%)Vmz{4kzuV*X<-+Rw2WQbAI(2c^_<;VtpU>DU32|R>7Jcq4dhQaxQ~f`i;7;$q zFLlpn_dXrpWBIhaQxz-6_g(EQTJ0|Hz^DHE;w}69F2ouA)U!}tzr3_@bpN(1)4x|Y z@{yed(Rx64ZC0KUn`RR}gyb|dG3Gb6rS55~+mN}qz4*onX9fCD|CY)(Zf)FLzoxW) z`T6yGk&Ug+!k3*vuMDI7ipCnR{9-lSch^M{ys6iFB3Ba##Q=9RJ$1f$R9jnH`aFK% z(NO_A)H5qIwooeEzwgd5*#Ukn><_T2w*%}pdqaHAsT$%jHOW{sum0lPDZ`QvhLgj> zZRfY;$6pW>pB4_qij$Ybr$r8*8Zk3d;n0{&#N5xd?cUEOhN?{+VDg@@`7+lUC5#8S z@g~o*So31-OZ>f}K3L%H+U`7kW&TA< zaT3EQTE5FkT*7s!P4etP^3FU=TSHUb$;qJ+Tja)|NP#U<_m}h$0PfJd_*cUa^C&lP zBFAZX%7a3!l@TiB64u2@e1&u~o(b?8vEUYfVL>agA7&O}l;X`1^PQ$Hp(MRe=EQg9 zIt{-=InsaSr$aZsW)-WZ+FeUezA=l+ZD;CA()WRgNLGPf5OvquUU$NA5;dTduXPev zs?IwrlSA?vnqsde3*CZfd@sEGFQrclCx=H`?Huh6txVPoZ+O{B?4}{cCG1X*Mv_;K zC|~#RHThF}BwnuT;a)kSWk`NbCY*RVmhawK)fSE>g#>cuwB(gl?!Y`ZZLZzWh5jdl z{sUyzXZ5FHi#slwPt^r9Q5ZWsH6mJI-ub+(Euhg!^hKVNg_g*}4?$#1f)lpHISZlg zc&Ix*pf0~%+a}D0(mbD1QCXj*a{hX#eEwmd%B29A%}%e7hnv0z8sgLP7*y-4wN~bN zV=EJ#9ktl`@m)Ew6A_*vi0<~bNZsgob2$D&k@PBk)Mf_QOTMT>@*P{V$)|Nlp7VM( z+3Apc(Kbo9t#HMXrh!O)Unr=pJ{QR!xZ9WfC6yz%J?CiY?~+6oX&#U%$|ALweoq-) zf{Y2Xds5}maC!vSPx$X?s`o2%5NSKlJnn`=@dqQJ*pX83uW@G;JPvSUNBzcqh`$%1 zP+|PyQ0#>I2lGR91@0T}4znEd@o+d=(dFLW6}hpK+bb&%DmzbYybytVD-f%L8lPUi z@#zZcD2&hNjToP)*7)oKH1G2>Mr!vifSRcLQRX)t`_qwDr6;RsXaq8x-!?g7dY*4t zx<68f3a)YgrY`<<*W&79QS5MZV6tO5>i2S)%N<{^x3 zPpxhTuWJWuESM8Y&5BmY6jfn0hD63xo0|%A#jvt1$pz6$StDrRl2dnBa&EK=sP2nq z%h$u9i4n2nEue-bC((42mEnB1)Eygk2Zmb*Mxy zwO{TBl(UJ|rlwJRiny_8RVo&p21Uc&(a{mDRncnd2yq>)Yi$!%P7KwUP2bbV=B28l zRW_}rdW@NJr_%E4J-&6RyN=qzl#Hm5x=OE8qod)8m1e_-c39Ls5_9UNsCz)k=PXM} zw@h{t7f`gJ%}MlUAz|M58ZweT1<-FJ*O_@I2x68B4-L1S=gn*GZ3#B-0tVM?6tc1gHG(BNQu+%9q2h!%fCl7)G}++ka@O2Y zp%2A=M**W~VI;mQ?8J`|*Gnii@kCWn3M7%06?R*Hay>5U$IgStjPR~KfTOCQsF*fmDrgsAd2Y^@)(0W)n|#D&LM#L^vZE^0 zQW-hYZNwX;YN)C+~L$x*Og@BgDyAICcS4eIz zIA5GS*%q89d<-I)o=~K!KcoKEaD0yhVlrYDM*XCY1DyErV&UK70Sn&;Qr|zv%KtMK zZat8Rb5)UL;?Mkwo=`>YOr+6*fRT4)k?-}9?-BBU$jH6$D`4a6Vq-p))}&tx*jR$U zbrAk{A-SE6Z;6c?W~v}lspjr*s(M$lOmnQ|Uck8`cdHX0BHsN9Y)|~21`_X@v5EhT zcL#{yt*XXyZlYh!?W*SBocm%H`63^=LdgFi=LV>!zOojH0qbXo0mln`5wPtZJ7cy0 znx*{M8FMkf(yda~_nna@sKF#a*KX*%LKqAl8`uNvZ1XKFcS`LAFL=T(s6_``U*Bwr>Oy z8w?it-)6h3YAoBon*mN0Q~X2gUXu3j74nXZweM zu>DOgmhGkn&4Fy*{nY?5$43ka@jqnq zT!gq?x~EH|AEAMo^nC(TfIgcW0b%n4Tr8WX0WAHNSXI={Dy@ZWNl9qDsoqMb6-{RR z+7PCCVu%2peAQ|*A7>gbae{N#srk#RSm56Eg`2(W7bknyi|V;94t>_vM&=9re~JIE z^8d97&Xn!F_*vJDpB+W~e0(B5+m!aEe%|6|OV?ss&z57Vz3X2lI3G59)lB*5WU$^4 zR*zDf`{7CwROyH70Bp9Z`*5?@ric3nvUZ$6p)~+%XbWrI4`1;}+V>8LAD_gJZT+N5 zuU>MeyqpW#YW}bM*m-DHSblB1i2z!Zg{S2UT#-v(E$)z6Z60MI4R;oU(6*#%Ut61& z8R(P#w9N29XW^W@{uC@F1{NW%bZ%mfDj!()_Rh8CD_jrJX_!qZysiqY#<*oiaIHCEr=YKexbOaqv-G9nZ^3Ue{s+|IqNaRNZ< zwoh!7ZN|QV^ea|4u}`gl8uPMU>=Kl58U`|=Gp0ue6rv6fo?z8y>CpifoCd{1(qH69 z%O|;845D2ed6MBTF-u;k3e`sNlhwi7y~-Kjq9p||XXhJEeIGjFuAsffGNdHHSbota4{rk)%QCtNxtCD-5-o!HXZ8xeS+H zsIcMYRNl7-wT+05b^AAR+uw~f5>RT4@IS9{Tq8kgLIe{?JP$_KPD{=8JZ=_+(BkfPH&4uExf!W3pWbiRpYe;;PdZ_)5GIcG3`9BOS&YzX^`M9tuI@nn>B0BKGId)t)U9a+W7ZD2*KxF{{IG9~x=%H=dX zhS^X5hM#3y&KnY1s#!(?kUO2X1^`M?9w$$?sytcco&wVwwW|+5e%H7s8d`*pN%Q6wpB z4H= zJ>sne@fGh8pSvU!`#5>;XXb}>zB&6ofR|hMra~^V0T6aS$q<$=!eT-p=%Msmz4QX5 zkMq*4A->E@w}!aNOK0hjczRD;n>owNv&Or`gR9J`9?}TBwz(jsf5p!dh1@-Bb-`9y zt0kdg5+paKub045z{e=`613L$Fb?w)6h0_>xpo>{HlMIijB6XgJd8p*N4UE^)Ytx^ z+9%9TVp-=O{h$56g0f%vAC#Z*KPda3()|C*wU71P@c%ac*YW=b{@=&{Yx)0G{*UDU zHT=Jw{|)@Vh5s)9JA{lof$j0*Mg-RU7S&B9qQ5~jnN~}PmdtLc64(z=3IX5Ud2B3xwWbT3mlWL9#S zynbMaQUhp@QX+;pS5j)rP18psXTdyb7XZPKg07CP~1ia*B%?Wl3lF;V#GYIitP&QNg!F+Z&0yaft?0R-4@~t z0?fTx#D{#u+k{x!9ze`@TN}10gs4vWA;dEP2_eS%91z5cjqsv3Q~R4DDy+%$Hw9|K zhVhjmTB2$KmvqH48@;#El8&DNIp(hHwDK09*~pLeyZ;Qp+!t>6)M@;*+PX2%kz}3K zKLA)a=C5RUZp?GufOtf^3#?2s;(Bhber89H@lrb6_R$kj9VLUqiRe6liFvh; zBiUw_MUNl?b8R{zu&Ks$>#mKA@F;W9qn?B$qAyX1N+r9HTui%S-AV=s@X*>Z{6&WN zIV-B*1#*g#tfeAS0&zv0?Xec`^a6Kt$w%tdEO)-<2!%q@oO#k5)BzB*gKG^w1=xYc zu(g^RdDzZPr>yRBEE8lA!Yd6Ld9|k$xIJntwZKz_k5CfPXfF7DCw16i?#s)nL*U>_ zDNgp4;@Chbp8f+$QDvh(1*pZFUkTLWT_8!!8(01VwP^X5)xuT9Ui`deABX$-q>g9@CFS}fRkE*H1yDlIUoIWd zMC2|XQ)6D+t7apxR!KQ^ebHGvPt3B)$C6QI0iH-@sY4xAb(y|w!wJ#n3LC^TKF@(U z=ih+~=~*7mSfoH@vrUEB%u-dRI|$xb9|febK4Ancu$4K$T0(aP#eXJ3-HK@J7@Bz; z*t{~)AGNgr45rA%Bqv@bc#!1iSRfmT%2P>LV2zXcaZu<{fb?m~VHX!FI187EQ!N`Z z?>Hc+^f35Ye<8^KLRE|2+ zc*IHQ5QHfRC^-p$PB-iVD?Q+HvUcANL#)f3C3lb}p;- z%Z{b2e+(t7vmHj!X*iEHX?iF>|Av~Cv1DgbVIU+o9o1|lJ+Nxl1b}QR-`-0)&97=9 z&n{b@1`-dpUus8MXbfPKLb?`OwWx}g=-#!CgeTurRmrIu{lPa~7|eeBAC6%3!=NPE zs;ICVaf0E>X=qAShMlTruLy(=%}YKg7sRX16hekIILC+{_HCO~+{>iKV&=Pg8bKC2 zDA^o*GW1O;md^Hho0(Vr^c6aPH8L^RsyQiAeBZH?8IfZLe-hNrq^Cwu=tf;UU({_S zS(-#qDf7*z4^oyq$o9EV%^zeglwk?x!ZD`mJ9e<#_3kEjd5yV^5T?e?Q~kgm_$Gku z8%#IBrNY|L7;;EZgNl@DzIR)y&0V9;3G z21iNpHjYVsgHSrG7O^g;ojeXPXnD0Gyr!$jQPbP$WwrTKYto>!maZ8@=C0or@Y z2Cb3$s?DD~w6afw?1YjP@4_sPGV{D_tkk5g(5;q6QMQtuHg`p}`IeXMr_Z%bk1`K< zsquXrQk&Hss>4x+LLEs$u0{ngTbCu<4D;z|TC$5HSgASD@!+%{pVE1#eSO!*_jS8x zjI-#RvMm!3-tVr+*{Ew`23>L%P08()9J`aGaOb4!N$M6~&N&sYJjdT`6?H$&RN7T` z-{tM+!&b%mU^ep9@pyCYWfPcSGZQ#xH7}+R8YpjehN$>2XS;jNwd1iTg<7B70wjC#%^{v6_8jVkx*xN^yY~2v)XlC> zbd14Yg`A+`)+G1#i$^GKS0ROrfL(K->+ac3#I$9CQ_8!1q@n?*g(4aT19L zl5&vqo^~IZ^PbK}h{rp&O>0SV&w4Mry1bx#R3WckiYjA%fCdcY@ zBmrUPF?tNhg=_-V^(p5-pp#IrPH6lu7-berv3jIVG?5XnAVkzSnC`?*Fo)AlvVYWC zL5)E5Cb56iP7kQGI*7>I%Yvws4+|v~)t|e$#=N@Ci+Rqnsm%96MZJX@-`%yY z_tQBu_PxM(#7=b#~PlDO*J_ z?I`z8<}0`Qrg|cPyIYPxVpZ&ToZRXVXE4GH(`Dq)$-MMC+|jYFb!X1lyGku>au$vX zC%Y_(-F4TbvX${2Qx9Jr`$I=CwyS?MJ9l9(N%wJFc$`r~uUIrcPJqA7Nh&%qRtUvt459F+X-Ey0}l zBOndSYl9%h;~r?!gZWQv>@fc&35BDE!^5ak8&jv7gYBG#L8`((sbc%d8x^}uR8i9} z+faYMp{bo3>UZddhIeSF&^9#O<9owY_>->Z$6ec;ISFU&log+@z`MMVr1+ccx}5_+ zpZlZHDX2nLM9g0q6hMgt?CU5&@LUK?hH}H)HH^bp8C%LzU;r1*gn*yie3~@L`*hVaQH*8E9_G`y_%a)X z5smbrBaJ?BJ`qeIYDE;fE2wKy2Rbp3lgQKDgKVf{WL9$b_;G_(NRtyOn!0@7U>4xw zONVHZKgi53{9tAuWhN&5nH?sTYHm-zYE@5hV#eTRnS!cle%vl+KIn?|{x3VqGtGdnD-IC9=_Wcz(E9^Ee zS@FGX@y#J;@WxT5FSWv{$rz7G-lhXL+J@qEo(@oxY|rP-T+E$$>jrD4(@%R@{msiH zc=O0+AZuAKreBkNPZb{5G6v%VC9(=MojBIk$N7C&4FH*i1OvYO3Cyda_gznkMnKB|{ed9A(^m;aee}n^(0GKn5Ye^1r{{P1-Y`|~=UwlwK4XID z&`g?TUM@^|H}yIl4}wJ9|SQl|XqR9$7;fYuWVQi)`X#2$>WJryGtU zpKGu8<@1jK-pCf1rNFRMR!A<&@4T$a5DrwH9l{Fp2x)fUzw2dIOW5PUcG|B8IM}$p zyo?j={iEqPHJfWd@|Juz07>|6tANacC?c2Vu6SM{O!sK_@^EI1>6^tZ^Kr|;C79!{ z5LbBO#SaTGti1FACydW? z#cX%KrSdWMFULjm8a|DkpPC*W-#$mrPM(|^9JUWR)H+qIt&#}Ne^SOWa5Mm!TkAHm zb6FUQ)i6lY8@AM)lo{dsqvlLd>>gl=aNFFyv9jcan9gabVPS5kN2h03itz{XLa{YT ze6vrl^&9vYAhVRQ>(|g$cU)%ZY_o+FOZY|r+J2q-dQso-fX;sH^*vdXg|o z1R)96U%=?%eTQ1o{l&}1QXO>^}f4*LGE28FC zHAtvkuRRSU34Q(ie`CEiQN^uIn&KB9OYwuO*9K-0FZB`67GkGeqZL~DAT;uM6iw50 zf;(6z(Cxx)FblVMA0*>|lL*EBNrZ^mbPdLVh1)u={=)4gK-0{RwKUHIVA2W@FPURv zkBMj#4KdHWz=e?a_rS0Q>@ffv@_zoj&LM9R#ukwrGUmnXN{bDmr{46&*GsiwIE#!U z%tC=Pz`<2%4qQ`*@ZtUo5} z?P*Fkh0o*dfrYRQDEpLR^`u%E^g>^mqs(_lXL&ap(A_!|I(&CubUc1Ye-yHtK!7Qt ze%gzy@bO9jNjZo|t%)ZV9l>xEL$qC8`0Ek^9r8FZULEMi0o5?cLnSlt+5fp)?(Rna ztoxP0I*u`a;LH{AHn%0kfVdl~%>qB+6`$?yj!`_bbFy6`=3&(}(4JqV?wh(%zJN>t zU~#Ix*6;1&Byj!}O;?9aHF=)t9}7g()0gYSwf*VE^FWpN9FaVN_`V~Ynaijj zX4mV&Ge$l=^i~c3kJkb29%?$+5}?a-hh73K;`Fh<1o#eT76UH}ujngR`?KvtfU-~h z9=hB8l|ak?&Pt#cl_RXxI6otTl|Z$(5*UxW&+%O{yk~U=X)Ul}B%_nQ1Q6G$zYgd8 zft0{?S_W*r!K6&C&M=NOKUWF)RX_DI@$-9{*}&G7NCC9Fd`?3Wx14dY^0eidE}``O zB=9Bx1}K#N4aao?=WCKz(D&Kp(suH}9;2)zpW%L-qKu5Hd=i}j)U-dqQ+Ji$&lyLl z$_KWS3bWL zfq5Yu_;7VcQ(UzB&RlwC#A>EZ^7g?rcyLuc*eFXk*LL6#d>$7qA_!Dn!q4zxekx04 zbCa{8wX{J*XioG=tOmfW=;Id1*NKh%;rTXNG>;_k3&Ech;6D=J&jw(4bhd*{c+d1g zh1fm(-xnco@h0(kJVvMTqRd-tgU|-R9Bb=3F5^Zq=$*tR9QE5CcgVJVrbRg0gCuu| zBb6Ri*+G(R_=ZVQ*&)9of7*vo|Det zPkYQP`}Cm4b58#`ClOlo^auDb&1wa0UA1(Nh$dzR-;9rSq43Plh9rQEaW*f=6U+y*2HT7)a1AWf+xdEtxIjZ89+g2pPLgh(!VaBj(Q=g)gTJo1|?hdvfclx4l|CzY&i@ zQ!+wvKk_yl8oiKR~$hX`>@;*_XKW!9z-bIh;Rw2Ntx`MKom%LfQ zSpksE$b89vzk}Dgq@L#5>XSUwttyvk^C-0~`u!eJu5IIRx!)TcauH}2?ZsbdEeQBa zNK;|8uw$oy%?X+d-$K~sNwp#nE>aEq4kPtD`!w8;R%JK2^W%7nJw^;K8Khr}& zAhZ$2m5neDm0}7C2$+O51heTP-RY0Z5z$PfQx4JCNYKKmX~K@A!VTbrQvK_7BKd^& z=nDIhI)L2rUaYrwJo%>2%--R?w(J5((vF8wx3%GA{G7j#hyaJ>%4`sVjz81hQmZH$ zdfq>gVGGl`9r(V!rJjCBON|1E3BJJ|AcO67JmvS_o3zRA;9H2@I(kWJC4Ba`)g^_( z<05hn?zMNENvxGVA!e0MXIFlL`;UPrz|Js9SD=@n*ztJV(opl}Fx(2dW&6H`8&=d2 zB36UpL0aPC~JhLDc@V# zgi@Xx;l*8*nYnJ0E~9SXr71-!yUz zfz{>g!9NYrONSgom@eM?j-Mp|5sl-)ypF1r4 zm7k<>CRO^RKR~s<@=&dJ5Eki{FJhFEKxxy0j;kmBobNZ#(HYsFGPG2V3=X*n4E#eS zY5fp873ooio!%nm$3qx=LI>aD>W2=#1;{Wj5czg=<^h;GAxcW70F-TUH@bU*C!aXd zF)kWIBGgl#BPt9ij`(2zc2FIndqSvePwg-eLzT+gDnJ`;V9H-H){Ii{=%0Bg7 zX9!iRdLag;5QrCItgZ^C>X(6Jkv5;oBr?F7A{L=|Em(*G-h|UI68%cg;Rn?z?M$!6 zRe$#JMfF2(SZZQ;$C#8~tsadsIgc~q;v8nP`xHb8;^NSz@~}0Ol5Oz2w{}j%dtZ|3+5)t9Zz%3Wy(iNRiFD2 zrM%)3IUKxpf7BGH?nex*trwYdUu4QtYZJrO<|q53-!Jq{?w%SnxZfBvWB>en$j7op zWm4EPf1l%KX6_*0;ranUdb5(|1Gz0`CKu1;dl*O@|8^hhpB$DTwL*h+pGwUHa@&O} zHk|PZH@}&is`z$la)g)U)E(b$ekaUk4C1Yt-*|h@$H^N%Gbd8qdV__khvD%s>bBa$ zjznFLG`j}2PjWkenGQhAr=b|{(P~(D3{t$}6u63?hOr**B-SC*I>N)IbjT&O8zQEV zP4OS>9HnTDo|Z{o8KE{j!&DL$*3F%9@;Yec%%IhR5 zxRHML7e=6*we8A@MqA|!N6p@aR=r;MC%XCSMOoea6QHk~&wGWx{(qisCVp{f-5k)E z)lE4cl5vJgGX4RKvof9m_}|yfUsCITs+*%I>+7bc-9-AN-2wHOVLI@IpaW+Buno-~ zG!o)(HaiX9d;|4p<|kEkj^^q}D$h;ze;BBse0yCa)31D=yDN5D{j~g4tQf-(N=++> zWs+mV=G6=RX=ELM@H4McahUm|r&&yrRr6;6Ql10oTTb^QbH;FjvYz{(hPXLP=rMGC^{x9tMfQc%2Vb{xACA@zD0+9Zbl07nT>g8A976e2k?qG3hUI5WE zFE0Vfyu8Yc=g;15p`Bd4WtB&K!{56xi{6cg;Cm{$%ZdhY1_@_N!KSHW(~CmBkZa!yitIQlL*70#w#4SF(QjJf03;CzWlvwMsjHI^Tz4w(1O3-tOE zAnEmI$6;jm9bvaiAf&@^YQw}oXIK?2l@U_cW(90g{r`#w>T~rV=M3q-FGqB}!zN?E z1@q&_4n50VJtI5I6(G^UJb}HA&@(&Bbp>F<`hR(MvH6R3mXp9^;Kh@`167jefqqq| z3O(8K4A403Gu}nXG3jfy&*(*BcoWYkAocWm zyg6^#DO2FZA%=(HTrmi6u0(N_6I7n#fAA}*+5Y2L1)K`^{WujXEv$bqFIAVHIYUcB zf_J@j&qLF^4J!6t@?x{`Twh-P44~4P^~+{!vrvo2rKHh_jS@bid>c#jXY3hps(r>* zv<>b^FM=8S{oV)6*jIq1P@}Jr2Ru^XB#s9oY2W1P#6On+oKL%>ymz+a@UYT6D;0~5 zPYz)8{X=gYrfX>h73A(h7E2BTU~G5Qt%tEZR>jEPx(O*vpX2lVZ2%A$*~>_0WOeGz zudu_ZHx1@$4dy)XZOy+0$Sg9CbMc1iN!7$q&EpLa*+Yxo(}p^r>G4GZ7*=Yb6qg`4;<&B4NP6LUQt&SaQTFA5`{U-pog^jesGNbHF z%gcRDStT{UkmrYznB?pfKMv*ep0%RdIexYCj${lB0jvFD-rz}<*8-?7iJwziuwbT-s%r${gx=%!lxJ=ARd9FAEFj1peX&yh@(~O6-0QcHBM5~EtfvV8p`DMpbmOupyWG8Ve z<;~e7WP_#s{hGf^coWSng=|T=dTJ*^R#Ha8U0pk#H*lF7eyB+}4;v`%vHIBpouG(;olDl%x0gD7|5C;)B@Q3D z)JH$qudTm(Jkv;9|Y=w&f=kyh|J>yK8^%dQ3m>+9S%<9jZr#hw9<9 z8hPM7%~w^8)#V1inmcITo?$E!soH}VU`A&V$N7i~-FMuB@9DNUyu^!ddkj7N;i~Ax zjYE$($f9SbA|n1PnzsO(z5URU^hSXvP&0wqG%23h{s_nuu)03!PkMl|lN3-|vM6hS z)cf`1c8c8wE5L>=c1z7VD&GV-yQS914faQ|PjA;vGGQilM7hmFkw$qa5&&~)N0dR_ zph%_W5`biT)HZQc9#)|#RzhYN#V>4AJhw2;ahz#P>lO04ruH_UpJ|JSGksV`=%kL_ z1aum9zJ>if0yAN@fI+=s|NT=h>sFhtI1laUD~0|VKfa*z9%wy}$6O<6I><2mR=NH# zd`ta~QSX@aHvrqKcte7F$SR&uu3yCu#FsK##rFW)tI*q34_$@cV;xkXy-@Q30faH> z9}9d7(4RN90-9I&vGc}Sfam)_=&}`jNg{osXD;(;HohDOZEnlq>+XGP!E zYE)jFs2*tw2p34N!1eXYQ%xtX_otgl)b8n33`mmow!#npu3nw0YOG#;!LR0MRa455 zmCkzgS>FIL>?6KQ#N^-Ct9LuFa*g=+1Qm}-zbNn#K%bT00W^*LSXMRw*e|*)n=4kX z#q?s8WaeddHo5ycv$AzRR<2?ldvI2sC03q7?H()p0*RH6s%!r)D>s(}9C{N-)vRR5 z55mf)vxrN4#K(l#;h50BW}=F)uYpu*MQz4X-I(;}V&xTpJ}ZXVnqoasZF-y~WBNc-7`f(k4#QyB+5N5xytL=OoUCC_F#Sq5jmnWD-MwE1}ud zKTDuo{l)iA;(g+SUQAU)`mPx%f4ACf*5Vhpl4Ubk{&Z|Eq>1?6JDjiQBJ-ZOUtn8x z62C#8{%y8rP7T=pF_1=Y6XJ0YabKQATp*F z>0hGKG3g%)91G|(e-xk@&W~mO5P;{;gk8&a;%ud7!xmU&BL!!WW#5BqH`ulQsW#tX z4GaT$x9wrx@w2VoQX)k2g9?;C^$Fg7^!1Kjod81Z9 zk8Dp$I|U~(e2tu}%l>DfdCPenls}aRf79js zn1y8c%y=5m{6eKv@e=^_&Mq~*AcHFXdXSy)vbA9B5YMa)vTyUUy(NO)L}ixBG zy=-rJplrK5I3vhD9RM*bHBkUYjvnq|-eZa5-%0Zrw(A2q+hDHYd0rP9McnR0UWWXcSXZ4l)_Rcz0#w4V$d zPa1^U`Ts`c`zHe}6BUIqgGjYJzQoJ6M*?lOJr39>$S(G>?QuX}I-^M50vjYr-vGRX zWs?7z*Rn?0k|nYhUeu-7OJLsiF&vv1 ze7lK5AC2ddlW1}p&g5#l*+@Y53+5LoSi z#0hqL5B`)e*m^y9DKCAsqk9sK=DTZ5A(hJL$sivk0zLvOUlu$`uY5{zaqJ7(#BKjv z<8$7*zy;B5B$97c2e8^isD+6@1vvSo^d+JCi~qcM>(f8V>AT6@>Tck~dj9ciXS9Us zo6kT|XKXm-%3Jr%*ek3Vn}z0#;GoWkU5JD3kk0z=JrW{#d<5nyxN}=;%=ITjFp}-A zd-jgiH{Idx+WF?u(>I>We(@_q{B6~g z&n@;=A6j73;C?^7*Mm0A+~a-y`T+o}-bf8T5o*pS!Uv;15u}O;&BTDE?Wz6R!Se*N z-UQ(sFEyvyT%08eap0l3F=qO&L{bEjN_ekXk5d$s&aaC0bNZr}W?!LJ37Bq)Mi(fQ zs2>HA+p>7UV0L#)U}{<01n15sJwn2>7ODhKR*Xj?Mr*nsY+{7Th;B58;%mLJcGCE-|rB=ESVs_>sca=oo=de zdQJca<7zWP6;_Gd(SC)oVk)#FL$xB(zGP8AlE?iA=d}#Z57EHYjf0O?{nb4FePruk z%}$}#!J4(W=zXRkcWShCa7n$O2l}-RE(IW~zjql>Z|^E}*D{zLD5{!9RRgK|{>H(B zx3_h1zOfzG0AjTgZA?U;1y%hJZ92ufn0wRj1N$99^^G@=wd8pNs@JsTtI1Q9c1N_puW|?j z!je#)sMfAsRNL4{Yh_-&pdIXCROYu-7Sk2`mFnWXqi7ml;kO+hJ<}DkD&+5%G$dza10M`96^7>~at~ z!|gPl(UHay^Yd)^-}>cO;N0xr&q+b~MD(XL-(H3H{I0JKY)O%6btDn}g~hXC>^((m zMLQAIEUEHOa+R=YP^ewWh@#X-xvEHVP(qe!LOv|vkNfFTHBn+!?TrF>P$^YQ1BnNZ zTRvM(!C=2?xa+DsZ(WM@gNpx&joLPp96iRO7Y%Hi|WoL zWh^PlfqZ*0$NAcK7-4;jIPn-jGRIf$nA}ls?zEEDKGnoqBTO&VwSTM%rN-tlD*5py zy|1W*)PC}6Nh)R1(tUq>pRm(H${SrO)pVdrK^#r$BY@zJwXw9S=r}zlRZRt>dGo*v zd^Q)SY?L|i5<5rnct&F#uRC&E-SzCe{+(!p_4xJy*qvA3yDyq9@7`m**DirKsWZ(7 zbEa1Eny>?DaWZ7sw><4P{*O)aE3=5o?p9X>`>J8VXtB#5fCUUdx}m-GYE$Sp+H8LOMh>oG zOwW4fCnp!nd%T&i_a(;`I*Gqv3C&*!I#|BE4Zu6-aVuAop8kuDi@$5r%2wHj;jGK$ zG`PHKEBzCG4noN`D8Uh_mgB|&5Ou{5@(7KT zjEYNr3GOcmZa?S7z)Qrt%&|H-5;pb=UXw?48_B9R6&1dCyX$a4Be4gQIuz8JDu_Jn zq;BHv($hNo>+b928+ad%m&f}{TXXAo>;0v#I8}SgH}L+_i|Tjl{iWW0?CfFXukilT z3-$iem-&Ek`73N5SACp%FsFRIQ?;*tx87fRRZjT^XUJ}f|579I6nOI8Ihgq4k8tB* zAl~>i?@$;w-ifeg$j2?8<{bxnf;)4w!%(Cj2W;n7$s_GNAKvc8?#FWmMFQjp)dQ~) zzW z=ntlOlyoHVHE=?8d6`}TY$F*OQ*$j9TZyazNcQIlhx6U0`j2xG8)N6xz|8`?waW== zZ)^8t8_0>6-YQ1W>jbVoiN^rCyMhPnEU`7Cc#!ENyI_s)>x$z2l_oK9#=E@7C3ZTS zm337!+P->*zU0;m#?H7THl^;ix>E1T+d^$vbVl1Wi?N$RiznPNX{xjEs_?mo#Xq|3 z@Mb6R7O9M*>Oas3NEZsV;P+;V{f1Kt6WD}yE;V@Q3pzip{He{vfOaIKX^34ZjCBy^f!&+OP}Ix3D_E5lu*|l+mKHMp-d5K zUCI}ag9JA(TBm29`@yPwb2>Cm>?P0TY#{Y`6lVl=Dx>h?A$m%?$C2Lkn8Ufc_R|f= z=|Oc~jgj9Y$L1Ybt*6!_X3G%)_uc|hU0=|tH0>ngID3l?0p@pE#AkiPun-GD%)TX| z)y@(r&Lp<`diHb3c74OQOwKyUalfBXd+;?{&0}Ub_1C0l3cN^-TDND2ZIlzo5+x@w zTKf>eEB~I=NnHt@$p4$dHqBa}+c*8&v9`))$N9bP{y3)rU}%2FS;A>pznfuxmmjl& zd|$1e2Q>5fv9aWNDj1HcsX9?k;3j8f@Y-na{bM)(gZGbB>HTBJ1n-MJul@aFncfF^ zS@iEZye#^ujQlApALdku@Lrnn1t8IKD}x~kxY(C~QeOfFWF?@(OEVCIV@iC)VtWn5 z;iba^ad;I-6`#zpGb;`XoZ7Xg0P{o^@z*}$-y!W_;&2F2IHQv&_ycPXue5*N=3=VW z*KN*IV^$25!keK2G0>;8vSN__vs{|)VE6;q70~R7_ye~SKqHQN&Z7sCQeR=QO1~jR ze<-ao8DO9VKxIws%YWiul`Qj0e4k)AobwGD4R`Vh76cB?b~0|(5X`l~eb9H2;?Mv6 z^h6>_fu9Tb8M%!W;IE;55tZ^T=zS@p-(RoXHCeo$n)wo-qfPD2x@7po% zCiBX#?R+F{iQ~N|zKJ7^v5Rs~WJ`WbU?KHJ-5nSweIa;q^PAzE%{*P9U{gZ_cELSH4!uLFke+K20+bZ|MK{J#^88sK6G5j zdfOjLr=gDEVy5=#9O_(=+2Y4wFC>~-cYbCZWy2klqM1vTG%v?5?((K_q2^`EW~*Xg z-s*BL8yzRbA0S|yF$=r-q|67%)~`w$Rv}0F5~Uc;ap_qg;QdUNasC=G260j-Hk#LY zPR^Zj1rAX7fUU?_GZtEA(Bw-C+j!IV&nU z@f~v#5gEWukR;h-TGa)~5`lkhm)QLlYsgl~Ctj`u$v!GO*9tLX(T`luXZ2*2n&igz zw}Sd&a(Fm7GLo8d*v`$T?C8QGFH#M8{c5gm8=1#=*M0)JnbnnUc%ls3V(A5Zrx9_q za`>F};>}1!C$eiP`Ebu_G+O|5?$whbnG?HH0Pnbc>RX#C=EQ0_KvQ!We zCHS}d5#cqiMT2?-QS+wR_iFz$V*G`|n1BZ3gyEn)w0RtmICuj)KLo$J&Rb5at;D*B z(GVGsgG(5$n4NoK5LbyV(iFn#*T^%YU*6mv#KU0v{St;5*WHHkrrGk_?0GBmNEe#5 zVZ6tI)NC#lcZxW)hw-Z26}IfpD9f_wQXvus`xnEWx}G2215TT#du? zoJF&29FjO*kB4X35M|?V#~qvR?yjx3A-uis$@}UM!n+(HW5_jJen%zV$bwSvl(i7W zddqNDnZG7LLT+D|UwVkc&rij=ZYVt?xhB7LsGRnYdqL}Tq&OB=w*^Y`CvW zscat~HN0AOudGQ#BT{N}o~TMhp93u8f96E*SuyvME7}p+y>JtOTpk=A;S79T&*Kw1~)Ay6}31s$8PX@~zBMjM=lRM_J zE+mt|3j3m!z6L+Zb_B%;t3$rVG8J1pXMMZ;@)mU~Ha6appL}pTZwfEUT@L=WYHxnH6Rv$7#O`&kQ5U#^qKv)T7}s-pd>eUB&Jvdd}s z5}a25laVBgMY0@U#^EZR{F}$H=y073$H$d8fr6 z%u&VB-X+6sk-;>XN zQ-0lvnTsdPHkrLXrwss@4CQ2A>m+ZtSMq^yP1|v5{UKU^GyYKI@F{D|5)g4lGplKb zP|2J+Q}DyA@;~aI<1Ad8^RhY0%a(RN zE9cVW*aYVY%H(Gg-@8Qx-Ax|KR(sdsjM*P;f|;<}HdT-<_Ka7|vo0xbF}CCbjMcMe zg2O~Efv+w7Oh=pgF14G?&JlOCjej!BJ%oS_eiv&elMbtdSZxZjbXJ1t(Rs5+Rv}BbXH{>t*;lLH@Rjx@Hc=*m-Q6HD zAf^F_vQ1{gJa`qxz^BSdOdvV^6@GZD$!H2ujUu16Zu9X?HbJp3FX2rufxS?loOL#V z3Dt7MpHR`(?QKWYjkeAG_YzN?;7IK9pxt(EjQi9Yi2M#5@%V(pBF0&cj4_9EmL3b{ z96^6rhehh1q4H_wcUQLeCH9-l!XP*8`R?+ZwH8Pyj+f+h zPm4zP%AG)!VPP=&1UME<{I@MVx>xwnD6@Q&Zu_G!@u@LeQA4f9{T5J>wvEu3J?S@y zRdl@lq+d9y9>A*t^^2=m7M%1eN;h-kpYPM!VZZZzdC@Z|(0;z}9kdArI`DYk8Zr_X z(H5@yx)Q8f)o_FJcUF1{NbT+r@kwN&fYn7;Vap%vX)$@LDv0>y zMNxaakACA1lXvg+1T*!N*J*%-ng@Xm)espYU4^D08m~TqpcO@X% zCn(!3$c-=8M>MHiiWFCTG`*Ka*$NhsAt!MOym+4f*{^&TyUnR^rF4b>ad@UH z=ls9OPhOCklBbstJ)xV+q=kATW+ZtTU-5Dhdf1fPf>hXXcL#e)C$@87!tDRS_id)r z7q*!G&-9~|P0Mjh!uP_I zg0eOye4nZ8%dY}gktB^maaj{QDg-LY6u298Zm(!C`S>pwLpN^_FyzBu%$tUQz)1K) z%JF7-MV3Bt*E@>{Q|D4c!G!ppQyw~l-^1OtF{E}^vAe@*_#Vqv-H73dly7w6dd$e( z$C>V#TYF<|!$Tg9U5vw}K1j8Pk)dkaPHC_91k57U)@G~y zhN?YEsk_`Y9K_k+G-y#shYFJg(F7W?i`#S$brR+>GvqbA?5^hY4=IRQq&OA64&FNP zA<#y#BBAI34R|KJJNC!Zv&+IuccE3Y^*vv3-vK~L8=4d>ml)Dq7)t~3?oQRIadUSh zd0{_`ZKjC5`Kj>Gsol|+d>*G=pE=*%%$`f^!Tk7}+xxDgBfh^w$bIN`e!9h5isP-@ z>prxVQHpamJyYT839X@Vp-WShxpjY6lQ|o+eXl#AY>V~GtV{(m%`578eNxIllU;xh zyN8p~@fX77v1qhzqWke+zV2LX*_CJ4B?y`S1i{9gZ{XR@wu62otxxLS2(-0{-+ ze2;owie`jObH)=k8~Xh#H=67DdRr)6>oriC?(K22gsKua8lm#N-lJ_i*}Y4Q8p@~4 zaiOUaEA<5tqY%uS}JDOH+`M>#-tpeW)lm#uCN zT6!@(oMAUP0ebh2=-2`eeKF|n&W=JfbE)21g>djnYN$!YZp?RA|FiKdN85rijTLD` z&kDv~-=FR{zBG+g(?AIfDeN*XTBIRZiD#5v1S3uLyMF(!1<3X7{ou1h{&_>;vf&U5sO5fI{^9+>H}j!-IOmslkDH3q;YX+9PblneV54!XF3F zPz=-g?wv?cDYiEc#3+wZY=a#8yi6y7PUYP*)E(Uz!B9uV9dwOFt2eo_S`9Y_j7Wch zre-4>Nn8aT@-33hD_=Wx1XRABv%#4;hvU1c@OjK^gLb)lbN1?a8D8!4Rg%T%IZC4Txet9zia z&`EDA3DB3s(T2$wiaqdo@Khe}aCc_TVg6q4u1igSAV2>0_P!svAJ1ldhRHr07H=(% zuaJFEX(rI}9kLIT_ZuH~pDa$!E08DR_VFDhci%Af-&uyzb$8SLov$ZDou9_l_FR!q zU&pq+68`z!nBr0)=L;4JqW z^w68-c5x25^DNioe8*07TgefH>$z&8J5q*u2(4!)x>|115t5NSg;YYxaC9jSt@m(W z-|fx2a&K??^;1thRp|`b=wjxadRN_TavEoFjrHbHgHPV}Mf7t3djNR17eqL*I+un1 zV!0~nChRZ3>4D4g^9tOE_7bWEPeznuP%w=?g?P?G1&&P(WkPZif96IK$=*JfLf&O1 zE!aS6Do<`k*kx27&P`3pNie%;pfP*#yvoDTP)&GA*zzHRY-b~ zb=1pWmqgW#^W)j!=n@T$I_z%lG&WVuTJBYwYu_d=J37i9nI0OP40{SPCkHmuioeDI zX49yxJN6Vb;}btLOd}(EDAg*M0dAo?dIslKW<*Gu<|OoxM0QXX>*h+i*M+=jT<-N_ zq=?uYdv?}Yc!CCG%d}qYCVRHacsPlB=s}Qu-+S=5elG(PjLP5AHRS6YSCOCOB&tZ! z&@^jko=e|#Jgi-V8&I_`H72JVpL>IRZB9wpVOcLNW?&vo=TWY``3bYjR;6=D^7*ZY z#?$ZfWBUKqm*0y34q|+U=&bv{6x#N!LTHQOcEOx*<@d?n-}tO66TjYH_7II_aG#-w5rj@xn>^M_&@fbc30##XRw* zZzvxJz#Q&NcO{FeivpcNSnCS0`JMcMgRY;(P=$4DMg#ckC)P`q+y(2U3xMHg3?B4L zd9x$?AfirxfUkKFmiuy{&b4{;O6g1Xe|WJVntgT=bvW3=i>xv9^dcPZ{P^Ms%xA~P z7w7(s-m}ehkjEE^+j-9~=6TOA;-;s5LYx;3jA02%2|!Qw``|yXC|YrZ)SYcy^p~1r zJA!vGnJ~Cf$}GE$PNR0K$A5b9J#u8v%pLz9dv60DRdGFj?qR(;&QNMhMf zgaUkXQ@Dy`8oOSB}=YZnGc4=ak!n4N?_1s3>rr@ARM8>AKNFFUSfqN%#4fVAqmrWS- zrh@i3@3$qF$cs4<$HocYUJ{xs3Bg-`!CBe4)OpbBD#tJA6>xUz%-WeV@0=OMS>*#n z2OR&Tsf=@ljQTtyY;YuM_fM+&qWxP=dF+?@;2*tnzyk>hAk)#oK^;);>Z?tT5%BO54qC*yvXMg`!VKGC1|C z9ln;&sfR z@V{sw3wXVZn|O-h=Xm*>Kqbr5-03V(?r>6Iir1)aA1gJnI!=gIhY ztoko|*Q)&jgYEJ`I<_pRV^T)zOkel5o7o$!(9KKXas4SN|-bT z)d3}ode;E~()}qG%+T-nS!UH&+Qag$43RWs2M_sY(VV_@l5z8oOm)iq7@I@0cDPIu znhsXXsLepJ@mUv@o+}$It&BTpuedsTqpO9!*EsZ(tWqkRCX0}07P7jyyI`&+xs`0z!$BLB~=ffW*Hq?l>i+~w1>(#8*c z%k6|$p}6R7oO4Dx0*=>EjZM}rB&D!LQTfHn*Knl6d>?Ja7t1r?@FBfQIHirR`sUEG zM3LAsiUUMkrVE|=1Xfa}c(^XMw6TbvroB|YiM(W-ftkQmeL%kxOjEik1*U1A_GngP z{-=FxtmE^+RE!8brgj%t&apBXqMq$Hin|6u(F@hwk1iAzggaVD$4b5wgCG_5q?ZMG z!JT4ecjSDA{*~5!p*nO1HAUuBuAH^NF-T+&`bi^04-sDw(d!NE*~T8)v-^6G)~Tm? za<%|Zmbh}70hd9E&62N4VCzl24r?zQa%<1FxO27+AjZx(*3fIC_Ciy4?b%Iza+(LQ zu8et-QZnq4W4RQtx|jAsqo$7fNCT0nIhzMisfzt5Kr*|OjmEAV%(X`bpoiKK92=;@kv%cDo9!!E~>)qN54Q{`~GXO(W&RSaKuz#lS>(!z? z+uBEafqMdEV!J(OT~58uAWtFEcqy<~6SbvM8#I54X8?e6R!I9O0^@wIt=bFQDSLAd zQ7Upa$w0e0XR}>Or6BFu&nS1FTk0y!kosLf}MWS$!Vyj>rhEQn}%aq&NS^6PVzw+ni~PtE>`yI`pIN9 zJ(2pJgC;aBKR2jsTMm7l_xs`1)3m$RgH&Z%1rqO@g3}PXKb6rH1!A-fxh67-T4iXJ zvKC2I99`LEw_ge(eVwGgkwV0nGb3~#iDi8puS6>ITzcIMr>bi z@j6gW8*kPs&jqx$wAdY(oT9z7+Pd4W>Jqjugw{*>7BJ-^WUjwE?5n{N9yx>`E7-+m;~1`NAW z6S@r{NA;)~wW3DK`2~l-5-tnKHtjhqE0pN_xia8h?BQv?d$}@bR*E--r=aol25UO> zB!Tco#;!M|N}zK-5uj5fs-SZ&uaJEaeN{+JprShy14XHJJk}r~slve~>8w*^2n-jr zX_JCaqS_*+Jv@-T+P+r+EI@pF%YmWV;A@F^-v^BLN~8ADszAzHQWg7W=5?}Yv2XJl zn6SnXSZD_4M68iyM%ze&gpMCu;r+=Vax%G}m)zz9xj&`u)FNBIhPL^r5F(U+Bj0YR z>!Xx3k)ERK8CP+egx*5)w5l_ud;0SO_6wPz!IxT~~R;Obt!V2W?&7n$qq z>t-e(RK1=eW6*jqX>J6{BM9Yt<>Vb^!^YXXE8BHn`S6OT96;u``;4UMw?y;XLiJ6K zkgFzS>|SSO{eS>jUyOZTB%d3jpI~kgkniAa2S#S>oIO~ra z3r}n7G3*__hR?lir^4M%CN-xi5#Z{pIu%Y$3C0o^RjEf3j&5Z(F5$&gTn7;n#q|-E za-o4v6xY4X%;{k1H~EL+^a2m#p+9z}zKXFHv6ZdVS9Q>7y;0W`RbLwkNud`|Xea7x zsinSp#ZvH~g!Y-Dtz(k>w7@^+Ujc>Wr_Ogg2;DBbAOi+ zufD2yrJ$boGst9H<2bZ@Qle7LKx==q<^fXLEjN({wE>!QUZZ)P9w_EHIe%&HXCavT?n^fkpzxuvo$| zR>D^$VIHbYY_stS*{>q3$1z38Y$e)CuzF~BBU$pQMay1RUOE0q*{ZoeGt$MpXT!XB zeX_7~Hg(nJJwx_@sT`xu3g<_yQsB0YNyW0P?Dt+yoq;#kysRU!w1` z?v;#*gvQG-QDJrTPw?b%+o|0=xNhF*@WV>wn0!BD4y?`%j6IEkYb<`rBXIJsto!^e zNCX_fb(5nfHcU~waL+}`Otub6`jpLpCbT=jl7)2RVEHH0@1hqj)Q3glcn3T~!mT-WTkV&pdLT!{WBAzs~ zrERqF$(vEy_%|VHTNP#rRqekpmxElFT4ub-j674Kov@U|N@y)1;BRko`14<*4$a`u zWqd-d+MMXMN}(EYq}P1Q2^lj0FfsHR!9nl9W8R*)S`ND4E}8QE{o|O094$u(s`TsH z5KPKD+J?~cG2}^XPC1YT)X-J3VEfSv+{JtaNM#l#2uLxU62zEwsiL zxq=TovkvLap*OaY_s^2o9Fm?R7?mSKujn|1eN$FWl^=V90utvY{Rb66S&laU>qk`_ z=U!+_H`v#+=cpo@$f;bksSS}cqLFUPZ=1NuDh?`kwkd_F1O@fPIzmqns1Y(UJ$Ex= zFv1S%0C;_i=>y(VeTnnC77$UtYcUX_^l*;cK86vrgjhh0NpRO^9WAc@|uA{Aj zQdg^jDFh`uIi-v?Z|#zFKvmkRrDZ8`a0FZT zvSbl(#!j>f(2K>#S#}#SlfyUEqyf=nq!sv*P){M&({!YEXBi=YbRVsdcktbOlugR$7 zDw)joVWWW))ahH{Q=wl}$#F|qS!QQ^tG(>IxSl23*v#Yb9I!dcPVGcT8~(OyWfi{Wsr#?AX~S0Qjq|%mB7~cxII@lvhn~iK zK>1qcXjLys`fWnJ}V-^!G!D=0e=geKZSrlUrE2WH8~5wN=M5z`=M zrmUG_ry1u^LP_f&2?HWoh^sU4%#K&>EagDlG5&Vt*E8RJt=$k}6SPLup zCpq9U|2U`rqQK;cOxVS65J)Ku6s`MQPSay6D~{?+ZvE`=9{IVyw8dZi1?i?#t)enw zAY?bGR>`4ZB7&w6$9ws`DK>pOnpGCunFle5_h$i+3-RhH@{Crwio8F#R*>S36sLnK zLMa6tKz|;PAgz>wHB8^&bEKp^MV`siW1ZNMA@38fg^W^)C2OQuT206$K)5g5RzD)e z9xcEVS3o@w$(D!v>3adpMgUDwhl+J5jEV|8Cn%8PpWW)DH?e$CuzybB)lzm|ab%NO zY_=5pdlR(qX-d)8sDJUbaiwWpI`z@|!*z>C|ew!UAWcNOSRu0T)w8qh85v@1dU z-lIs#h(pR>XcPq(9S<3N7i1|!fE+=JLWU}*119Q#ht4+AJe{`4II`R_Q5+_~hXV6M zp7CMy!!81}x)_P&_zvT+aF4jvxjay8xZa*9OLvO_96lGONDco`enTsW@Xufu zGmDzrW68uXxMnm+s>N<@E15#bIAe+>ILMb97NM<{-h}4&>v(`Cs0x?$4PPXmRDxV) zic+Dr&uY$JWL!vX)ttY7TzkBpJflzaLvI3d^09cZ_#SYv&gP%(G!6ug4 zh~D@)aFqwclLUmzC-QaDMEa|s*swEYhg?H;QkLJHV)Ne22{!sik(`P8T8j%ETw%x| zTO{yz^^cR&S}aC17m45p@F|Swwir?L3Jf}))QPg|)?&g`y;bppu;GvtyZ#a7SfvOn za$pLD%#9X8?gBV5mBK7WY*!d^LyX973Qe<436X^lDKsNisJM9pQ+AT530`3rQ9~ej})IyJ-}v@S+Lzo)}c* zK$Ea}Cs;WKMkdOx-|XU8-N8uZ9x$b(az-c%&@?rd2NPJ5%9hV$0>==(LKG= z2MYH_AcLv%4_yAM+yk$2l}*vt;9>kP=@dtDt>|W^hjH`4U0QiPujW4bR|xrsu@l34 ztE{>pKaCGDC&-Ta0x@YgUlW@3UJqb>s8gRM;KPajp|YttS3H7J8uj}c@j7c{v}2%= z12~Er<=pvn_WY+rhPq*p`ou2b(Xf;w+~1fl&;|0t1kiK-5Zy2OSB4p_J3t(s@OMa@ z#^s=TVmQT&Niv}Wi~s|sK`Soh1u;22l z(gVH`XZ>H}*UkU0@#}F)IwrsV%X4!0^^%w4_;oTbCzW3})mr?zgFrmL9y#ZP_;r)Y zX57gB*EW9ryNZnC*J8%k1;bL~hu9*9*pW>By0#6o<<>CERD=CL)K3kwm#K4+6sB}@s9g*k8EU1N4ukD|9w!A=M+*W#5uPq09AenBOH;-qQk9OmY~QS87adWaNCv9u~G2@ZaQ!eP+)XuR0FOFcaub` z5f`}Dko%3`J{bpB4Y?-V2cmFkW7kgcV&X*MLU1Jbk@LaSpo{vebRQEhm7jnwHHKt| za)3?J0v5@9Im712n|}1j+e2kEe!>2nHcmGB%9}Y~kK^aB(3fww7#WB*(`nmC1xK)58x~oZCTN4#6sl z7BfQqfh_#T!{pqIz_3n>*ag?hDQRjqEV;6z0G_6{e8ZVXbM1*}%P%d78-2I((izvD zkhXlCKo@y%vx3~lwdJhaoq)D{oyunHS`yE*xhnF_H&2jX|M7Q=UtcBAkzf1CWSoKb zTYkme395zujyYYAA8uuS`#*qR<#fDbO>a*cze)iye*N3&Cx>6VE{fyV^LaU`{Q9TA zS^WBU0`b~%Q|bxv>z`CMe#@`_EBV#-lm9ZmN&zu`9oPHh@arF+kK@oWx6_2If6C&aJ6QrV2NpNr>LuZlcj ze*O3FEq*;hpd-KD#Ju}ke*Is`ujNnwm-$r+i1F*E-A)d_j(9qbUvJ~(q>itlr!0Q` zj6giUx~cvN=)<98$!5&NjM`=+Ua2Bam|urcHKh-aRdsAXe_hO+_FI1aU&*hfzW*}6 zN&zu`9o+Tg@ayBhjpNr^UQQ~%<_mNgU$0b<+w|cZlTL_V^HnxuIZm`~{Ff{rV*Ht1i%mUmqn9 zKfW$XI3a%3RW_sdujBdk78Ti!UyJ=?QpII)Sem$0;IfDlFwTp3E*6O&qPSMHxmC3D zUflFci+gtv5blllUL49ST)6lDd)|xUPtobh;Qv3p7g?juJHF>)yXDx@5yxiV&b=4q z!Vw$@J1gU;^;jt(#=mPL>`M5Ly%!6O^L}CSukxb!9xo?#yj}Hki+|S>i09wtBeI!= zW$JI{y|_wcGp^wfskZUFRpa*j>wETF{yh%m#opqjGv>`ch703YZXFmc&;|0f3UV9s&f*%i6Bv9) zt8B(Q55+U@c`8ylFt+1gSa(dCwd)7{S(Ii@Dv9dQo$Jq!2P_tTiaTTu0^Uc$|+mdf3Ij3`%|KgW&z*UAesgBJ$ z#RqpyUnNmmCYzt-C)>WRiyRYPu}%*BCgn)#HWJ{YCl(uSg&D1KHl=XQX7(hx3C?as zzDlI_QjzCk&VefOT*~>Bt7t;0G$GoQk#cC@ceIz9mp#Ts5!1Arf*kzE33D82nGP1@ zG(ir?o6Ct#b(HK9tQ1c&{!o=@TP97a={NS~BjhMOg`>l*mR((J*k~E0Nfx(4WTol% zE(KSb*Bh8YwVR)yD$u41q~zvk%#LWFDH^DY1{OsFPelU{M+4<%K&omaP*V;gTWGar zZlkYd;9Y&$m69^OPI?JEWDO*JV4>4CbNo>0vao|{XVJ5+n!Z)xt1B92a6*{6HOIw0 zJ+1n7b+_lkR5oXQW>9Yq?nu^_>hEnUvUL$Z^J%^#-L(TC0h3D7gavGh#P*Ls>Z{|YPSLpdkacc?(~Wf9Y#%T_r*RXQ^8 z-~(6NZG$4uK>9vzq?d#70eo;X=Ze$^5BII8KREvV=h)_zQL*7SE7NTiM?U>y{Z$p) zF4KpQVHd!ruX1xF>+S0c61jKTzM8EKrEJs9D2Co1;igH3CAQtljnDVJ%rS-$u2re` z1tS$3BW$?Of8%AjZRqs<+B|$GY_ch+|0}9q!JR#lTfsG5b$h1TjxS?gxgM*zD_gNjt^IOdJ_t+A;UP~o zE#fIhkH~wTJY_RTt$RH;T1QzJBQfE0K&F$(lRjvO9G+P&X@L!=R1y@>#l}NdsDouH zITs7*B?lwOt;2cw&ED&@c|RjY-4ac$jAttnZ4;H2vzky8oBE2dC+EP+0t^uyy$Hf( z+(jC?QJwEqN*MHIOXI+ME``Yc?o!D_A9xAN<{E1w8#TX=6mmpTIgtdp%DtCaXHsTc zsL7QayekxtmXm|j!5{>MVXcNfMsSC0cC1uK5Oegk1fSqxot*s?LHS3ispL^xcIwUs zUvhHgFgcQ^ND7jj<3g6Dk>WI=$QKm~!A&ZMZB+{Z4sM%Q4u(Vxe1Jf7D|gL5Kjd%- z7b%SOSIYQM^E0}t_FRbwnh{@aBtrIF8jDnfk$k0`*knu*Fj)2JVClzF$8M#ev?Gdo z>MWI&6LHfypRybj-F%1)V|eq43qG(T{RG zO?vfc&z=5-X4&Qep46m~v^<`YEK5yt<_LdBmG|-?HhW`ahu@@Y@<|dviKLNhH{@9i z{Y;R#8{nP(Q~g5NsTL=x{hqw1lTG-hn7kRhX9?j?GG<&JlMrunoO!J5VEN9Z@>Yj8 zn^XI}U3@K^Lj^B9B|x|h;6=q`#+~=W61)g^3TNEPJ5@@xI>h)}1{)qtWNt>Dn+OyX z#PHO<7VBgcY;o?nr3L8a%{JdkoO#)pz> z^8iR~X|Q^s=W+SqsCrva3Pd^Vkc>~vYzrv}UB9LztC`Ay{XCOfxX@RCh@I@)t6m$Mk7tNM$G`EDaD2KeQ&>0`j_|A(d(2fVUL_jpUy)-sD78YNrpEs*6;7iY4-bSUtjXfBL}x= zqt^uY_6-zW+W%F(y1F_%hF%xqr`a#c@%R>j-DV5v5K!C4$K|70YXwQ=_7}SJpulVl z8o;#mr+GpvdgH-8_SJe*@KAR?*q5X9G7cZyt8cQerGryYb|PKmOM~8Wa4!T_O(y#x z$)KW_-@d#68dIPqC_3=UK1n!X4*lZHY(TEc7<8ZP?to$49Qj)g2uo5*tT3%VnY*P- zI!fK~j)^fe0Kss&8>!9HBk!T-=`#A>1rq+|R!DHwbZaWIRpixyn`KUdq4j7-RvN#R zMqT#KIbk}@kH6eKGbsHed@HrJDA_AJ$Kc&$N=50{Dz(YuJ@kasBGwz-zs&7ZvV8~IilSNEK%=E^e zdFYwt!H_$1wf55bb@WhhPeQ;YccIxbSKF6sFD(x^UQYv2p%&00H2ky)&Q&Y4;&=MF zTdh%F6Z}-QwhO(aP>@+qH}0Z>B4<&9?Vkx@JZ4h*1S)d|bg_tU`qqkF!c!H845iQx z63W~d+zU%BRV-DoKlrJ`x4SRr|4Qcv3O=K(alS}*ZGJyVyH(#DJlrF=$3fc=(kU-X zy?`k#Y?|JrT3FAa>6zRZdtlvOJFpW1DgOqPEpwxyTYEjkxr-j#BPYYV55BLj3x>K7 z_kM7XG$@errEqa(P%Oh}T^7R3nHi)K^oh7Ng7aGJ$WE;iq%FcFcW zZX}&Zhg;;m*qE6clK@+LDCU(eP)JZ{`zD+l7S3(Qwc!rz3Qtvr0I>mon3>5<6I@ogVWdjOol7uv^%p2Gt)Z5-V`(t=C4x&TV|8Jk-NW> zwE04D+DnZ&>z7H@aySMsP&g3%4{c6hZ$efIY<;!9R)52{tE;Cgs$gJdR}R$~`dKjS zs6BVoqn?WQRiRwAaB!FJa97ROtBcJxPT6^0%>^v&31Q+vJ)wr^Gt-xgorhum5qVav z(nhVTI3z)Bo}HYbCuxzCew~!w^{A2fE5<2%J!6l)CbRzF=FnC+QXn--@17`*#!wxF zqt|3)P>2Fe9t%zC{WZZ}XeO1H(w-)r)H~SPBXk(ON4hUSoa(;U;7J=Dy{=ZSa1DmK z%YeFWk8jr(0mn6ro5NZ|=U8yktXh9V?DwEZ6Z^+TygIuT>{mpw9~@*N{|JLZO$o!d zzPvKA9hq%$H%- zYv~a>pJD_h_efk%|6GSskD%3#dQnjHBH@Ux_O+p&7NjCojc-hn1r&Nbq+|w{38@}~ zB*o?z>JBMNJN_(PI~XJoX`_u5yM^>abEHXp{v$nCBY3gUbdFZhsu1*GA5!E*LgTE2 zb4hrDq|FqqK+FQU_CS%nYwgcGqaHoDCve}zT}93&sA+-OMTdfi`i8g%Pt~l46lij? z$;V&G#Iwl>1=otXb`(Uq=j$-AZx`LOV1d|eUrVCLHhk*aZTGFs4ULw1(CIfw_sw%uv!sQnIA z`^Mb-6-owbj|a8kE9`5f_B$NOEh7KAVO^GL7hi46`w7)<(AW7IZt<;GLcayMA1+`% z6gPoEZX|~QYx=>Ow{W<)DBfD7jM|V)X`xJ;qtjA! zjR~cdYQ8cVEkNnz)`TNj^pK9`rOB{ts4tKh?kbh-#GJNUrHE4C9U>Ypg`@ybW+Jfy z2v0d4@OM84_;MO|q5xJ(?J6t)(RmwHimymifjk}dSAgn()by(l51 zmM!#WLVBZ`hY7~j9IVuwgDJAKwB6DuMRYXB$Q&$+^U(8q6fjYrHPCNk}#EG(xpV%Sep@G2G@d8n#$!&1({i)oUSH ziJRa%m%Bi$2=>tN59L*Gn$e%qSITbT*62vR6#_CL}r zMtkmN3g~EhNNoyH_1HEKO56ogX$tyozjg{r$w)|Ig1cWZ)eonWC<`^pW~Q%gE<`4 zHUpWLxXW((u8l5}#0r2U9m`}jOabuab8$nkMsjLJ>*QE}^F03vVgX@tWD~pKxx&>b zM#`?uaNwM+VHVtj5$;jb2-igF838WJt7vsI*33FbKa8e`bS%(!1;fc=pX2UA&O2vG z(D7Q@ChQFTj+>;KB!L+iwURz3)G*v3WUbG2HVk*E&{%iF@DvrwY#8ED)}gDN4MSXt zPp@+~3`vm?%L~KBVfj@4#&XL*s=qi5Y3pKD0b3luSeE(a){SDLte@D0CaZJPW4Mxl zy52x6Y?GA{j5UNQ3M=&o-_u4nBc+rXd!NpomdyvlTqPNAlg z_O-8LLDYlz3Y*sMnDLs)$&dn>7otK)Dhzu14i=i|Ebkl{6{xq|jG>PI<6W$TV)Bc( z63W5(1(v0(kZ_TNNtfXtm+GG+x7NFsK{Gtv@QgfDHkSAPm^cbfeZ-_)NPE`*cO!@p0K!Z0 zjBpD+7m8;PWyQwev!w9!XkQ3CQ+~)*kdyzZ76DTIO!)P+2S3zJgL-gpm)q+LG8@DS zfcMC{gCD}_X;^=-3}8=(emAUi*1+Qx>9NF`|K^kg(N71 zLJO#1uFx*eJZLIi$pBi!djanm)_WG=YzbRb>hL^q{xBg|M1WMjW_o?RL2~A(>Gko($eDAffz(j(NV}3P^}zvIN{LRj zn&abziIc2Z)`&qEak3K#siqnd1Hveh8f!vFK%$3)2i1t`(Ux5lkFS^A(md4B$GU|9 zspEKKA}fbrz_+rfqlD!Cpj06qMMOEKkd+H$l;|~Yk#WoEyJO|dd&Ula9iC#NivpN7 zbwzajzD3{+bNS0etceW5N9lptJz)}uX=@UdMGp=VR-By{3?+F6E6uKaXJ1!&`Kme= z(H$i268_O3#drOKA(vA4m#xpLFV)R-1viZ_nMwy6VT6eui{*n#t91 z{lm^%r~iJpzSE!WKT8@NDRV^zTx~U*yEme(p6O5XbZE4reWRVnYjoxh%trU)X*D{H zpftLte3C|Ymk7w|s7BLRxrfOa$u^$mmKWbjXS{T3FYg2&-$>q#?HEEuyf@5CU%;6D(rkB5y!&Ln{Nt!tCF*wzABCn zGjQ$AgZoNt-W+6zd$YMHsHRE0<7}j)ZMt>py&B6AuL3ER}v&xgHtn^5&>zA#AjJ%*9O0S)oNw@hFQf6Wt9eU_bnts6gS1zCi|A$C1@) zr4w>X8-;9bQzrEtxJ+hlK-@T3#}-A}rQdIB7-o)M!<AYOkMOFH`=^6)3~o0x#I*MH>~a`0^16_~ZzC@%d$9596jQ zH81G~Y-gei=dAN~WmN1bDVGNB_!rKupE{<$^JCskOSFAc;J*Bby+O>JHm&?aerx`j zbbCIYwqLRcvrccSy=njHKa#4nYWCpt;9?w{GGC`Ep9Eg%DlgioFO}K7Nk5di94`l^ zHqMI3D{|@L{H1`KzFbPnY|xg@lk#;Gxt9J8&#be)XRYDPm$I#|nGF>Ul3Z`GKKkbK z5rb{;%f5y7{o2yMi>289hCQ6~$@Ig534KNIeaE0X2n8xHXRc}sxGvX*hm-$3$Y$d* z?rWR1N9!sMDTm%im*eM}zC1akEnTj!hHKSeT=Ot4!1|sN!KU%ARn|*bE>*6=(lm$XF9|a@u=rEIOd$K- zvmM-;*(iqH4ZSv!qbR6ZuclXR$RaK{N)P5JVZ}Dxk>F?+T9(}E4 z9RKWC#&N`*O%G)rmgy+W{=5`)`o3VKul;bZwP?$ujH(D;D=p!kIdxT^Xuqqouh3h3 zO=9bFAw{qh*lbrru9B~Kym7&`vXv&qT+Xg~TJ>k3N_15+kA0ol#;Dg7Ap@qVSEKf; zx~lcsua@U6*M3g(wOyb!BP*@7Ag!WTsl2YSwRgt^j z;WHojOd{XLNa$@ogSXovB?9d>+qK4gDK@AZA{AA~=0udol5WV-#b*LZtQkTMnaw&= z;a3$JBZ9`(Q&501>p^8vv;JkyJJ<%dzwADAJj>^+#5h zABvQvCnDM;CFZFAPrgxw49Rh&`Ar2jnMJuaL6mLUay-<#u~ z>C`ttfT@d;w52^0(*mF0g!9hU$S(gK4*ygXKmQ~b{ap1P6Wq|>`SEiP9PO%Fg>Xa@ z(<XoNgBBNpzlx@&1Xk5meD(B zy_7CX)PXy>7*x{-((PK`A}+{YiLIslgTDFy_7-VN$Ju=i3Hq15orATd?-p#ot04cN zcaXO9vJu36G&s03DS2N(^UOTFBOUn%@#v#@+S0D_b;sb)^SnKrvr0dx^3Glvd_O6i zq94pTVC9?D7<^x@zH}sSLE#GwIp}NYqRkVhN?&U_E1(1_TFd!mEs4fdv<}WDJpX** zKs?|;UHRMnhoR>uX}%u#n&uo(n!fhj5%t`#`#>ReD8OqR>AjstGXly**s(GW%FM4uvIPJbSA<1d%fRXFwB;@RsU2E z+xM8Lt6mMEfpatA%x$5;q?B&aS5tzR6`XWsWi`d*uVd^@rvp7+xAx$}SpUikPI*mx z=s`ksta&eGHXSXCCMlUs-ro7^vxUw3ird7mW6tJxw2O zuO6EyD*QxeNDu%aanWCOu4KB)p;f}OHlxQi)?TJl3FxoO^!^Is!&z49q-g5zN$Txa zTd55KX6nm`=e9C_ZHDb-;Q^Co7bRFUdp@5+NBF$p4*P`qGF zUeK(~%Oh?ey$Ka*l|NJoE`>Zp*Ar9>($)`EbLg#_iy1>}acZ=c6caK=;#;D)RtU3I z=t3Chp$4q_iV|0=z`0(pNflaEEm`Y_*}8_W|EC~g{KRXGK{u*Bk&6;l%gWBHkqOZT9N#CFr*~^y{6zm3d0ss0P5?v|o5u zG*bZ`m~3Yy46c{EOtXbvyvgMQA*NH2ZXy{1)2X~&Pep!dRoUya-YY7%&FQOS?Z%>sKwwkRMp~==zCrW7MIiJS$+pisQd>I49wPjzU)>aspnsyv3rI z%8#Uteaor8&1%(y=aVNY-L^oJQR(&;;r7z4i#Gov78Bq#kQozk8{Vf+UK5Dgu>IPw z?W#&q5tn9)xcyQU6b0#kss{iZF3s77|Et9}K3UX~B=Ajerz^QtQT;mcXY3*uoXUt& zNSCz8aPm7!QVU6XYsg1cat?_5)b6C<&faV-JBX42AO+xI0kBd)Pw=FP==+?kii#11 zq)Kfs26YxkOfmQXq0YtN6|r==gxZTiTj+EA_0SYn`3@x@L%bqG#wPgc6NNZ-iwrqm z$q=SJ`5V2LL#~ZD35_pRPIrBTpE({&9 zbTzZ5(34#)S=msA^}TAym;w7E6yU#<%z7DEQcyC>3lfn9-3U>mT>A=N>jnB5`b>wu zl^qzZH+a9ZB+=KJP5!j9af|JUk2LC&n*X}@>~O~7gt+(KVYSJL_RCf{Qj~F%Wm0G= z9KRqz-=L^tPM;`cJSE8xKA}bl%wVESn!l0pVTm;^0t2|_<1YEc*3SLAVo9u&5+NF$Zj zbs&u@7&z1ix>_XH-%4E;cVE(7<&>elE%uZpr>I!b>2kLHbJ5UYwh&7RQueZ~s&cYu zEe*0Nr%Ccf_R#;4+Bg<>Thc95U_ z>sc%bu{M+rPGR(@$6ey}5fEBt#V0T&UUg8b~NGaI(JxagH3rg{pLC@re zwV}zZD3hADg>R-|f{$I~A}9bhNwCXe#}Y@lh^SsmdWBY+QFK8#hp3*aMG4`l)QFT_ zmUNMbSdF?#jec)tp{uO+#Xg7m5~}0}FE^v#Ib|4dl%2*tu(IBMrH(kNC)=xw z6GA<4(3Y6;)JOG|p%=&*SD*Ev+hHYtng`AEh~4YbHz}?2`k2(s9*{O5%t$e32?{_?m$3x{lpyB8z1J;|}@E zjT@>FU7 zA-EQRKBc(K@!gAdg?w9QkZ+1+{>L#OFNuEa4tgxe2?XQo zEMv(r>wIxEvrKS1)>%e0)u6F$kcScMgnF*u{|%_8lX3hsz?BI7toV z7!8+n&j`{WxFiB!^c*Q{s-=T27`?0VeFMaNg%rloR=Q8+rm;AvD&nLcZNiIGcR zep`~!4OcneN^Fu?KeNOm7gMx!Z93g5Y>>fwy7Bf^V#`rMkx%$|EH6ypq2K^zPZV1l+$R3czrgpcmRmx8m}4OxMge19&Yw z-^GtlzVGKfg?AlQ@uwZiN+d1{qo);~#q(7Dz9j!2dCGR0zT}tp^Lh5O(na&dKS%T3 zP5MiDPU7!%(oW;Kou|Z0+CTBkow`qYCEf{;^;c#G1s|Ep?8S5pK7*yamb}Ty5@dP#8VYI4 za%_LWj|N58U-uGH>#vUiqy748B{A*SUqAhW5K*+M>IrpQ{(=I)T7Q+C*81x*#~YV6 z)pqgKmzYb)N39=Mb9#g{HL-oYqlFy1{@;z&|H5efUjR<~`aeNT`}$vWy!s0OtNxPH zsz2rD>uY=uIBnj`{UcnUYJh*7yExJdmh+ErD}RiB{s&x^Lq-6fHF3zO;%TkEGg{gF zNzIXw4$daO)VQ5j1pn#&q0Xv0*f>qA`V5BE-|}DOGS-ZR8&*wV zUV;~zG6LHcT;&ej>k_{sWdyt`g=M3vtKeAQy#?$Rkr^lp-=`WsvvSG!;mfmm9rZ)q zcE4u)W*pLV@Y6GH6id6^Tj*;^@b;@&_$e0D)1WS+e-Yz3t7t4k4XLV|-$N3Xo#DTX zg_)FzhDIZdUt+XXP5LCF*mnKN)zy74M!%J_$7 zNo!;&)qk&tof3hpLSIALf)Q>{QbCf}9rhTPMPcO<@HJ%nUT@MWtH_`&wNmZzJz&_p zz5KI3FuFw(ca?%?Hyf>&Th%*2!1q9lO82?3D;m9>fWNEMsjJ>WY-=(kb= zQRA<^qvi`-pKJ4JOG#rhoM80-(qeg$)rfO(R7->9KN#8G9gQ3^)AM{jm~p_A^5Qd@ zwWt?-z<^%6IfoAn14QPkNPK|woxE{VBmJ8A7a0X0u^lygzeg4N6Ui!{_H!nnB_HpR zsyxMU$4Zp=htPBS(3G;S4MR;oi6IOH^cTyG@}yhOHJ8oaTCSGOvMvVV`FtsvOvvbp z3a*AI6f+agJB<~OB-m;U>R6j2>CzWW_o(bSu1h3Wg6ML)fm{0 zB`1op(LdY~xzr?w;id}~oUAy$oADb~CnkowO?-oC;;jH zD=d+5J!wT`TqD^{AFeS3eRETUs_t?d`MfFix|BdiiDAkM7n7(ArbSs4=Fu@>(eY0I zh3qRc4qt|-PmxL`k{$VV1x?P@Sat4F%EmqvT+)AW(Ocu%Yzd5WF{ zymTBy43JZA>*8DKGM7hFz+J6$zp>+~qlN>^ztc&5Jmk-yKIzPrsgA>}&J3xJTdLzF zM0GN$P8!NtMyyK3E{jSc zqXwx`13|xqgf{fw)Oq>Gp@;A#QGDztbOQ8{5v|Zs2x)rqXoP%a|9n4IpC6uBeeyc3 zPhqF^>6|{_#0lMGm$wOlo^0tKp^X^L&_R$%TMvzlR^X@}dhNGIA;iQ-=jD%%l|SL@ zmOr`E@&|wO^4}Z~Yd@i{L7yd^mL9~Q+Cf{4`hOp%{ju^Ve7*ALbXxw9zpOO#xM2<5EEY*h)|Rpz+#$!@(kB_<|**`W$DOxKDz&A7Z>6~3zcH*=!pzfFj? zf6elr@3j0{wve`w!B>?(I#&J!vwY}cP=P3UXTe`AM+x5?)q6YaK!x6|*BL;tbzCw#r~H+Ne8kj~04W>gmMs%jnj zK#$KbHeO_@7~2VmHZHbty_c)PLKB(fYqnhz{q@D7P{u;uhu~lOn_M95-j+liT4D%1hDhau(!}Xak}S^>H~dt_XHU}=1F-NuM$bdjVRo@UOM#-<;HBNB!j4{Cow5v7XzMhDQpmbp446NVPmloZ++Q5yPaK`|nC&V?$l0b?0jluZ{i7Vs5j-o;5JYfrf+{Ljw#vyulKQo^|kjS_s!Q_cgI^K5+|pWl=?I*B=6 zs&BcAm?rrQOBEaA&J^2^gU{LGK!GNo$Fy6k8br?uf{nfXL0zVx?f@Za-*c?MP~$#t zqiyr-@g`5b{;3bl*DmkM>nomeil7-2g=faXSMEM5t@JW=sve#}{BT;{YohdWPvb!; zN1gWikW~(+7Gs`iD0IlwOJBjNodk>@#1h_WCEUc+LQf^3^D~5cq0^~1h!b4)G<`(! z0uGt39?{)6PjWe>85dc(J|$O!O(wR?Ym}3}->kJ>kL}~}p)yC+Di@N6Fv9g(x2LY*tad7J7CN@DC=A=?K4ct$&=$*ik?owq0q~y$J)X z--%TuaDz+ytK|5X@&^iS-m3sg@AFG$<<4{_!_2;F8>W#{@J<=w&b&$IRw982WdJ-s z3M%S`d$&qkBl5BqT-l5gGeWd`v!qEXqH0x~B@Y~mDKA%<@+KPZ7}5H*(b(HUV>1kk z#%jL6=2x2z%#yS)AI8T%RFlrMP_C35m&ZP2NxE%+jjB3I!!_+)3z7;Pv%3}~coVT# zVTC&0cE0P+wd`L!qxLU?C~3xEp33r7K)|$o$^4<>V>M!~@sCO~Ubzf}yoBTt`F=Kw zDSr2Y;pu@p#53{dD=Op-Bq!MkrR24CMfAl-NoAd^Dr1oeIXyF3j;Ji_e$A=yYy#^7pRppzjYHcaVKmPrk& z+(6OS7^hkltPr3gu3G54`r+yJ(5D3avHWIMn7tVBAfCTP{N)C&7A4n##F+xcATuGn z3B|@u95ErIJ)amD#pL6}BbdFXh@(pCW7uL1cM_6@52btrYXT!I!|Klq9ccf_=r$9K z9p`{@Hf4*dDWYPsar1qOg{CO3m_=)eonn0aQ6%ze7KkIU*zK!+Mgu}~_%R*Kx(oqX23om2v8MtmGLZ&1AE-7zcQlIweS*g2qc3JQ|EeXG2KJ zcDam@e1EHJbTmR?p-i+7C!SPNGkt~93SS`ws7ga0OQA9@!EaYRWK+vVsvY3f*(OqyBoT>KY|Q__ zk|xqJTGcaJK$`LK-3d176Xt)}UOB5|v>Hr`D!0*bg^G0ZXjB)g>{7FAR-?>D^`KD@ zbOwGq|A&#h9i?TGHq=wJ>=;yF%5eiU(LXkek+hdg*sv+V@fcm|kQzJ?LPd^s4n`KME~?n?MLCCg-6%i~if? zWH|CWjUxkMW8FAcnJgtZWUTumgJpEAa~OBeNw6(p7bKI9G_we;GJ_ICA-s_@o3yF| zDUZr=g0CP?*59;E9>6Lm5A|AZ`{l z(g{n5s_ik0Ote`Cl}*j^&&`gE&1L&dWvZZQggs~d!TtG%^@-WqgT0A?2v^v=owayX%YGSzS?r{P(#tB=$zgKx_*rnbq=R za5F4eOq49AT!=JGMY%sKoV27X&r^*TE;Uhd8ZhEf@*=Ghk}q9kkE4^S&7v1s6d~kN zmZEBEoO>5ai$thARJTkn^Y933)>o=i{iL|N)NvFN3CvU(`4-Yuina1cUMTaBCy0@` zDubk&^)}H;^CE@nClsLa_miff6DwawgVX7fID`LXGI`yBg$karY%i6RLZ|_ILNn9| zR(6I_hp>?D?++2vR{4w|K@h_^E3>VN6jL3BGZVM`;?G1v2Sgutk^~!*1kfb_LRU(I zULzBY!DkAEqZ+W)m*`iCCa2qvS*X`g>OH!xl zLz9DsyLxDM*=w2_In9S=^nk+>>^MXu&nh&Y1jfX0p`b;zJdNdWTJAPpe@`9fTXhN% zbX_j=k%c}~*^HO2e~isI_aY{Tw;NN*Z&|6XBWR4}$DG(tBqX(yof!Z?U3v8bv`_s8 zM{uXpw<+*lCMEXG6-b|xyxZ%x%GwVb}6LpLOw*as&gr{V&yA9QtODvSae_d zuc&(5w#JxHDT=Mq+YjtT1D-1AJClSc^3w69>isU$7b4UFW=+3W;WjP*HTBVW<_xa6 znBXY_GkMnGYN-jV=9_bKQ5y(8#zX!gf@!9hvbf3|8<6mi#R#?Ol8bX|tXo{3;*;by zF7w0O-D`@_$7>m$Y$c;bGk@gWsA`{1oH=#4z^ty)-20i;?V$I6KbEU)5r2w+yE68n zZ3@wH5z13$^aE2jhBTRWI72IO_^!E6^3^`0urh0r55s(&+I1inX5X3lY&Sh@rBl55Gk9@?;`CbzDT~Ktfq0$LOR{*)DO{R z;;JDMIYZw;nyhB>umya9n#DWCKi*z8MvMp;95di4cTOFO+d$qf8y{mYZ-2#FeT<>0 zSR%uHhApx;+waUpliL(_8y6B8nWbC|G6~A4-BsUdT!yM{9*@QLPz{SMCo8yf}uBhzlPmwb>l zjB6-TBUfWsR;nzY%`aO=#eG3WZLUTm4WCElZgZ40wX51OD&|}1hTq$Hb41(Q97)!y zoOHI%B+_Bb&V-3(B9esaTBP~51ss$!*CB3ILU-jTeBSevw7JSkwvJ@h0PDn-XciV4 zgVRg>@I1SJY>IzsDraUO(Pe~S)*}aVIK5fER;FiLh*i+O6cI(CzV^_JF2D)jhSLqm zE$eM;RLQ(I#uaGnqS9@4kW(1YT%sHLf30*wZ+G@l5fxPvUB)$cKqT;|P3_HaBCpj% z&uQe#2NPGv5RJdtY>7suCybkI^MM$zTi!x5qY2~8Sj+J5F_JgOdG$osAJlm`_se-s z{vV`pWY7plq%3uOq|6<;j1z;Pgp~3EPnWV&BeUI++2V~gej>{~k>U)#gyjq}wHA}4 zH%HBY(e<_X^LD-(eyVto6}KxP<+vprRsYmz{U;t>`&9o3Cx+be2bi$k?<_m*>f-T} zA`?f3`>6V}h{V`!3%ktd(e#1d(xExA`>VbtzD_rr5}BO>;w+Tq`BtWOin62HbNv3e z&}`9u&5iHl$0`2%Q}>I)C~oAk(aI@Wx1Q^XOv*hj7TZM7H!S}sdf-T{lSvOp!52#G z6nQk`KdpcI$%RkO5^V+_$(Xq93dwi0WV8yMS*jc`v>sr?sk`U+W= zt?Y)`0!1EluuZ2UzPUuc!G0>lI&&EHG6Gf>NNB8hV%#JT*vFr?@y9&O%vq{>;Z)(iu4 z?fDHe&w5xt=+9lO=ROkf4z}xu*b?UxMMr&|^}auA@xU329kaLUN5UIT9LQyG#YRuF zaaHGtZ?xVcI>mg1kW{dQx;6lYU*^oTOkdFfl|Ki}_+n!{8IHn8ePc;-$LfI-qHCXeYIAkzR8xt{7_(&llv*v z`97Tc6?EqB;dNZuet9*$Lqv`tL-|9p=;?N+u;CyfoONYBP3s zgF+qRKkz9bq0o;NBt;UKLeRKxQH6R($9HV$SyU~>qwl-TKHeBAy}r^Zbr zt;{g}l-uUV#mqd7H_}@*Iuz`hV!Jq*HMBOUUR1*zK zAV3HqphXCXfC^}o$rb9-jaoH=vm%$ajkuK1E~?#I)B#DKtjabPIK z<-s<=%s`V%v3Wp%ZA9qO-1VV80Q}n9Kvn39Go0NhpnRN~!xc`wh5fO6iG{E0v|^R` zF^T8m>pH<#!^BsBE5XLlfcza?HYP8~@_C4Qd@G_qRQM`cBHnIjg*P}QoA1MD1<1Nv zg||k35FXojvI7IlJm#{6ALUfN3&btjA49E|^SN1qg)SrxG?HsqlMRGWf)6Yw7exZc#)M5! z9N5A?sP!dN-^@N#fM`VfFi@XlnkX;UK}6}p8Gb|&{WbDF+Ql|{kQ}7By^cbCviJfdCIE(M(F{YVIb=o$q^Uof!sov<O0K$_oI)6$L>kMD88Sazgi1+;=}q5 z@F$`LTPZRwu+~|1+;=2A-5I*m#`@4FI$Y5|^2%;Me7BQ2CB=IU&0wVUJ-)w(MmYj& z9k1H~e6hji+->8t%)K<5ai(vchqnOwJLH8t<*=&Bywe zVjY$DAVA4H%-O(DBvyH;@iYXCQT@IUHIbCM(66$Gx*I?1E$30*Yx#1X`H>wWa&Q00 z5BP}j_fFOq{zd?shifv=NAy`j?Ji$uA^JsR3FFtrWeMw{X6XsCgoimkKyH{(ejjy| z8dt|N8X4%DK*Ks@SPx+e6Q$5rQ~Wwzy(P>igjM67}m}TzLb2uX5d}*vFiR(U{YM6}G zV>-i_LEd6Tm{%dohva!&cVI=LnqcS&moWrW4Y54W6ak}v;U3 zl@*}Xb*~_Y8`dMEznxr3- zrHwb&5}2L2tT~|5|Cm4<$pKndBR~fOYckXvH)`#w5%T@F2{MwwkjrC^^&YHJsLSVR z@aLifELO{f0Z&il&%N&{4lnX1{JF6rUgSdUr|dOx5+N*qg8G3-PlZId%1wqRIi9g& zZc7NN=HR+i`=mNoz73o9NljOO!x^o1YmpyGY|(0g<&S}-+L0+16X|lN^1zuy!S_X^ z%Xm<$DM7xi1wWv)l5rP`jN9X%kBGZpDCIv$xG#g{SEBC=1>7^7YH<<~cT)Ku;oRD# z?;>OWW(j=xtK^N|Eaj5R-}+yat0%89XNN!?B?_xgRoT!2gddE4J0wjw3w&YO#eVvC znY56Fb2FIp$Ek0wxmMqqTVEZy0N8_>0sy=EVUOK=moY7tWSiMl5bFU#G8p%euCIN0 z7wtlf)oBY)eUzwau;ad7a;s@@vz1#;f2`BXu8ad@OdipDjAY5G4vM;3SuY{0)cBEE zbGN-x^I9q{G|y1CvR5=KZy_X2d6%lx!KhF}rL-)8x8<1Bc%?n}U##5ENG7qz$f~NY zQ$m8rq(WaiSC8r1)EQfzklY&fuVwmpd-arLEPO(+?P$u0x&Lu;E8&7`qSsp2M0*-H z@s%mjo^$|r2|YST`x#ddW9eIE5Hx!5M`_D-C!pxHShMXojm*VV7fY$Y$2<(oG$Yj7 z3T$kKrXtRnP>eUOab!lUzdqqGrhU+vUt~!`a^dB^x>ofp6@`YDLpo*I3i6h_H#XN{ ze0D}a>boSg0M^@kjYPGmC@%+dGwFxJ*unc`brANtU1jsN9B)KSGW?t>s4F_Jl67lAv~}@V1d_{%2AjCXQqI!=DgxhwHJ@Jyi_-ClpKDqcC{OtutqsPzFo_s zOo#SkxWw^Aj;wE9`8-2vjOz}lxccv#9=g|IT+0_wknrBGH^HM98B0#ZC(!eRWCA@+ z*VSDbk^4xv;blRMjuBg;k8mE*mUoj_-&gvPs^g0~d$Y}t*)<9r2`ID7jVnEE>|!|v zvz1RGWV}I3pjdE%2e};o08uR2a#SZz^(~(6`0=fL+nB(L2L5+Uh|C9MLY#x{@DqX0 zTyfRG-layK>WTL%L}yKEi4aBeXsM|QwV%Zdj~gnB??YorTb$%PPlyHeQIj!)sdCak zz3Dtfs+TB^|H==^jN8}AOn*6ZY)(ZlF@aGox?g%H{c(rv`lj$0d)4~+b5O=*>pPgGTCDV`Zy3UA1cupsLz`2C2h^LP zLwur}aM8~2IEOJszJL~QN}(=XTrV@dSA6982<7pz0=okZY{YVexvf&vRy2}xI%&8yCT|dS6iOMgsohpV6 zt0#J%dDER8osojp1FHaxP&6rb@5)(%tG|KJg$B9_hK8mI_>Ww1QmOO2Pb2Uw)EcO_ zzaq)t*j5|vIlDMrJq~5 zelEGznn+;GmgF2+=^nR|LnO0bNfQR{Ty;34ecbRIBR4#o3k7I4eQHK?VWtX|dzuRe zNXVQT(D+NR9I*<`H55Mx8PC&mH8)JPlzdYSKoH5~*am!8Ed(<7X2fM?M2+-s(PL8MTA?>PlN}`=kkw<&EdHS!~?5Eavs2>+eiKVt^4PU3J+Bo z+PsBY?cgFw!zeK}-Ol=3kIWt%?xs>VcqeJKT~zA9;nCal6XeT1PHn1^xo?W)^d5Q} zmWZvA6-{C~-D+aU<#Sqa5}h&?5G=+Qx#!^N!mCn@oaV&2@!n7WBlakE=uP&!`n z6F^zngmny9e-E$ zja_k^o8K}gmCVt{1l}VB%J!(XFqNSQyL#qt)QVd4{r3IZvkh9F@o<338NDjp=DHwt?czwBByUCO=5mql05As2B6++ozomU#^w&Rsv*Shzy* z>_QM3FHty56N<$Urt`}%j!D_I`c8_vjVftwsS)InyI0OMFmG-X9}`&dsdjjb9bb_y z@ZCnB#^F(lBGt&oj5mppDkSkAg!SFv?V4mjXzJ}!3vhZ2pX)5+~vxOHp#7klM8VVT4niM{(Ev|m3`~!*GXU4HeI>8<8hIuEb zo%Sf%X+VVY4lY%Z_i_ZcpQw@SJU~xqgkI%rxfgeIkVmm16)%6xDu# zH;VRtRekQgTG}GhQ>%J|;Xj_@@b!^X8hASJQ4msj3fCJW^LRDu5Npltb)XkFKa>I} zl2I5-4^7U{=_nI98Kjr97I)3K96aSYLX*?*ke3PBP!2Ysn#H2kkxsS&L}tsJ0Jb?V z&_K~}&J*?y7vndWt>814(V-k93U5dkkn&mzeT{)LY_Rsw_|dlq_r5Mi#SWhi zb-`xz?OJdZ>Fudsgi`+K@LeOlNh*&GJ-0VoCyUSqSsf+lessnE4}B{&KXHfo37OGT zA?_FLUnGx|Wp*xTTw+51mx&`7*O=^JJ_&)(m7n>kJG5A-!Ixr4A`>DLzGrqudN8$_H}2g!}xql-yQia(KQ@r zh2QY_33B)lnPlQ{i$rp1?6w~hVpfOzLs@zXeEz|X^IL=namKPVrq*HUUfCm1zjpSJ94TWY0;iE z|7L0as&5gm`tZ&*gu;%rtevXt;3?eYn8&*lsuvZDiIS0D$ zz1P06wBmucvOR~5Jq*NMjb?&(VuJO#*D&{czV$h8?#oNz)LAYQ?bHRxSyf-RkSN&`?e*8oB3Ts;7Q~T57@_!LBkfj0-cBU(ZaW@(4 z+B@T*xWNA58)EfM>>rwQ^?ZO$ncRe}HN?!iP z8Ib$P35ZH-N5nxSnG}fP5PClvhtLi}KqyxrbO$hKhfvcLqc`uyZ^)n^^lJk8i77@t zv9bm2==Qsl;@xh?f|V809CqTi@@mF<+FyQSp8HpOPlM+mXI&)5p5 zDjXs6Kl_4Pv;Th0;s8Pe}e{TcVN zC6eu^HR+{nT!OHhI+)5_a^aNf zs6cM;q#2yi(G@h@p--p`u|8(Jo~$hrBJpxHC1e`p$b`5?n5r<*v_E@Q@F)=5LnB#h zv%%;dN&^D(^5y(yzMd2?)LwT~#!4<5W%FL)AD-jQcs&Ua_K99y z8GDw>yj?1Xm-!xk`1K@T((B10Rxmb3tYKY8z<-K6Q;jPHXxgZCT5ZFkPSQO1u(7O; zZoZUOJjj(CMu! ze?`maJXklCT4b#)rHxb3)0u>qVPH+nSe|)2#a+W7V@wL&Xokz4#D%IWWaNrTAr4uc{#zCgCK#TzYdyd;Xjs%!T%#2_%E3({D;k$(@myR zI{72BPICq%n{0^PPN(y6pkV;xn?==KvWx+dRc(RnK+(U=#NvH!D~T5%{|;=85B zPgR`V`w$YydS8Ljop)1&e<>kqooWhS5I;&yNZ`z`p~0tW?nljVYxj^DGg30}rt~e) zCz7}`VOV5d#>mC2@{RGkf;ULxMW*}m)tJgs!s{5@jz)A*o&B^%xt$TX+zK= zqj&P-_R;%_pkeSw?K?jvU{-Z8`s@`H9E(Bf#P**ntrLH_nYzmZ%Hoio0d|h15KotE z=y-}SP@axi^F}KANjO8uiSZSLe`RMv?`I{hdF}eTm7k4aK%k6r1zt>)7f`eisV}-| zGrJp}acUm1Pc4Rnoyg}v@G(q3ac3;k(Oqt%ylCb;$)*?hy<;PjG=(bU=~PX0c&t}7 z?JLjPiLJ-%v5dzFJ!-IL+rB z`YwAtN+Lxk^#YGQrajvz`%erW!9{CTKjx{n*WN5+#=jUL_;GclRmlrjoE51cN1Q)| z(mSJ97y~7v>;;FZOj;0}v+;erFm47mqH~W(lZyDs!Lu{k)6{RFqiNFdFo1%~xQgPF z<%^ld5`s$T(9N)$l~#Q~*Ydy8syeeQ8J~S5v+;4Fs?FdQrui$!W>H6O?oz;c5&o@ zb<;8JuC7hHWqXa@r9eW6aD0Bg;? zXec$FFf&x_j~Dt*sqq8i03Nzra+Fb3Ljz1$DBm}Xi=+J>nif=sqPgaYR}iW;UO%Wt z&JlUA{X+*nmJjt*mHPf-JVOrCbmq?q343z|S>puQEp0>Z*X#lWShe*}SU|}ZreExAWaKLr!@5$~M{}F-^sO@f z#u!QqeThA)Zu$+E$}ZGfNs3p{PP-)#r=Qq&%K?CL@`Gj}w~xTMK?gXv=2;++Y`zUeMqzj8#wT0N+^;~t-mUT-9PlEM~ z*8nXz6;3L=ST&H(Njq&{(FL=i@lDLoHcetDh`6AzG{(d=TY(L?xlUS8 zbsA=h6|^AocL^W}!lYsBCUe9`npU1OLqn_)|HnRaDSeHn#R&b8pz$Jq(2guMenB7< z?@urXsX)LE%ipKoa4CIt=f$Yq*O)<*Y&jOJts^!L=8$>v&pVF$tmO^Nt^Sdx*$9?_F z=Owd$8F)atGMXx6R*UFfZ+b5KKIy&&whh_)l-i6-$iqsm<-naZu9r}T@|#r7B4LZ|RHXC>T_rJDP+vGXnJ!JdONY`~k2C13SaVMoLT=1O<$%^F z)B0P$6lk#X0d3Lmqz+4k3XKR>Nn<|OB7`;}|Ms6sp39#k?=@3c>5$;NpoW?n6N$0Xwjrk>u^FhHjk<-8cwG#)T?H9s7d= zEhbUh&C?=k+X))$_@nj*YYC|O#H+4}ZT~|^5gWUm>ctetr8e*F7ID7se@WWzxCmME zxlF>D%!WUDj}U0}j;i|6&)CVIwASbm|EXi0X}4^AV!PWr)<)3yl0T|rpAm@Pv^5XO z)4pf2UjNnJ|6imIW$*uGLKesI0zuQ>zbd~9L0e2e3L2!z&$vbH%y~6HXKaWS6lX*^e?k^1!C#=Gc8DmMOX4B|lE;`wK!M#yKyoFVCrbrSQ2}0TRBP@ux|ppAuyyiHzyglCi0}|pRzK?P z4A|(H)1R;TrWPd4ZU8?nvIP!@`U&CF77B}RwC-e_Do#hrd09dQ4q$YHellyFws1RN zw!e?81}hPu6$0GjRKizf+BA=y(+&At-;7b~nFVFm{yEE6g*W zy|T?`HxEyJv|PX)&1S#H6wxx&jEAHewco2y)p+kwR$4NoE)+_f5->{IGmSGd-JEC= zwY&b6=n{6b)C)D#3!B9(qfIYyM8?n!z0C;zQ1CfHN^uj%*hEP6<`LkPDngy#i7E5~ zAR~_6^Hv>U3l9tu%qc_jUAjxo>>SDZLAn6~^OqB6{&G}RYTSw5Uto=c)0p7z_yT0X z0fQoJo$>e%I;_cRv5=6!%?{n<1D*C-fciiHCFX4kMa|P`jFA!wM5R`VccgP-%m#{Q zf=L2K|Mra6SQ(#_^aSg%N)Hor{YnqBdm^Bs4~RgeDJ9t=D0hO=&I{Mj?9gz<0;U;% z|3HX}T&*^-BPDvJ@hjpi%K3AGQiV|?`J}sx2#Ed~qMCaWpnWm*k$8olL%P`e&Ht;VDY`Zn{P7y$2gnl&mkImu_Y!3OQ^px`$7VT=?hDm0w^IY^lXPdO)Cr+;8h`!s`RVcfh_YYc zLr5eh9(=CY&85b2cL~_IEOx?T`rKYU!r~K=7kU#9r!~i;>iVbyUT5gI?&Y?Sp_ph(#I95)#JJrb)jQ(J#sOZeSt|8*`AJqKo4@k1!;2BOC zvL77oU+*WX6D3mWguRUpY>4#quRmhuQ^n$WE-aQpvCehUK6n8K45hPlLhR;=#`l$& z(apSbn!qdl+6>3DD6Xb zhCxYG8hx3@aNeVx>ew#Z^tlc$JU4e1tc~+Hq3L32g+a+?WpMAVs{zgt`MF=18rG2~M1 znNjlz?vz|!)|Dqc1<}0tcUeyI0P-D^rx-V=uWP~Am^;8MFSkB-TjW)FL5+!08Irf$ zmT7J`{>~1R?FN!gv7WSTrNrm%wV%|R*=9M)xLb!!B{9H!DV>j8%bz9rXH79wO$v9| z(K`y(&+Db1rDm?|O3u%KLqxVSvSsF@j{FlS@etN(=i38K%3bgwaWFqjIguaAmpxkT zuo9jwYViaf@VJJXesx{S!8uiUN8xI|M10M2W*?B!b5}PUN{RN7`T>FxHMf_+!TBLq zYMV5vl39!>@G038Mze4Md8jkl8V>bL-IZ$j;MG+|?}T_(aYSFaTIuucsyw8W`M&H@ zxj~fqDmN=dzAa`En4S#u&6UCab-fT;@eRE54y#*f}lvX!XnzS0)%p*pdZH;$+MI7MliRG6fWB8U2UsqiR% z*Uq^vN|}Ks#(97=A~DbGgSdTOv1KLAvQ@U(;KKE`+3%~y<*tu6Py1Ozcxc^0d4v#>fNMF7JkF{dd}jeNm^8;2!xSMIL6xqvJDJH6UMDtiJU0LEmK zMG-_bC6iz03D3f5!yaR>N>gmmAP{3fhcccbY6Hrbsvh32s5+{_D}T$oe(Vn8yA%v4 zmHnes^HqW3f}~?67xb+9gwR*orT7hp@vFyFkpzMm_$){01lb0KQgu$AxVw3)i(WaD z+>!;6u3%wBQ-ZwA6E2ieu(M^b@V3u{S(Il8k%%sR2k+Bn-6SrN@IAls&VjE9~~hziZX1WlnkQuYgUdZqmXH=j!C5QNIw>(z~fG2 zT`K`#Q%QGwQ|IK!YaFk~n_o2oB4%}6KsJ@5vILMxr+~T^{GJGEI{AB?n+Sy5Z%F2#N63kA zpCZEJHAh~-t#I)$xsXfWxMUw_gfLK2AVkwd(^~(ELfOO#aI&@ozE`EbrRsJH-ah`# z8}jv~JWjNT;D?uGyhJo$Pciu{xuq>NZ>d6jT!v2CV&BSNS5#})AFE+GwkvA|!5FP8 z<#To9)t1s|G!St5!6&@l^nB&tc>(f75XWiycYc(&{MGN8zL{UAlqA_3YIsNUP^6G@z)cl%-)417JrR`|EmK$#`HrF$Ya2dwk=z44_fJL7y+L`C-h_!7 znRosDG|v`f=l%*jdE7(&A;6{^d2 z0dg5I3oRH2LG!P)`4;SDaxGOz&g7khOOzL=T^JNVJg7|D$&^xmXYoD{kbB6juwjxK zljkLO;*9ME^BB36wZeWP-gAaoFwcH+2((!XsMfGlD(a|IeQR8}c+h^gW&20R8!}gt z6}^;3ZB)xuFx*#7^JJ$sdY3~O-85dX3-l~%2&Z-KkhZY?=O3vUE!GFLfJhGo@GLr5 z!E@OQ2fHo_-)7f0c=slo7#VLE#wpHe+QRP(fASDLl+PqqUuesp#Hnpy7gO`L{9{@m zkB@{MgUue@a_$#<40a`ZrRslEOY&Q4nt;OY^FDS`28U=SW(GqNxlKk1z(?dbNTy(+ zL|9Ys1vQA)^s)xgnqR!B0aF6jq}sbX8DI|$nITAa&@r_9+ zIeZ0TyS3W1q{6{z!?>BUz^-rfz8`rIaO-=_^L$w;egn->&{YK)eESv?!0KIw6r#Y8 z0^rWxO}u1U&^@6^y@TKNr5{9xf({mvBvKqKd z+Aq{e77k*C5N4RMGJ*JCmYY1aAe%GHS}P>QT2l}S&YD;{IW_@fTyju5t037|&W*w! z$~uX0mM0uxlfLW6(9T?P&f@TPeV`DPyOP$TZ!b5M>MtCrDlyC;tl2uAfhW??c|gO$7P=$d zDjTcFFjjRXZ4Kh^&<| z0JeF?JK~}Q`w5F=(0oA{`4`21f~Qpc`jr+WduLF~B;`>j(|!a{$qZ0KhSa#Mxul!j z&VfSoZ>k6>7j^i%)=@$M0kd}BZ-jdkxxPh^+S$^RH00v2 zlqS+zfr_OaARv){3J`-j0FfgoCVN>Sf?Cx87z+zi^gV1>J;vLRYLEr@chW1HuSboE z7>-k@6f8Vxsw+rKto-5j{DM9yT5tzh&=eXVq|MS$3!7Dx8r#_dLjm8F(aPP+oJf~8 z^2}7k72Z?cD`R$ED=v?SB3k}g{e-qq5YLR(7Rr*WpJWKqucJU#3%Y5g_C{^tX8HmM z)6q<8)QWcN`|SI)XY0iaYgrU$+sin_FH{A?rW>ljaZs{1kRq)}`zwsR9gnvX3bmKb& zMTxVUQDN3rRZDKfH&y8jwlRZ9rHv+5xa=@+0)*Lrj`R>rU_%&r7lsPL?uP4FcorZN z&JN?+da}_X{bB_`KZ~5=m>>_mw0&TkyYdq*Ldy9&?pCDJy^QzXLMVuOoOG*+Fu7eE zqut8cYWo_=@M#NOusC`HegiS{BP@hlJ~2Y+jcCDrvMb0{XHbE62pc}CnjCpkqFH>< zsitYAsZ9!}9yAG1*z_I;Jks@JB)E-IE8#6hjY)Phdv4Ygb4lRuQjedpRx-q?ye{@s z^J-Fg{-S%#U%WVKwUazk=|(AyoaApy@m|Y%TZ(mR%9Nz?XIu|f6cHDa-(;f*SfeD1 z4>X~Al4l-YHzNtOZ+N5_Tabsf6<*H|Au5mQ4K!$sQ=g#mw9_XUY*{g?-%`#T%2><7 zL>YJVC7$ttPSwf#NZwTk3uzKM2K z# zi(S=Q;>FCLs4li#@;L0nYl$BbP8y&aYoS|Nrb8T5y>OHEFQI605O`JqL)faDb)>`>i@7 zl$g#0J<@2d8mUIBehHOS-I2kqe!=9PDB6p7NUij$I_MEei*d-!+FsAJb!$Pn=mzgM zi+*8m$-bqgAJX37-g%mSHowVxm-YJCQ3SgFQwJ)#a&5EtM1GU+ljuy>}UTL9%sia>Zqd>{{wK9O>Y`4tfOfx zy|P|fC~YoK)+%rNT1iO+@s=z=IMpsxd7c>Z2nm;E9Wt5Yki1YSVQqO1;voetT-6m< zoxnm#fs3u}RicO~9O&OSwhJ!UzAAM^O^#uX)t)^^vvk!HPDRnHiU%p^9otuDI`Eafi5pQ zg*G9MFGv!mupnXIK(3Q!9dU++t_D5z#KjkIa}?M;3=mTqP*^T)p3583eUU`{2JaM+ zzwn27Eh84GlrV%&*bfCFMeG3qBP>UdleFMWvKX(iC_$SQoc=&KQYr;yn*vNMaI%sL zArMlt@}G#K$nP{B7@)Qx%23uUdRNM{sN>6gFozE3@r^;WILEkdHB+MN%Fie`*|+{*H>n&f2rrNTTR#RDLEa1LCijZ%s%o3QwR&nST*&>!m3|6kMJih>c~;zLU39;* z)VhLb+@CD~a)&qo=2JTD8t2k4tz0ADQhF)orNURoO0VRk(fnuXqhtcUbjB}_Bb{nD ztE|4m+aJGsXWy_ml+OPU_JzB}#awXh7CFdF0lj3>p{;s5MvyU=$i`XNl`<^k-Wd5g z_$u}c7=K4N<3{^xDJkkoj?#%n&KgDYxre`(+*p$UEMk=Px$v3gM;4+VfG3$H&(QqpKSC^GCmm@Q1V2AWT*^@j2cR`XIY@iIi zHc8(J69ZYn*aP3dA2W%aYy;GH!wYR5vdWQ>yWwCLPCQcA!L|VClMAq#LrxBxK0fCg z@gweA)DbsK8OuogoZBVNKh(vgtS$LRG|YK`=5L)-e92ICg0(13AQExCBfYSW!7(>+ zL06TxLO|>?D|}ii6m4@x<4l<}lG!J%oI8LoJC$57db_q_kJY7*+<}eu#C&shSGLLt zy|(C=RF&|({^mKoQ%M4;E4BT8g-o7@5#z0;3F|6Kxw^4gTPR2Vx?%r3|4VJ;mtqUz z4-&Bn44ULg^WJRy{_otkm&qt>;(A`dSxj;JZjNy0HDSccmI(gnXTt?uqM61lDJ3Ny zYcHV%CrQmmW#IzH9;PuAm;j!+z_WD?3eQlk;(~>KLU65WDcnOoNYDycv=v+x1O?8; zx?l}i80&;VUi2-%QSI<3Q{Nr%?k}8(0ARbFL$^k1)G<13%a3X!qtff;#8`dqZ~T3E zLZ5f=V)gm*$TMU!ej>@zxfj}#yiYJC-KtY(^v#hvq@Acb2tRBSeFs5^M0E#y!gyI4 z5J?P`Y%4ANc!U}v-w}>qMDi#=05+G7`B;Zuijl`mMJJ5A`Ur{8BT7nV3{h{!2g^;m zVbY5X*$fCt6S@&Nl{C9gW!v4XRa$T@jpGb)=(K4(gJKFhJR7MiBIr~0ci-UXNE_Y6 ziJ`s^Ga4~GROYv!j8*kpHXQ6&d#;omoV2F;2My+?kHkVAz62v{lGtKZKS_*MyDo5W zf1u&rKx-c@Fq0U)!Qb#}KX1=A)F140d~0UIvQE{A;uW&yw`hy}Od~cdXF#K@O&E7% z0n&m+l&raBx!r&E1}%6CFaERBwBYpwBG>RI{KVPt%%nifKDQw3>cgcq!7W3~b)S%( z%lj7n)@q&pRw@t#_qS5PuLu;Dao|&fLBARl7ZbOGFz^vi5^2`jCgbuKo zbiGRYC$C`#Ukt4o@iCqi;g9ubZuaFZZRf1$?*{Pd%ca!KF(< zE^b-ul6aYwsPQB&>HGr3B}?3uRzBr~U6$;lfd)s`N&U+}{b`Pw<}StnR&kdkaK;G; zs?G?Z`BIuR@^tt%N8qG`X3b8oY`stQ=oPw9nSbZFku>XP(w*!+WCVsR5sBoum==GT zwK)(=)}Hz!W2Dvg(D&!=^|ws}Gwl218N3~MYPA#W=SAOaMq{n&oZKQTB6l*akEhTB zRh53q_iRKCpcS=n<+o~!{=@)ovr@vhKh`?~h=PaEWK1A%?G@r?5Y`j-@z;H<%|89(z%py=YTJVomD-A7B zp)*_&xr+EmfmC}+BIpSgPCaQw(xH1LU^C&!T6b^_(|c&I;U7@NVv!me&}>KuMfDqS_hSB zNk@nD6QaKhKJ1Z^+Fvs`x85HE9qR23@(kXu2Dk`x0OvuH7D0VcbI@v;9f^_enUTpD zw722|Yfnpl5aH($*>Z)8oZ%-<>N~BaTpGf}`K8*RvYapm04Pws-FoJ zcyhPN&^@=>zKf?)cfnwfRy#I@5$}keJZ1)gSb@eJ@){$?$ZO+v)SAGI=M9TR>^_U*!Aj=9aB zKP`N#-S-9e5YN_Q-y`seJ!@xV2}>l6w&=!M4nmZF1htT6iH$7mz+8X(IRD^j;fZ$N zF{?1BXU{sSno!|3oX8nikjy5{J|gI=f5>EACevJx3WoKQihnN4vEX)|C-Ni0%okqM z^4lu<>#fG>%cYh;^I0pdYxMAVGdTNTe42RsA*<>W;?Cv1@Yq4g%N%r^+Uq&Vi438} zWhpEpyQ~$Y>K&pnxGrC0058>NIBHNp;oVhT;;f#Ls!tXhWNv-FTc4bUGvexTBERix zOF~;uEwyipI5oe~`z_!g)##g0tKs-cjb?-Ws62x&0o}spmz{AS?WQnr(CG1M3zapqxzR45>t)| z41a2+a8#X`wv#l_fFgm0g#VyQU!al zbU3I#nF>AnNiq%KEem>it?xE*BH}H4nqr~-)(A>}ct#)

xi8_O&2bA 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 N{PutT`Tr~e{|o8s+tUC5 From f356fc51ccaa538db4d6d772095f1a5142a6c046 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 7 Oct 2022 14:02:35 +0200 Subject: [PATCH 407/599] Stip quotes when parsing `in` expressions (#162934) Fixes #157751 --- src/vs/platform/contextkey/common/contextkey.ts | 4 ++-- .../keybinding/test/common/keybindingResolver.test.ts | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 97473d6c93f..b2bcf092821 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -162,12 +162,12 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf(' not in ') >= 0) { const pieces = serializedOne.split(' not in '); - return ContextKeyNotInExpr.create(pieces[0].trim(), pieces[1].trim()); + return ContextKeyNotInExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf(' in ') >= 0) { const pieces = serializedOne.split(' in '); - return ContextKeyInExpr.create(pieces[0].trim(), pieces[1].trim()); + return ContextKeyInExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (/^[^<=>]+>=[^<=>]+$/.test(serializedOne)) { diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index 77935d73c2c..8e15fbe71c0 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -235,6 +235,17 @@ suite('KeybindingResolver', () => { ]); }); + test('issue #157751: Keyboard Shortcuts: Change When Expression might actually remove keybinding in Insiders', () => { + const defaults = [ + kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != workbench.editor.notebook && editorLangId in julia.supportedLanguageIds`), true), + ]; + const overrides = [ + kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != 'workbench.editor.notebook' && editorLangId in 'julia.supportedLanguageIds'`), false), + ]; + const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]); + assert.deepStrictEqual(actual, []); + }); + test('contextIsEntirelyIncluded', () => { const toContextKeyExpression = (expr: ContextKeyExpression | string | null) => { if (typeof expr === 'string' || !expr) { From d037139d5d66fd3adc17c132d3b61c9e849cb8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 7 Oct 2022 05:34:06 -0700 Subject: [PATCH 408/599] updating tree.indent should be reflected live (#162937) fixes: #161747 --- src/vs/base/browser/ui/tree/abstractTree.ts | 65 +++++++++------------ 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 9b7a75ba596..c82ff404931 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -298,11 +298,6 @@ interface ITreeRendererOptions { readonly hideTwistiesOfChildlessElements?: boolean; } -interface IRenderData { - templateData: ITreeListTemplateData; - height: number; -} - interface Collection { readonly elements: T[]; readonly onDidChange: Event; @@ -332,7 +327,7 @@ class TreeRenderer implements IListRenderer readonly templateId: string; private renderedElements = new Map>(); - private renderedNodes = new Map, IRenderData>(); + private renderedNodes = new Map, ITreeListTemplateData>(); private indent: number = TreeRenderer.DefaultIndent; private hideTwistiesOfChildlessElements: boolean = false; @@ -354,13 +349,20 @@ class TreeRenderer implements IListRenderer this.updateOptions(options); Event.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables); - renderer.onDidChangeTwistieState?.(this.onDidChangeTwistieState, this, this.disposables); } updateOptions(options: ITreeRendererOptions = {}): void { if (typeof options.indent !== 'undefined') { - this.indent = clamp(options.indent, 0, 40); + const indent = clamp(options.indent, 0, 40); + + if (indent !== this.indent) { + this.indent = indent; + + for (const [node, templateData] of this.renderedNodes) { + this.renderTreeElement(node, templateData); + } + } } if (typeof options.renderIndentGuides !== 'undefined') { @@ -396,21 +398,9 @@ class TreeRenderer implements IListRenderer } renderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void { - if (typeof height === 'number') { - this.renderedNodes.set(node, { templateData, height }); - this.renderedElements.set(node.element, node); - } - - const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent; - templateData.twistie.style.paddingLeft = `${indent}px`; - templateData.indent.style.width = `${indent + this.indent - 16}px`; - - this.renderTwistie(node, templateData); - - if (typeof height === 'number') { - this.renderIndentGuides(node, templateData); - } - + this.renderedNodes.set(node, templateData); + this.renderedElements.set(node.element, node); + this.renderTreeElement(node, templateData); this.renderer.renderElement(node, index, templateData.templateData, height); } @@ -440,18 +430,27 @@ class TreeRenderer implements IListRenderer } private onDidChangeNodeTwistieState(node: ITreeNode): void { - const data = this.renderedNodes.get(node); + const templateData = this.renderedNodes.get(node); - if (!data) { + if (!templateData) { return; } - this.renderTwistie(node, data.templateData); this._onDidChangeActiveNodes(this.activeNodes.elements); - this.renderIndentGuides(node, data.templateData); + this.renderTreeElement(node, templateData); } - private renderTwistie(node: ITreeNode, templateData: ITreeListTemplateData) { + private renderTreeElement(node: ITreeNode, templateData: ITreeListTemplateData) { + const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent; + templateData.twistie.style.paddingLeft = `${indent}px`; + templateData.indent.style.width = `${indent + this.indent - 16}px`; + + if (node.collapsible) { + templateData.container.setAttribute('aria-expanded', String(!node.collapsed)); + } else { + templateData.container.removeAttribute('aria-expanded'); + } + templateData.twistie.classList.remove(...Codicon.treeItemExpanded.classNamesArray); let twistieRendered = false; @@ -471,14 +470,6 @@ class TreeRenderer implements IListRenderer templateData.twistie.classList.remove('collapsible', 'collapsed'); } - if (node.collapsible) { - templateData.container.setAttribute('aria-expanded', String(!node.collapsed)); - } else { - templateData.container.removeAttribute('aria-expanded'); - } - } - - private renderIndentGuides(target: ITreeNode, templateData: ITreeListTemplateData): void { clearNode(templateData.indent); templateData.indentGuidesDisposable.dispose(); @@ -489,8 +480,6 @@ class TreeRenderer implements IListRenderer const disposableStore = new DisposableStore(); const model = this.modelProvider(); - let node = target; - while (true) { const ref = model.getNodeLocation(node); const parentRef = model.getParentNodeLocation(ref); From 6d59844e1cb45cc9538032539753f36538cc4dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 7 Oct 2022 06:09:04 -0700 Subject: [PATCH 409/599] fix splitview scroll perf (#162941) Fixes: #162299 --- src/vs/base/browser/ui/splitview/splitview.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 159c58a2797..999d2cadfd8 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -556,8 +556,13 @@ export class SplitView extends Disposable { this.onDidScroll = this.scrollableElement.onScroll; this._register(this.onDidScroll(e => { - this.viewContainer.scrollTop = e.scrollTop; - this.viewContainer.scrollLeft = e.scrollLeft; + if (e.scrollTopChanged) { + this.viewContainer.scrollTop = e.scrollTop; + } + + if (e.scrollLeftChanged) { + this.viewContainer.scrollLeft = e.scrollLeft; + } })); append(this.el, this.scrollableElement.getDomNode()); From e97990e4ee4ea89a625f7656116f194c19768dac Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 7 Oct 2022 15:52:42 +0200 Subject: [PATCH 410/599] Treat removing keybindings with `when = true` as if they wouldn't have a when clause (#162945) Fixes #160604: Treat removing keybindings with `when = true` as if they wouldn't have a when clause --- .../keybinding/common/keybindingResolver.ts | 5 ++++- .../test/common/keybindingResolver.test.ts | 13 ++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index a76a8a8da14..636504d11fc 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -70,7 +70,10 @@ export class KeybindingResolver { if (keypressChordPart && defaultKb.keypressParts[1] !== keypressChordPart) { return false; } - if (when) { + + // `true` means always, as does `undefined` + // so we will treat `true` === `undefined` + if (when && when.type !== ContextKeyExprType.True) { if (!defaultKb.when) { return false; } diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index 8e15fbe71c0..137d23986ad 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -235,7 +235,7 @@ suite('KeybindingResolver', () => { ]); }); - test('issue #157751: Keyboard Shortcuts: Change When Expression might actually remove keybinding in Insiders', () => { + test('issue #157751: Auto-quoting of context keys prevents removal of keybindings via UI', () => { const defaults = [ kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != workbench.editor.notebook && editorLangId in julia.supportedLanguageIds`), true), ]; @@ -246,6 +246,17 @@ suite('KeybindingResolver', () => { assert.deepStrictEqual(actual, []); }); + test('issue #160604: Remove keybindings with when clause does not work', () => { + const defaults = [ + kbItem(KeyCode.KeyA, 'command1', null, undefined, true), + ]; + const overrides = [ + kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.true(), false), + ]; + const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]); + assert.deepStrictEqual(actual, []); + }); + test('contextIsEntirelyIncluded', () => { const toContextKeyExpression = (expr: ContextKeyExpression | string | null) => { if (typeof expr === 'string' || !expr) { From 4de06d175c4e1b4cf0773ef0a0409ef77851fd9d Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 7 Oct 2022 17:36:09 +0200 Subject: [PATCH 411/599] Move "H.264/AVC Video Standard" to cgmanifest.json and remove unused licenses from the store (#162955) * Move "H.264/AVC Video Standard" to cgmanifest.json and remove unused licenses from the store * Update cgmanifest.json Co-authored-by: Robo Co-authored-by: Robo --- cglicenses.json | 61 ------------------------------------------------- cgmanifest.json | 26 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 61 deletions(-) diff --git a/cglicenses.json b/cglicenses.json index 0ce05392959..eee2d66c8ef 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -32,20 +32,6 @@ "Copyright (c) tunnel-agent authors" ] }, - { - // Reason: Waiting for https://github.com/segmentio/noop-logger/issues/2 - "name": "noop-logger", - "fullLicenseText": [ - "This project is licensed under the MIT license.", - "Copyrights are respective of each contributor listed at the beginning of each definition file.", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - ] - }, { // Reason: The license at https://github.com/rbuckton/reflect-metadata/blob/master/LICENSE // does not include a clear Copyright statement (it's in https://github.com/rbuckton/reflect-metadata/blob/master/CopyrightNotice.txt). @@ -102,36 +88,6 @@ "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." ] }, - { - // Reason: Repository lacks license text. - // https://github.com/othiym23/emitter-listener/blob/master/package.json declares BSD-2-Clause. - // https://github.com/othiym23/emitter-listener/issues/3 - "name": "emitter-listener", - "fullLicenseText": [ - "BSD 2-Clause \"Simplified\" License", - "Copyright (c) 2018, Forrest L Norvell ", - "", - "Redistribution and use in source and binary forms, with or without", - "modification, are permitted provided that the following conditions are met:", - "", - "1. Redistributions of source code must retain the above copyright notice, this", - " list of conditions and the following disclaimer.", - "2. Redistributions in binary form must reproduce the above copyright notice,", - " this list of conditions and the following disclaimer in the documentation", - " and/or other materials provided with the distribution.", - "", - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND", - "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED", - "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE", - "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR", - "ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES", - "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;", - "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND", - "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", - "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." - ] - }, { // Reason: Repository lacks license text. // https://github.com/tjwebb/fnv-plus/blob/master/package.json declares MIT. @@ -174,23 +130,6 @@ "SOFTWARE" ] }, - { - // Reason: This product includes AVC coding technology. MPEG LA LLC requires this notice. - "name": "H.264/AVC Video Standard", - "fullLicenseText": [ - "This product is licensed under the AVC patent portfolio license for the personal", - "and non-commercial use of a consumer to (i) encode video in compliance with the AVC standard (\"AVC VIDEO\")", - "and/or (ii) decode AVC video that was encoded by a consumer", - "engaged in a personal and non-commercial activity and/or was obtained from a video provider", - "licensed to provide AVC video. No license is granted or shall be implied for any other use.", - "Additional information may be obtained from MPEG LA LLC. See http://www.MPEGLA.COM.", - "", - "For clarification purposes, this notice does not limit or inhibit the use of the product", - "for normal business uses that are personal to that business which do not include", - "(i) redistribution of the product to third parties, or", - "(ii) creation of content with AVC Standard compliant technologies for distribution to third parties." - ] - }, { // Reason: Missing license file "name": "@tokenizer/token", diff --git a/cgmanifest.json b/cgmanifest.json index df82bc993e4..726864e87f6 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -484,6 +484,32 @@ "That's all there is to it!" ] }, + { + "component": { + "type": "other", + "other": { + "name": "H.264/AVC Video Standard", + "downloadUrl": "https://chromium.googlesource.com/chromium/third_party/ffmpeg", + "version": "4.4.git" + } + }, + "licenseDetail": [ + "This product is licensed under the AVC patent portfolio license for the personal", + "and non-commercial use of a consumer to (i) encode video in compliance with the AVC standard (\"AVC VIDEO\")", + "and/or (ii) decode AVC video that was encoded by a consumer", + "engaged in a personal and non-commercial activity and/or was obtained from a video provider", + "licensed to provide AVC video. No license is granted or shall be implied for any other use.", + "Additional information may be obtained from MPEG LA LLC. See http://www.MPEGLA.COM.", + "", + "For clarification purposes, this notice does not limit or inhibit the use of the product", + "for normal business uses that are personal to that business which do not include", + "(i) redistribution of the product to third parties, or", + "(ii) creation of content with AVC Standard compliant technologies for distribution to third parties." + ], + "version": "H.264 (08/21)", + "isOnlyProductionDependency": true, + "license": "OTHER" + }, { "component": { "type": "git", From 9559bebbe02257d61b224664c14929c11b5c0736 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 7 Oct 2022 15:48:42 +0000 Subject: [PATCH 412/599] Debt - implement Download command in core (#162781) --- .../update/browser/update.contribution.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index 6cfdd311e50..bfaa857ef3b 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -18,8 +18,9 @@ import { isWindows } from 'vs/base/common/platform'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; -import { IProductService } from 'vs/platform/product/common/productService'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IProductService } from 'vs/platform/product/common/productService'; import { URI } from 'vs/base/common/uri'; const workbench = Registry.as(WorkbenchExtensions.Workbench); @@ -139,6 +140,37 @@ class RestartToUpdateAction extends Action2 { } } +class DownloadAction extends Action2 { + + static readonly ID = 'workbench.action.download'; + static readonly AVAILABLE = !!product.downloadUrl; + + constructor() { + super({ + id: DownloadAction.ID, + title: { + value: localize('openDownloadPage', "Download {0}", product.nameLong), + original: `Download ${product.downloadUrl}` + }, + precondition: IsWebContext, // Only show when running in a web browser + f1: true, + menu: [{ + id: MenuId.StatusBarRemoteIndicatorMenu, + }] + }); + } + + run(accessor: ServicesAccessor): void { + const productService = accessor.get(IProductService); + const openerService = accessor.get(IOpenerService); + + if (productService.downloadUrl) { + openerService.open(URI.parse(productService.downloadUrl)); + } + } +} + +registerAction2(DownloadAction); registerAction2(CheckForUpdateAction); registerAction2(DownloadUpdateAction); registerAction2(InstallUpdateAction); From 3dc9881b3f8af1a1b7383980ca533c5b87e92645 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 7 Oct 2022 08:52:24 -0700 Subject: [PATCH 413/599] skip processing if no filter (#162956) skip processing if nothing special --- .../tasks/browser/abstractTaskService.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index dff79ab21f0..45e556780fc 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2782,6 +2782,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer const identifier = this._getTaskIdentifier(arg); const type = arg && typeof arg !== 'string' && 'type' in arg ? arg.type : undefined; const task = arg && typeof arg !== 'string' && 'task' in arg ? arg.task : arg === 'string' ? arg : undefined; + if (!identifier && !task && !type) { + return this._doRunTaskCommand(); + } this._getGroupedTasks().then(async (grouped) => { const tasks = grouped.all(); const resolver = this._createResolver(grouped); @@ -2800,6 +2803,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } const exactMatchTask = tasks.find(t => task && (t.getDefinition(true)?.configurationProperties?.identifier === task || t.configurationProperties?.identifier === task || t._label === task)); + if (exactMatchTask) { + const id = exactMatchTask.configurationProperties?.identifier || exactMatchTask.getDefinition(true)?.configurationProperties?.identifier; + if (id) { + for (const uri of folderURIs) { + const task = await resolver.resolve(uri, id); + if (task) { + this.run(task, { attachProblemMatcher: true }, TaskRunSource.User).then(undefined, () => { }); + return; + } + } + } + } const atLeastOneMatch = tasks.some(t => { if (task) { if (t._label.includes(task)) { @@ -2812,22 +2827,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return false; }); - if (exactMatchTask) { - const id = exactMatchTask.configurationProperties?.identifier || exactMatchTask.getDefinition(true)?.configurationProperties?.identifier; - if (id) { - for (const uri of folderURIs) { - const task = await resolver.resolve(uri, id); - if (task) { - this.run(task, { attachProblemMatcher: true }, TaskRunSource.User).then(undefined, () => { }); - return; - } - } - } - } else if (atLeastOneMatch) { - return this._doRunTaskCommand(tasks, type, task); - } else { - return this._doRunTaskCommand(); - } + return atLeastOneMatch ? this._doRunTaskCommand(tasks, type, task) : this._doRunTaskCommand(); }); } From a2024df88586fcd9a30bd144c2fc689364656cfc Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 7 Oct 2022 18:24:32 +0200 Subject: [PATCH 414/599] update distro (#162959) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 176e0a7ccb0..1c6f5f301f3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.73.0", - "distro": "d4b1b117d224d627ec65bb0fd0b02fdee65303aa", + "distro": "76fdab745a3dcf7a4a13b0f7f549d680e6323972", "author": { "name": "Microsoft Corporation" }, From ca48f75e627cd5f7139d319ed4bb571d716570f2 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 7 Oct 2022 12:43:35 -0400 Subject: [PATCH 415/599] Update aria label to match explorer (#162951) --- src/vs/base/browser/ui/splitview/paneview.ts | 13 +++++++++++-- .../contrib/files/browser/views/explorerView.ts | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts index 659eb9bd8fd..c59e58ef51f 100644 --- a/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -60,7 +60,7 @@ export abstract class Pane extends Disposable implements IView { private _headerVisible = true; private _minimumBodySize: number; private _maximumBodySize: number; - private ariaHeaderLabel: string; + private _ariaHeaderLabel: string; private styles: IPaneStyles = {}; private animationTimer: number | undefined = undefined; @@ -70,6 +70,15 @@ export abstract class Pane extends Disposable implements IView { private readonly _onDidChangeExpansionState = this._register(new Emitter()); readonly onDidChangeExpansionState: Event = this._onDidChangeExpansionState.event; + get ariaHeaderLabel(): string { + return this._ariaHeaderLabel; + } + + set ariaHeaderLabel(newLabel: string) { + this._ariaHeaderLabel = newLabel; + this.header.setAttribute('aria-label', this.ariaHeaderLabel); + } + get draggableElement(): HTMLElement { return this.header; } @@ -127,7 +136,7 @@ export abstract class Pane extends Disposable implements IView { super(); this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded; this._orientation = typeof options.orientation === 'undefined' ? Orientation.VERTICAL : options.orientation; - this.ariaHeaderLabel = localize('viewSection', "{0} Section", options.title); + this._ariaHeaderLabel = localize('viewSection', "{0} Section", options.title); this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : this._orientation === Orientation.HORIZONTAL ? 200 : 120; this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY; diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 158ea94cbfb..a36bc07ee12 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -262,7 +262,8 @@ export class ExplorerView extends ViewPane implements IExplorerView { const title = workspace.folders.map(folder => folder.name).join(); titleElement.textContent = this.name; titleElement.title = title; - titleElement.setAttribute('aria-label', nls.localize('explorerSection', "Explorer Section: {0}", this.name)); + this.ariaHeaderLabel = nls.localize('explorerSection', "Explorer Section: {0}", this.name); + titleElement.setAttribute('aria-label', this.ariaHeaderLabel); }; this._register(this.contextService.onDidChangeWorkspaceName(setHeader)); From ba3536f6484db96b850801bbe93ba02b274a5f25 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 09:50:20 -0700 Subject: [PATCH 416/599] Fix terminal editor background padding color Fixes #162769 --- .../contrib/terminal/browser/terminalEditor.ts | 11 ++++++++++- .../contrib/terminal/browser/terminalView.ts | 10 +++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index b71eabb4d8b..e429e11b712 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -15,7 +15,7 @@ import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { ITerminalEditorService, ITerminalService, terminalEditorId } from 'vs/workbench/contrib/terminal/browser/terminal'; @@ -29,6 +29,8 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { openContextMenu } from 'vs/workbench/contrib/terminal/browser/terminalContextMenu'; import { ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; export class TerminalEditor extends EditorPane { @@ -220,3 +222,10 @@ export class TerminalEditor extends EditorPane { return defaultProfileName!; } } + +registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { + const backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(EDITOR_PANE_BACKGROUND); + if (backgroundColor) { + collector.addRule(`.monaco-workbench .editor-instance .terminal-wrapper { background-color: ${backgroundColor.toString()}; }`); + } +}); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 966f327339c..89e3251e380 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -301,11 +301,15 @@ export class TerminalViewPane extends ViewPane { registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { const panelBackgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(PANEL_BACKGROUND); - collector.addRule(`.monaco-workbench .part.panel .pane-body.integrated-terminal .terminal-outer-container { background-color: ${panelBackgroundColor ? panelBackgroundColor.toString() : ''}; }`); + if (panelBackgroundColor) { + collector.addRule(`.monaco-workbench .part.panel .pane-body.integrated-terminal .terminal-outer-container { background-color: ${panelBackgroundColor.toString()}; }`); + } const sidebarBackgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(SIDE_BAR_BACKGROUND); - collector.addRule(`.monaco-workbench .part.sidebar .pane-body.integrated-terminal .terminal-outer-container { background-color: ${sidebarBackgroundColor ? sidebarBackgroundColor.toString() : ''}; }`); - collector.addRule(`.monaco-workbench .part.auxiliarybar .pane-body.integrated-terminal .terminal-outer-container { background-color: ${sidebarBackgroundColor ? sidebarBackgroundColor.toString() : ''}; }`); + if (sidebarBackgroundColor) { + collector.addRule(`.monaco-workbench .part.sidebar .pane-body.integrated-terminal .terminal-outer-container { background-color: ${sidebarBackgroundColor.toString()}; }`); + collector.addRule(`.monaco-workbench .part.auxiliarybar .pane-body.integrated-terminal .terminal-outer-container { background-color: ${sidebarBackgroundColor.toString()}; }`); + } const borderColor = theme.getColor(TERMINAL_BORDER_COLOR); if (borderColor) { From e6dde6aad07dc41fed832bd747fdff780dda82de Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:06:43 -0700 Subject: [PATCH 417/599] Fix active terminal tab when moving a group to the bottom of the tabs list Fixes #159907 --- src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 2b1b063de2d..6baeb8f6596 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -677,6 +677,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop { if (!targetInstance) { this._terminalGroupService.moveGroupToEnd(sourceInstances[0]); + this._terminalService.setActiveInstance(sourceInstances[0]); return; } From 6d85cd954fc18e0f930ed4f11f4aeaa2f6f450ce Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Oct 2022 10:25:17 -0700 Subject: [PATCH 418/599] Properly implement disposeCompressedElements (#162972) Fix #160382 --- src/vs/workbench/contrib/debug/browser/callStackView.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 74631ace0ca..fb4c19d14da 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -621,6 +621,10 @@ class SessionsRenderer implements ICompressibleTreeRenderer, _: number, templateData: ISessionTemplateData): void { templateData.elementDisposable.clear(); } + + disposeCompressedElements(node: ITreeNode, FuzzyScore>, index: number, templateData: ISessionTemplateData, height: number | undefined): void { + templateData.elementDisposable.clear(); + } } function getThreadContextOverlay(thread: IThread): [string, any][] { @@ -691,6 +695,10 @@ class ThreadsRenderer implements ICompressibleTreeRenderer, FuzzyScore>, index: number, templateData: IThreadTemplateData, height: number | undefined): void { + templateData.elementDisposable.clear(); + } + disposeTemplate(templateData: IThreadTemplateData): void { templateData.templateDisposable.dispose(); } From 30a8ab36b7a3a9e8273200a61653d589400813b4 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 7 Oct 2022 10:36:07 -0700 Subject: [PATCH 419/599] Debounce event handler on notebook editor open. (#162975) --- .../contrib/outline/notebookOutline.ts | 14 +++++++--- .../viewParts/notebookEditorToolbar.ts | 26 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index 1103b138b84..24b51153c5b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -8,7 +8,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { Emitter, Event } from 'vs/base/common/event'; import { combinedDisposable, IDisposable, Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { CellRevealType, IActiveNotebookEditor, ICellViewModel, INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellRevealType, IActiveNotebookEditor, ICellViewModel, INotebookEditorOptions, INotebookViewCellsUpdateEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IOutline, IOutlineComparator, IOutlineCreator, IOutlineListConfig, IOutlineService, IQuickPickDataSource, IQuickPickOutlineElement, OutlineChangeEvent, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; @@ -320,8 +320,16 @@ export class NotebookCellOutline extends Disposable implements IOutline this._recomputeActive()), - notebookEditor.onDidChangeViewCells(() => this._recomputeState()) + Event.debounce( + notebookEditor.onDidChangeSelection, + (last, _current) => last, + 200 + )(this._recomputeActive, this), + Event.debounce( + notebookEditor.onDidChangeViewCells, + (last, _current) => last ?? _current, + 200 + )(this._recomputeState, this) ); } }; diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts index f48c7cb938b..18abfa18c17 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts @@ -306,16 +306,11 @@ export class NotebookEditorToolbar extends Disposable { this._secondaryActions = []; this._buildBody(); - this._register(this.editorService.onDidActiveEditorChange(() => { - if (this.editorService.activeEditorPane?.getId() === NOTEBOOK_EDITOR_ID) { - const notebookEditor = this.editorService.activeEditorPane.getControl() as INotebookEditorDelegate; - if (notebookEditor === this.notebookEditor) { - // this is the active editor - this._showNotebookActionsinEditorToolbar(); - return; - } - } - })); + this._register(Event.debounce( + this.editorService.onDidActiveEditorChange, + (last, _current) => last, + 200 + )(this._updatePerEditorChange, this)); this._registerNotebookActionsToolbar(); } @@ -338,6 +333,17 @@ export class NotebookEditorToolbar extends Disposable { DOM.append(this.domNode, this._notebookTopRightToolbarContainer); } + private _updatePerEditorChange() { + if (this.editorService.activeEditorPane?.getId() === NOTEBOOK_EDITOR_ID) { + const notebookEditor = this.editorService.activeEditorPane.getControl() as INotebookEditorDelegate; + if (notebookEditor === this.notebookEditor) { + // this is the active editor + this._showNotebookActionsinEditorToolbar(); + return; + } + } + } + private _registerNotebookActionsToolbar() { this._notebookGlobalActionsMenu = this._register(this.menuService.createMenu(this.notebookEditor.creationOptions.menuIds.notebookToolbar, this.contextKeyService)); this._register(this._notebookGlobalActionsMenu); From a7153c246c7e12d955e2a6ba83d233ddcdeaf340 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 7 Oct 2022 11:49:39 -0600 Subject: [PATCH 420/599] Fix many instances of not using ILocalizedString (#162978) --- src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts | 7 +++---- .../gotoSymbol/browser/link/goToDefinitionAtPosition.ts | 2 +- .../contrib/inlayHints/browser/inlayHintsLocations.ts | 2 +- src/vs/platform/actions/common/actions.ts | 6 ++++++ .../browser/parts/activitybar/activitybarActions.ts | 2 +- src/vs/workbench/contrib/debug/browser/debugCommands.ts | 9 +++++---- .../contrib/extensions/browser/extensionsViewlet.ts | 7 +++++-- .../interactive/browser/interactive.contribution.ts | 3 ++- .../contrib/mergeEditor/browser/commands/devCommands.ts | 9 ++++++--- .../contrib/mergeEditor/electron-sandbox/devCommands.ts | 9 ++++++--- .../contrib/terminal/browser/terminalActions.ts | 2 +- .../contrib/userDataProfile/browser/userDataProfile.ts | 2 +- .../userDataProfile/browser/userDataProfileActions.ts | 4 ++-- .../browser/gettingStarted.contribution.ts | 2 +- .../contrib/welcomeOverlay/browser/welcomeOverlay.ts | 4 ++-- .../contrib/welcomeViews/common/newFile.contribution.ts | 3 ++- .../browser/editor/editorWalkThrough.ts | 2 +- .../contrib/workspace/browser/workspace.contribution.ts | 5 +++-- .../services/userDataProfile/common/userDataProfile.ts | 2 +- .../common/userDataProfileImportExportService.ts | 8 ++++---- 20 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts index c3f073892da..6360be59725 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts @@ -29,7 +29,7 @@ import { ISymbolNavigationService } from 'vs/editor/contrib/gotoSymbol/browser/s import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; import { PeekContext } from 'vs/editor/contrib/peekView/browser/peekView'; import * as nls from 'vs/nls'; -import { IAction2Options, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IAction2F1RequiredOptions, IAction2Options, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { TextEditorSelectionRevealType, TextEditorSelectionSource } from 'vs/platform/editor/common/editor'; @@ -42,7 +42,6 @@ import { IWordAtPosition } from 'vs/editor/common/core/wordHelper'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { Iterable } from 'vs/base/common/iterator'; - MenuRegistry.appendMenuItem(MenuId.EditorContext, { submenu: MenuId.EditorContextPeek, title: nls.localize('peek.submenu', "Peek"), @@ -83,7 +82,7 @@ export abstract class SymbolNavigationAction extends EditorAction2 { return SymbolNavigationAction._allSymbolNavigationCommands.values(); } - private static _patchConfig(opts: IAction2Options): IAction2Options { + private static _patchConfig(opts: IAction2Options & IAction2F1RequiredOptions): IAction2Options { const result = { ...opts, f1: true }; // patch context menu when clause if (result.menu) { @@ -99,7 +98,7 @@ export abstract class SymbolNavigationAction extends EditorAction2 { readonly configuration: SymbolNavigationActionConfig; - constructor(configuration: SymbolNavigationActionConfig, opts: IAction2Options) { + constructor(configuration: SymbolNavigationActionConfig, opts: IAction2Options & IAction2F1RequiredOptions) { super(SymbolNavigationAction._patchConfig(opts)); this.configuration = configuration; SymbolNavigationAction._allSymbolNavigationCommands.set(opts.id, this); diff --git a/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts b/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts index d775f018888..87492186e71 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts @@ -297,7 +297,7 @@ export class GotoDefinitionAtPositionEditorContribution implements IEditorContri this.editor.setPosition(position); return this.editor.invokeWithinContext((accessor) => { const canPeek = !openToSide && this.editor.getOption(EditorOption.definitionLinkOpensInPeek) && !this.isInPeekEditor(accessor); - const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { title: '', id: '', precondition: undefined }); + const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { title: { value: '', original: '' }, id: '', precondition: undefined }); return action.run(accessor, this.editor); }); } diff --git a/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts b/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts index 77706619c1c..b2df34e97ec 100644 --- a/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts +++ b/src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts @@ -104,7 +104,7 @@ export async function goToDefinitionWithLocation(accessor: ServicesAccessor, eve const isInPeek = PeekContext.inPeekEditor.getValue(contextKeyService); const canPeek = !openToSide && editor.getOption(EditorOption.definitionLinkOpensInPeek) && !isInPeek; - const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { title: '', id: '', precondition: undefined }); + const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { title: { value: '', original: '' }, id: '', precondition: undefined }); return action.run(accessor, editor, { model: ref.object.textEditorModel, position: Range.getStartPosition(location.range) }, Range.lift(location.range)); }); diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 87c38c65e32..1d64a7383ee 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -9,6 +9,7 @@ import { Event, MicrotaskEmitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; import { ICommandAction, ICommandActionTitle, Icon, ILocalizedString } from 'vs/platform/action/common/action'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { CommandsRegistry, ICommandHandlerDescription, ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { SyncDescriptor, SyncDescriptor0 } from 'vs/platform/instantiation/common/descriptors'; @@ -568,6 +569,11 @@ export interface IAction2Options extends ICommandAction { _isFakeAction?: true; } +export interface IAction2F1RequiredOptions { + title: ICommandActionTitle; + category?: keyof typeof Categories | ILocalizedString; +} + export abstract class Action2 { constructor(readonly desc: Readonly) { } abstract run(accessor: ServicesAccessor, ...args: any[]): void; diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index d4db825ca72..ce2a3e8fe51 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -372,7 +372,7 @@ export class ProfilesActivityActionViewItem extends MenuActivityActionViewItem { const actions = await super.resolveContextMenuActions(disposables); actions.unshift(...[ - toAction({ id: 'hideprofiles', label: localize('hideprofiles', "Hide {0}", PROFILES_CATEGORY), run: () => this.storageService.store(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, false, StorageScope.PROFILE, StorageTarget.USER) }), + toAction({ id: 'hideprofiles', label: localize('hideprofiles', "Hide {0}", PROFILES_CATEGORY.value), run: () => this.storageService.store(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, false, StorageScope.PROFILE, StorageTarget.USER) }), new Separator() ]); diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 583c82929b7..80308ec506a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -34,6 +34,7 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b import { showLoadedScriptMenu } from 'vs/workbench/contrib/debug/common/loadedScriptsPicker'; import { showDebugSessionMenu } from 'vs/workbench/contrib/debug/browser/debugSessionPicker'; import { TEXT_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; +import { ILocalizedString } from 'vs/platform/action/common/action'; export const ADD_CONFIGURATION_ID = 'debug.addConfiguration'; export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint'; @@ -72,7 +73,7 @@ export const CALLSTACK_BOTTOM_ID = 'workbench.action.debug.callStackBottom'; export const CALLSTACK_UP_ID = 'workbench.action.debug.callStackUp'; export const CALLSTACK_DOWN_ID = 'workbench.action.debug.callStackDown'; -export const DEBUG_COMMAND_CATEGORY = 'Debug'; +export const DEBUG_COMMAND_CATEGORY: ILocalizedString = { original: 'Debug', value: nls.localize('debug', 'Debug') }; export const RESTART_LABEL = { value: nls.localize('restartDebug', "Restart"), original: 'Restart' }; export const STEP_OVER_LABEL = { value: nls.localize('stepOverDebug', "Step Over"), original: 'Step Over' }; export const STEP_INTO_LABEL = { value: nls.localize('stepIntoDebug', "Step Into"), original: 'Step Into' }; @@ -407,7 +408,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorContext, { command: { id: JUMP_TO_CURSOR_ID, title: nls.localize('jumpToCursor', "Jump to Cursor"), - category: { value: nls.localize('debug', "Debug"), original: 'Debug' } + category: DEBUG_COMMAND_CATEGORY }, when: ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED, EditorContextKeys.editorTextFocus), group: 'debug', @@ -920,7 +921,7 @@ registerAction2(class AddConfigurationAction extends Action2 { constructor() { super({ id: ADD_CONFIGURATION_ID, - title: nls.localize('addConfiguration', "Add Configuration..."), + title: { value: nls.localize('addConfiguration', "Add Configuration..."), original: 'Add Configuration...' }, category: DEBUG_COMMAND_CATEGORY, f1: true, menu: { @@ -978,7 +979,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorContext, { command: { id: TOGGLE_INLINE_BREAKPOINT_ID, title: nls.localize('addInlineBreakpoint', "Add Inline Breakpoint"), - category: { value: nls.localize('debug', "Debug"), original: 'Debug' } + category: DEBUG_COMMAND_CATEGORY }, when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, PanelFocusContext.toNegated(), EditorContextKeys.editorTextFocus), group: 'debug', diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 20ca6f57e8f..cf017e97f5e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -60,6 +60,7 @@ import { coalesce } from 'vs/base/common/arrays'; import { extractEditorsAndFilesDropData } from 'vs/platform/dnd/browser/dnd'; import { extname } from 'vs/base/common/resources'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ILocalizedString } from 'vs/platform/action/common/action'; export const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); export const ExtensionsSortByContext = new RawContextKey('extensionsSortByValue', ''); @@ -79,6 +80,8 @@ const SearchDeprecatedExtensionsContext = new RawContextKey('searchDepr export const RecommendedExtensionsContext = new RawContextKey('recommendedExtensions', false); const SortByUpdateDateContext = new RawContextKey('sortByUpdateDate', false); +const REMOTE_CATEGORY: ILocalizedString = { value: localize({ key: 'remote', comment: ['Remote as in remote machine'] }, "Remote"), original: 'Remote' }; + export class ExtensionsViewletViewsContribution implements IWorkbenchContribution { private readonly container: ViewContainer; @@ -170,7 +173,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio original: `Install Local Extensions in '${server.label}'...`, }; }, - category: localize({ key: 'remote', comment: ['Remote as in remote machine'] }, "Remote"), + category: REMOTE_CATEGORY, icon: installLocalInRemoteIcon, f1: true, menu: { @@ -193,7 +196,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio super({ id: 'workbench.extensions.actions.installLocalExtensionsInRemote', title: { value: localize('install remote in local', "Install Remote Extensions Locally..."), original: 'Install Remote Extensions Locally...' }, - category: localize({ key: 'remote', comment: ['Remote as in remote machine'] }, "Remote"), + category: REMOTE_CATEGORY, f1: true }); } diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 4c686a06160..10682d94745 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -24,6 +24,7 @@ import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/s import { peekViewBorder /*, peekViewEditorBackground, peekViewResultsBackground */ } from 'vs/editor/contrib/peekView/browser/peekView'; import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest'; import { localize } from 'vs/nls'; +import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; @@ -64,7 +65,7 @@ import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/s import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -const interactiveWindowCategory = localize('interactiveWindow', 'Interactive Window'); +const interactiveWindowCategory: ILocalizedString = { value: localize('interactiveWindow', 'Interactive Window'), original: 'Interactive Window' }; Registry.as(EditorExtensions.EditorPane).registerEditorPane( EditorPaneDescriptor.create( diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts index 1c28237d1bf..0f2b6b56183 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts @@ -8,6 +8,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { URI } from 'vs/base/common/uri'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { localize } from 'vs/nls'; +import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2 } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -20,11 +21,13 @@ import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/merge import { ctxIsMergeEditor, MergeEditorContents } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +const MERGE_EDITOR_CATEGORY: ILocalizedString = { value: localize('mergeEditor', "Merge Editor (Dev)"), original: 'Merge Editor (Dev)' }; + export class MergeEditorCopyContentsToJSON extends Action2 { constructor() { super({ id: 'merge.dev.copyContentsJson', - category: 'Merge Editor (Dev)', + category: MERGE_EDITOR_CATEGORY, title: { value: localize( 'merge.dev.copyState', @@ -76,7 +79,7 @@ export class MergeEditorSaveContentsToFolder extends Action2 { constructor() { super({ id: 'merge.dev.saveContentsToFolder', - category: 'Merge Editor (Dev)', + category: MERGE_EDITOR_CATEGORY, title: { value: localize( 'merge.dev.saveContentsToFolder', @@ -145,7 +148,7 @@ export class MergeEditorLoadContentsFromFolder extends Action2 { constructor() { super({ id: 'merge.dev.loadContentsFromFolder', - category: 'Merge Editor (Dev)', + category: MERGE_EDITOR_CATEGORY, title: { value: localize( 'merge.dev.loadContentsFromFolder', diff --git a/src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts index 0f8549b5647..63049439462 100644 --- a/src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts +++ b/src/vs/workbench/contrib/mergeEditor/electron-sandbox/devCommands.ts @@ -9,6 +9,7 @@ import { randomPath } from 'vs/base/common/extpath'; import { URI } from 'vs/base/common/uri'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { localize } from 'vs/nls'; +import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, IAction2Options } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -21,11 +22,13 @@ import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/v import { MergeEditorContents } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +const MERGE_EDITOR_CATEGORY: ILocalizedString = { value: localize('mergeEditor', "Merge Editor (Dev)"), original: 'Merge Editor (Dev)' }; + export class MergeEditorOpenContentsFromJSON extends Action2 { constructor() { super({ id: 'merge.dev.openContentsJson', - category: 'Merge Editor (Dev)', + category: MERGE_EDITOR_CATEGORY, title: { value: localize( 'merge.dev.openState', @@ -132,13 +135,13 @@ export class OpenSelectionInTemporaryMergeEditor extends MergeEditorAction { constructor() { super({ id: 'merge.dev.openSelectionInTemporaryMergeEditor', - category: 'Merge Editor (Dev)', + category: MERGE_EDITOR_CATEGORY, title: { value: localize( 'merge.dev.openSelectionInTemporaryMergeEditor', 'Open Selection In Temporary Merge Editor' ), - original: 'Open Selection In Temporary', + original: 'Open Selection In Temporary Merge Editor', }, icon: Codicon.layoutCentered, f1: true, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index c6c85fe83bf..65a13731388 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -2232,7 +2232,7 @@ export function registerTerminalActions() { id: TerminalCommandId.WriteDataToTerminal, title: { value: localize('workbench.action.terminal.writeDataToTerminal', "Write Data to Terminal"), original: 'Write Data to Terminal' }, f1: true, - category: Categories.Developer.value + category: Categories.Developer }); } async run(accessor: ServicesAccessor) { diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 848594527db..1f8f5687d18 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -289,7 +289,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements const profile = await userDataProfileImportExportService.exportProfile({ skipComments: true }); await textFileService.create([{ resource: profileLocation, value: JSON.stringify(profile), options: { overwrite: true } }]); - notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY)); + notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY.value)); } })); disposables.add(MenuRegistry.appendMenuItem(MenuId.MenubarShare, { diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts index df6317f8117..a8bfcdadac1 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfileActions.ts @@ -149,7 +149,7 @@ registerAction2(class CreateProfileAction extends Action2 { }, { id: CreateTransientProfileAction.ID, label: CreateTransientProfileAction.TITLE.value, - }], { hideInput: true, canPickMany: false, title: localize('create settings profile', "{0}: Create...", PROFILES_CATEGORY) }); + }], { hideInput: true, canPickMany: false, title: localize('create settings profile', "{0}: Create...", PROFILES_CATEGORY.value) }); if (pick?.id) { return commandService.executeCommand(pick.id); } @@ -342,7 +342,7 @@ registerAction2(class ManageSettingsProfileAction extends Action2 { label: `${action.label}${action.checked ? ` $(${Codicon.check.id})` : ''}`, }; }); - const pick = await quickInputService.pick(picks, { canPickMany: false, title: PROFILES_CATEGORY }); + const pick = await quickInputService.pick(picks, { canPickMany: false, title: PROFILES_CATEGORY.value }); if (pick?.id) { await commandService.executeCommand(pick.id); } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts index 7b1282eed4e..2c5c3b04784 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.contribution.ts @@ -124,7 +124,7 @@ Registry.as(EditorExtensions.EditorPane).registerEditorPane ] ); -const category = localize('getStarted', "Get Started"); +const category = { value: localize('getStarted', "Get Started"), original: 'Get Started' }; registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts index 7bdc7f207c4..5e7a51a2ba0 100644 --- a/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcomeOverlay/browser/welcomeOverlay.ts @@ -111,7 +111,7 @@ let welcomeOverlay: WelcomeOverlay; export class WelcomeOverlayAction extends Action2 { public static readonly ID = 'workbench.action.showInterfaceOverview'; - public static readonly LABEL = localize('welcomeOverlay', "User Interface Overview"); + public static readonly LABEL = { value: localize('welcomeOverlay', "User Interface Overview"), original: 'User Interface Overview' }; constructor( ) { @@ -136,7 +136,7 @@ export class WelcomeOverlayAction extends Action2 { export class HideWelcomeOverlayAction extends Action2 { public static readonly ID = 'workbench.action.hideInterfaceOverview'; - public static readonly LABEL = localize('hideWelcomeOverlay', "Hide Interface Overview"); + public static readonly LABEL = { value: localize('hideWelcomeOverlay', "Hide Interface Overview"), original: 'Hide Interface Overview' }; constructor() { super({ diff --git a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts index 55ef4113b60..562f3412963 100644 --- a/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts +++ b/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.ts @@ -7,6 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { assertIsDefined } from 'vs/base/common/types'; import { localize } from 'vs/nls'; +import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, IMenuService, MenuId, registerAction2, IMenu, MenuRegistry, MenuItemAction } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -19,7 +20,7 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } fr import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; const builtInSource = localize('Built-In', "Built-In"); -const category = localize('Create', "Create"); +const category: ILocalizedString = { value: localize('Create', "Create"), original: 'Create' }; registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts index 8eaf3e7322b..906d5a4d76c 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/editor/editorWalkThrough.ts @@ -29,7 +29,7 @@ const inputOptions: WalkThroughInputOptions = { export class EditorWalkThroughAction extends Action2 { public static readonly ID = 'workbench.action.showInteractivePlayground'; - public static readonly LABEL = localize('editorWalkThrough', "Interactive Editor Playground"); + public static readonly LABEL = { value: localize('editorWalkThrough', "Interactive Editor Playground"), original: 'Interactive Editor Playground' }; constructor() { super({ diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 4dad7461871..cccb98cbefb 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -622,6 +622,7 @@ Registry.as(EditorExtensions.EditorPane).registerEditorPane // Configure Workspace Trust const CONFIGURE_TRUST_COMMAND_ID = 'workbench.trust.configure'; +const WORKSPACES_CATEGORY = { value: localize('workspacesCategory', "Workspaces"), original: 'Workspaces' }; registerAction2(class extends Action2 { constructor() { @@ -629,7 +630,7 @@ registerAction2(class extends Action2 { id: CONFIGURE_TRUST_COMMAND_ID, title: { original: 'Configure Workspace Trust', value: localize('configureWorkspaceTrust', "Configure Workspace Trust") }, precondition: ContextKeyExpr.and(WorkspaceTrustContext.IsEnabled, ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true)), - category: localize('workspacesCategory', "Workspaces"), + category: WORKSPACES_CATEGORY, f1: true }); } @@ -647,7 +648,7 @@ registerAction2(class extends Action2 { id: MANAGE_TRUST_COMMAND_ID, title: { original: 'Manage Workspace Trust', value: localize('manageWorkspaceTrust', "Manage Workspace Trust") }, precondition: ContextKeyExpr.and(WorkspaceTrustContext.IsEnabled, ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true)), - category: localize('workspacesCategory', "Workspaces"), + category: WORKSPACES_CATEGORY, f1: true, menu: { id: MenuId.GlobalActivity, diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts index 5aba82d0c06..f7efa31fe40 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts @@ -75,7 +75,7 @@ export interface IResourceProfile { export const ManageProfilesSubMenu = new MenuId('SettingsProfiles'); export const MANAGE_PROFILES_ACTION_ID = 'workbench.profiles.actions.manage'; export const PROFILES_TTILE = { value: localize('settings profiles', "Settings Profiles"), original: 'Settings Profiles' }; -export const PROFILES_CATEGORY = PROFILES_TTILE.value; +export const PROFILES_CATEGORY = { ...PROFILES_TTILE }; export const PROFILE_EXTENSION = 'code-profile'; export const PROFILE_FILTER = [{ name: localize('profile', "Settings Profile"), extensions: [PROFILE_EXTENSION] }]; export const PROFILES_ENABLEMENT_CONTEXT = ContextKeyExpr.or(ProductQualityContext.notEqualsTo('stable'), ContextKeyDefinedExpr.create(`config.${PROFILES_ENABLEMENT_CONFIG}`)); diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts index b9b95d027fd..cd2aa2d8c23 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts @@ -56,7 +56,7 @@ export class UserDataProfileImportExportService implements IUserDataProfileImpor await this.progressService.withProgress({ location: ProgressLocation.Notification, - title: localize('profiles.importing', "{0}: Importing...", PROFILES_CATEGORY), + title: localize('profiles.importing', "{0}: Importing...", PROFILES_CATEGORY.value), }, async progress => { await this.userDataProfileManagementService.createAndEnterProfile(name); if (profileTemplate.settings) { @@ -70,13 +70,13 @@ export class UserDataProfileImportExportService implements IUserDataProfileImpor } }); - this.notificationService.info(localize('imported profile', "{0}: Imported successfully.", PROFILES_CATEGORY)); + this.notificationService.info(localize('imported profile', "{0}: Imported successfully.", PROFILES_CATEGORY.value)); } async setProfile(profile: IUserDataProfileTemplate): Promise { await this.progressService.withProgress({ location: ProgressLocation.Notification, - title: localize('profiles.applying', "{0}: Applying...", PROFILES_CATEGORY), + title: localize('profiles.applying', "{0}: Applying...", PROFILES_CATEGORY.value), }, async progress => { if (profile.settings) { await this.settingsProfile.applyProfile(profile.settings); @@ -88,7 +88,7 @@ export class UserDataProfileImportExportService implements IUserDataProfileImpor await this.extensionsProfile.applyProfile(profile.extensions); } }); - this.notificationService.info(localize('applied profile', "{0}: Applied successfully.", PROFILES_CATEGORY)); + this.notificationService.info(localize('applied profile', "{0}: Applied successfully.", PROFILES_CATEGORY.value)); } } From becaa24c93c9e93b70804b6048fc3963d7832a65 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:58:10 -0700 Subject: [PATCH 421/599] Update xterm.js --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 8 ++++---- remote/web/yarn.lock | 32 ++++++++++++++++---------------- remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 1c6f5f301f3..9a35de0240d 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.25", - "xterm-addon-canvas": "0.3.0-beta.8", - "xterm-addon-search": "0.11.0-beta.3", + "xterm": "5.1.0-beta.27", + "xterm-addon-canvas": "0.3.0-beta.10", + "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.16", - "xterm-headless": "5.1.0-beta.25", + "xterm-addon-webgl": "0.14.0-beta.18", + "xterm-headless": "5.1.0-beta.27", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index c241260d8d9..eb4549d8bc9 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.25", - "xterm-addon-canvas": "0.3.0-beta.8", - "xterm-addon-search": "0.11.0-beta.3", + "xterm": "5.1.0-beta.27", + "xterm-addon-canvas": "0.3.0-beta.10", + "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.16", - "xterm-headless": "5.1.0-beta.25", + "xterm-addon-webgl": "0.14.0-beta.18", + "xterm-headless": "5.1.0-beta.27", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 953d7a08983..7a0b52b469b 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,10 +11,10 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.25", - "xterm-addon-canvas": "0.3.0-beta.8", - "xterm-addon-search": "0.11.0-beta.3", + "xterm": "5.1.0-beta.27", + "xterm-addon-canvas": "0.3.0-beta.10", + "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.16" + "xterm-addon-webgl": "0.14.0-beta.18" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 438b1bcdb37..dd89770243b 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,27 +68,27 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-canvas@0.3.0-beta.8: - version "0.3.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" - integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== +xterm-addon-canvas@0.3.0-beta.10: + version "0.3.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" + integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== -xterm-addon-search@0.11.0-beta.3: - version "0.11.0-beta.3" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" - integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== +xterm-addon-search@0.11.0-beta.4: + version "0.11.0-beta.4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.4.tgz#35c01a98b092adbbd1828b0d2eea28485a9a1538" + integrity sha512-rtDBg9CWDw6c0tMeBmaKan2UWwSY88UkfkLv+g50EopDyx6J337nxgjKGioUjF0pZ1VwFOaP1+rFRk8XwLiUHA== xterm-addon-unicode11@0.5.0-beta.1: version "0.5.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.16: - version "0.14.0-beta.16" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" - integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== +xterm-addon-webgl@0.14.0-beta.18: + version "0.14.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" + integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== -xterm@5.1.0-beta.25: - version "5.1.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" - integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== +xterm@5.1.0-beta.27: + version "5.1.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" + integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== diff --git a/remote/yarn.lock b/remote/yarn.lock index 53709b74a0a..951e77cbc7e 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -788,15 +788,15 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.3.0-beta.8: - version "0.3.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" - integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== +xterm-addon-canvas@0.3.0-beta.10: + version "0.3.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" + integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== -xterm-addon-search@0.11.0-beta.3: - version "0.11.0-beta.3" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" - integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== +xterm-addon-search@0.11.0-beta.4: + version "0.11.0-beta.4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.4.tgz#35c01a98b092adbbd1828b0d2eea28485a9a1538" + integrity sha512-rtDBg9CWDw6c0tMeBmaKan2UWwSY88UkfkLv+g50EopDyx6J337nxgjKGioUjF0pZ1VwFOaP1+rFRk8XwLiUHA== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -808,20 +808,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.16: - version "0.14.0-beta.16" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" - integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== +xterm-addon-webgl@0.14.0-beta.18: + version "0.14.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" + integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== -xterm-headless@5.1.0-beta.25: - version "5.1.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.25.tgz#9c9e117caa7c5fb56e4518e6ca14549c3d64d974" - integrity sha512-NsEsf/tGdIuoi7Ey/jIPFbRVWgNFhlmw9PKibW8GsudfAZkbbgggLe/gCHFlOYXpa+vYNGr8cDmDqGT86mFvvw== +xterm-headless@5.1.0-beta.27: + version "5.1.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.27.tgz#59b9033e1f3e7e09bc9dc7d05dd1d82be7a31659" + integrity sha512-ow/0UBeMNGZMxhK+0bZy3pBK+O5so3d2Dbx2z1umjv5EWL2+Ix/Mz51OtQWd6YdSVrs9z+I1QeAd3aYWnnpG8g== -xterm@5.1.0-beta.25: - version "5.1.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" - integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== +xterm@5.1.0-beta.27: + version "5.1.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" + integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index eef5ad9c708..3f9bb0f03ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11582,15 +11582,15 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-canvas@0.3.0-beta.8: - version "0.3.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.8.tgz#1848d54091e864cf6aa7310e5d883203fe09247a" - integrity sha512-NGaPADoh4/out6pCgfwh6lVDpJQtQXMRBXpvHB2rMcJqAZ0KHJalQXbjBmwSL9/WiHvYLhmqvGJ3+Pd9aE8hoA== +xterm-addon-canvas@0.3.0-beta.10: + version "0.3.0-beta.10" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" + integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== -xterm-addon-search@0.11.0-beta.3: - version "0.11.0-beta.3" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.3.tgz#ee466425b83c74b69cbf71903c3781895beea5ab" - integrity sha512-Fc9VuQn31JNnD2gZUEFMUYLpz6kPw5LMLp7YTB5iDv43JklEJL/14v6C4dFZkAo95MPi7yr3CUefYXz0dt+O7Q== +xterm-addon-search@0.11.0-beta.4: + version "0.11.0-beta.4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.11.0-beta.4.tgz#35c01a98b092adbbd1828b0d2eea28485a9a1538" + integrity sha512-rtDBg9CWDw6c0tMeBmaKan2UWwSY88UkfkLv+g50EopDyx6J337nxgjKGioUjF0pZ1VwFOaP1+rFRk8XwLiUHA== xterm-addon-serialize@0.9.0-beta.2: version "0.9.0-beta.2" @@ -11602,20 +11602,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.16: - version "0.14.0-beta.16" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.16.tgz#161d5329e8b82fb80cb333f3b957d9c1fb735b63" - integrity sha512-W985IS9RTwcwaVlmw8UOxqHur7YSP+EoaYHLvxyj5Flih0tZgJdWjlXs6Om2PmT5VifB+c88AUjL5SeZTjRgqQ== +xterm-addon-webgl@0.14.0-beta.18: + version "0.14.0-beta.18" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" + integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== -xterm-headless@5.1.0-beta.25: - version "5.1.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.25.tgz#9c9e117caa7c5fb56e4518e6ca14549c3d64d974" - integrity sha512-NsEsf/tGdIuoi7Ey/jIPFbRVWgNFhlmw9PKibW8GsudfAZkbbgggLe/gCHFlOYXpa+vYNGr8cDmDqGT86mFvvw== +xterm-headless@5.1.0-beta.27: + version "5.1.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.27.tgz#59b9033e1f3e7e09bc9dc7d05dd1d82be7a31659" + integrity sha512-ow/0UBeMNGZMxhK+0bZy3pBK+O5so3d2Dbx2z1umjv5EWL2+Ix/Mz51OtQWd6YdSVrs9z+I1QeAd3aYWnnpG8g== -xterm@5.1.0-beta.25: - version "5.1.0-beta.25" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.25.tgz#e926e1bbfe64deee5138dbde4e233963fe9baa9c" - integrity sha512-bX1XJcFWcAvkEoDSGsJa/2hcgHFdLcF9/QnfgsRyePJniTOYuXSK3Z4JK4h+2myUyHMeXjqUehMsfzQ/hA8k9w== +xterm@5.1.0-beta.27: + version "5.1.0-beta.27" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" + integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== y18n@^3.2.1: version "3.2.2" From 37a2386313a2b5f2bbce0f2f40b452b44d68dbfa Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:58:25 -0700 Subject: [PATCH 422/599] Load terminal renderer addon before open is called Fixes #162973 --- .../contrib/terminal/browser/xterm/xtermTerminal.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 892e5411f86..0235cb9f434 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -210,6 +210,13 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this.raw.loadAddon(this._decorationAddon); this._shellIntegrationAddon = this._instantiationService.createInstance(ShellIntegrationAddon, disableShellIntegrationReporting, this._telemetryService); this.raw.loadAddon(this._shellIntegrationAddon); + + // Load the relevant renderer addon ahead of open being called as it's asynchronous + if (this._shouldLoadWebgl()) { + this._enableWebglRenderer(); + } else if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + } } async getSelectionAsHtml(command?: ITerminalCommand): Promise { @@ -240,11 +247,6 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this.raw.open(container); } this._container = container; - if (this._shouldLoadWebgl()) { - this._enableWebglRenderer(); - } else if (this._shouldLoadCanvas()) { - this._enableCanvasRenderer(); - } // Screen must be created at this point as xterm.open is called return this._container.querySelector('.xterm-screen')!; } From 20b891367db457be65e2d2fc84001a2ea3c1a634 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 11:14:19 -0700 Subject: [PATCH 423/599] Sanitize shell integration early This also fixes the sanitize function and adds some tests Fixes #162456 --- .../terminal/common/terminalEnvironment.ts | 19 +++++++++++++++++++ .../common/xterm/shellIntegrationAddon.ts | 2 ++ .../test/common/terminalEnvironment.test.ts | 14 +++++++++++++- .../terminal/common/terminalEnvironment.ts | 19 ++++--------------- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalEnvironment.ts b/src/vs/platform/terminal/common/terminalEnvironment.ts index 1d24a24f60d..7f7ab14a2db 100644 --- a/src/vs/platform/terminal/common/terminalEnvironment.ts +++ b/src/vs/platform/terminal/common/terminalEnvironment.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { OperatingSystem, OS } from 'vs/base/common/platform'; + export function escapeNonWindowsPath(path: string): string { let newPath = path; if (newPath.indexOf('\\') !== 0) { @@ -35,3 +37,20 @@ export function collapseTildePath(path: string | undefined, userHome: string | u } return `~${separator}${path.slice(userHome.length + 1)}`; } + +/** + * Sanitizes a cwd string, removing any wrapping quotes and making the Windows drive letter + * uppercase. + * @param cwd The directory to sanitize. + */ +export function sanitizeCwd(cwd: string): string { + // Sanity check that the cwd is not wrapped in quotes (see #160109) + if (cwd.match(/^['"].*['"]$/)) { + cwd = cwd.substring(1, cwd.length - 1); + } + // Make the drive letter uppercase on Windows (see #9448) + if (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') { + return cwd[0].toUpperCase() + cwd.substring(1); + } + return cwd; +} diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index 47ebe176985..b1a1e4498f9 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -20,6 +20,7 @@ import { BufferMarkCapability } from 'vs/platform/terminal/common/capabilities/b // eslint-disable-next-line local/code-import-patterns import type { ITerminalAddon, Terminal } from 'xterm-headless'; import { URI } from 'vs/base/common/uri'; +import { sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; /** @@ -383,6 +384,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati } private _updateCwd(value: string) { + value = sanitizeCwd(value); this._createOrGetCwdDetection().updateCwd(value); const commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); commandDetection?.setCwd(value); diff --git a/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts index 2c58f9ec1fd..5f8aaca7e15 100644 --- a/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual } from 'assert'; -import { collapseTildePath } from 'vs/platform/terminal/common/terminalEnvironment'; +import { OperatingSystem, OS } from 'vs/base/common/platform'; +import { collapseTildePath, sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; suite('terminalEnvironment', () => { suite('collapseTildePath', () => { @@ -37,4 +38,15 @@ suite('terminalEnvironment', () => { strictEqual(collapseTildePath('/foo/bar/baz', '/foo/', '/'), '~/bar/baz'); }); }); + suite('sanitizeCwd', () => { + if (OS === OperatingSystem.Windows) { + test('should make the Windows drive letter uppercase', () => { + strictEqual(sanitizeCwd('c:\\foo\\bar'), 'C:\\foo\\bar'); + }); + } + test('should remove any wrapping quotes', () => { + strictEqual(sanitizeCwd('\'/foo/bar\''), '/foo/bar'); + strictEqual(sanitizeCwd('"/foo/bar"'), '/foo/bar'); + }); + }); }); diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 5a17c3c3f69..290023e91b6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -14,7 +14,8 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; import { ILogService } from 'vs/platform/log/common/log'; import { IShellLaunchConfig, ITerminalEnvironment, TerminalSettingId, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal'; -import { IProcessEnvironment, isWindows, locale, OperatingSystem, OS, platform, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment, isWindows, locale, platform, Platform } from 'vs/base/common/platform'; +import { sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; export function mergeEnvironments(parent: IProcessEnvironment, other: ITerminalEnvironment | undefined): void { if (!other) { @@ -190,7 +191,7 @@ export async function getCwd( if (shell.cwd) { const unresolved = (typeof shell.cwd === 'object') ? shell.cwd.fsPath : shell.cwd; const resolved = await _resolveCwd(unresolved, variableResolver); - return _sanitizeCwd(resolved || unresolved); + return sanitizeCwd(resolved || unresolved); } let cwd: string | undefined; @@ -213,7 +214,7 @@ export async function getCwd( cwd = root ? root.fsPath : userHome || ''; } - return _sanitizeCwd(cwd); + return sanitizeCwd(cwd); } async function _resolveCwd(cwd: string, variableResolver: VariableResolver | undefined, logService?: ILogService): Promise { @@ -228,18 +229,6 @@ async function _resolveCwd(cwd: string, variableResolver: VariableResolver | und return cwd; } -function _sanitizeCwd(cwd: string): string { - // Sanity check that the cwd is not wrapped in quotes (see #160109) - if (cwd.match(/$['"].*['"]^/)) { - cwd = cwd.substring(1, cwd.length - 1); - } - // Make the drive letter uppercase on Windows (see #9448) - if (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') { - return cwd[0].toUpperCase() + cwd.substr(1); - } - return cwd; -} - export type TerminalShellSetting = ( TerminalSettingId.AutomationShellWindows | TerminalSettingId.AutomationShellMacOs From 1caeac2354be88cc595d9d962f178bc5cf854060 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 11:21:03 -0700 Subject: [PATCH 424/599] Hide failed to activate message when it didn't try Fixes #158218 --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 1 + src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 1 + src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index c7cb9da5658..e32628f01e3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -455,6 +455,7 @@ export interface ITerminalInstance { readonly initialCwd?: string; readonly os?: OperatingSystem; readonly capabilities: ITerminalCapabilityStore; + readonly usedShellIntegrationInjection: boolean; readonly statusList: ITerminalStatusList; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 540c770e19f..f1e4b3b2b3b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -207,6 +207,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _target?: TerminalLocation | undefined; private _disableShellIntegrationReporting: boolean | undefined; private _usedShellIntegrationInjection: boolean = false; + get usedShellIntegrationInjection(): boolean { return this._usedShellIntegrationInjection; } private _quickFixAddon: TerminalQuickFixAddon | undefined; readonly capabilities = new TerminalCapabilityStoreMultiplexer(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts b/src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts index 4b7b97e5d06..8c1434a7981 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTooltip.ts @@ -22,7 +22,9 @@ export function getShellIntegrationTooltip(instance: ITerminalInstance, markdown if (instance.shellLaunchConfig.ignoreShellIntegration) { shellIntegrationString += `${markdown ? '\n\n---\n\n' : '\n\n'} ${localize('launchFailed.exitCodeOnlyShellIntegration', "The terminal process failed to launch. Disabling shell integration with terminal.integrated.shellIntegration.enabled might help.")}`; } else { - shellIntegrationString += `${markdown ? '\n\n---\n\n' : '\n\n'} ${localize('shellIntegration.activationFailed', "Shell integration failed to activate")}`; + if (instance.usedShellIntegrationInjection) { + shellIntegrationString += `${markdown ? '\n\n---\n\n' : '\n\n'} ${localize('shellIntegration.activationFailed', "Shell integration failed to activate")}`; + } } } return shellIntegrationString; From 1bebd6e2f1cad3778c32187eb605d21e35874a07 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Fri, 7 Oct 2022 11:42:17 -0700 Subject: [PATCH 425/599] Polish walkthrough star icon styles (#162979) Update star icon size --- .../welcomeGettingStarted/browser/media/gettingStarted.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css index 7537aa9a1e6..d9136fe108a 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css @@ -333,7 +333,7 @@ .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .featured .featured-icon { top: -30px; left: 4px; - font-size: 12pt; + font-size: 14px; } .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-category .codicon.hide-category-button { From 7d1b7b6280ea027aef4511a2ecebd2459977dee6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:07:31 -0700 Subject: [PATCH 426/599] Expose show texture atlas command This creates a file in the workspace and opens it currently, this could be made nicer but it does the job for now. Fixes #158920 --- .../contrib/terminal/browser/terminal.ts | 5 +++ .../terminal/browser/terminalActions.ts | 39 +++++++++++++++++++ .../terminal/browser/xterm/xtermTerminal.ts | 8 ++++ .../contrib/terminal/common/terminal.ts | 1 + 4 files changed, 53 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index c7cb9da5658..d2792bef509 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -987,6 +987,11 @@ export interface IXtermTerminal { readonly onDidChangeSelection: Event; + /** + * Gets a view of the current texture atlas used by the renderers. + */ + readonly textureAtlas: Promise | undefined; + /** * The position of the terminal. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index c6c85fe83bf..2682d462750 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -55,6 +55,8 @@ import { clearShellFileHistory, getCommandHistory } from 'vs/workbench/contrib/t import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { IFileService } from 'vs/platform/files/common/files'; +import { VSBuffer } from 'vs/base/common/buffer'; export const switchTerminalActionViewItemSeparator = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'; export const switchTerminalShowTabsTitle = localize('showTerminalTabs', "Show Tabs"); @@ -2226,6 +2228,43 @@ export function registerTerminalActions() { clearShellFileHistory(); } }); + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.ShowTextureAtlas, + title: { value: localize('workbench.action.terminal.showTextureAtlas', "Show Terminal Texture Atlas"), original: 'Show Terminal Texture Atlas' }, + f1: true, + category: Categories.Developer.value, + precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated) + }); + } + async run(accessor: ServicesAccessor) { + const terminalService = accessor.get(ITerminalService); + const fileService = accessor.get(IFileService); + const openerService = accessor.get(IOpenerService); + const workspaceContextService = accessor.get(IWorkspaceContextService); + const bitmap = await terminalService.activeInstance?.xterm?.textureAtlas; + if (!bitmap) { + return; + } + const cwdUri = workspaceContextService.getWorkspace().folders[0].uri; + const fileUri = URI.joinPath(cwdUri, 'textureAtlas.png'); + const canvas = document.createElement('canvas'); + canvas.width = bitmap.width; + canvas.height = bitmap.height; + const ctx = canvas.getContext('bitmaprenderer'); + if (!ctx) { + return; + } + ctx.transferFromImageBitmap(bitmap); + const blob = await new Promise((res) => canvas.toBlob(res)); + if (!blob) { + return; + } + await fileService.writeFile(fileUri, VSBuffer.wrap(new Uint8Array(await blob.arrayBuffer()))); + openerService.open(fileUri); + } + }); registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 892e5411f86..e0c3c536b5b 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -121,6 +121,14 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II } get target(): TerminalLocation | undefined { return this._target; } + get textureAtlas(): Promise | undefined { + const canvas = this._webglAddon?.textureAtlas || this._canvasAddon?.textureAtlas; + if (!canvas) { + return undefined; + } + return createImageBitmap(canvas); + } + /** * @param xtermCtor The xterm.js constructor, this is passed in so it can be fetched lazily * outside of this class such that {@link raw} is not nullable. diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 7d3d05d5e16..2f6901c8d82 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -573,6 +573,7 @@ export const enum TerminalCommandId { SetDimensions = 'workbench.action.terminal.setDimensions', ClearCommandHistory = 'workbench.action.terminal.clearCommandHistory', WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal', + ShowTextureAtlas = 'workbench.action.terminal.showTextureAtlas', } export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ From 8b49f1a780881ad36c244679037a191feff21e43 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:08:48 -0700 Subject: [PATCH 427/599] Improve precondition --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 2682d462750..d794801e399 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -2235,7 +2235,7 @@ export function registerTerminalActions() { title: { value: localize('workbench.action.terminal.showTextureAtlas', "Show Terminal Texture Atlas"), original: 'Show Terminal Texture Atlas' }, f1: true, category: Categories.Developer.value, - precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated) + precondition: ContextKeyExpr.or(TerminalContextKeys.isOpen) }); } async run(accessor: ServicesAccessor) { From 944e63e798a3407ea196a31c5454c42cf6d4fd54 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 7 Oct 2022 21:26:26 +0200 Subject: [PATCH 428/599] Use submenu for switch output action (#162966) * #162304 Use submenu for switch output action * fix monaco editor checks --- .../browser/ui/actionbar/actionViewItems.ts | 8 +- src/vs/base/browser/ui/selectBox/selectBox.ts | 3 +- .../browser/menuEntryActionViewItem.ts | 47 +- src/vs/platform/actions/common/actions.ts | 1 + .../contrib/output/browser/media/output.css | 42 -- .../output/browser/output.contribution.ts | 443 ++++++++++-------- .../contrib/output/browser/outputServices.ts | 9 +- .../contrib/output/browser/outputView.ts | 97 +--- .../services/output/common/output.ts | 2 + 9 files changed, 314 insertions(+), 338 deletions(-) delete mode 100644 src/vs/workbench/contrib/output/browser/media/output.css diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 0e97d180ef1..02e9bc99513 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -435,9 +435,11 @@ export class SelectActionViewItem extends BaseActionViewItem { } private registerListeners(): void { - this._register(this.selectBox.onDidSelect(e => { - this.actionRunner.run(this._action, this.getActionContext(e.selected, e.index)); - })); + this._register(this.selectBox.onDidSelect(e => this.runAction(e.selected, e.index))); + } + + protected runAction(option: string, index: number): void { + this.actionRunner.run(this._action, this.getActionContext(option, index)); } protected getActionContext(option: string, index: number) { diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index fbf46c262fe..d31b8828697 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -14,6 +14,7 @@ import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { deepClone } from 'vs/base/common/objects'; import { isMacintosh } from 'vs/base/common/platform'; +import { IThemable } from 'vs/base/common/styler'; import 'vs/css!./selectBox'; @@ -77,7 +78,7 @@ export interface ISelectData { index: number; } -export class SelectBox extends Widget implements ISelectBoxDelegate { +export class SelectBox extends Widget implements ISelectBoxDelegate, IThemable { private selectBoxDelegate: ISelectBoxDelegate; constructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles = deepClone(defaultStyles), selectBoxOptions?: ISelectBoxOptions) { diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 41faa91d8d7..bac16a59fc4 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -5,7 +5,7 @@ import { $, addDisposableListener, append, asCSSUrl, EventType, ModifierKeyEmitter, prepend } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { ActionViewItem, BaseActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { DropdownMenuActionViewItem, IDropdownMenuActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { ActionRunner, IAction, IRunEvent, Separator, SubmenuAction } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; @@ -18,7 +18,7 @@ import { localize } from 'vs/nls'; import { IMenu, IMenuActionOptions, IMenuService, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { ICommandAction, isICommandActionToggleInfo } from 'vs/platform/action/common/action'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -27,6 +27,8 @@ import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService' import { isDark } from 'vs/platform/theme/common/theme'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { assertType } from 'vs/base/common/types'; +import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; export function createAndFillInContextMenuActions(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[] }, primaryGroup?: string): void { const groups = menu.getActions(options); @@ -468,6 +470,37 @@ export class DropdownWithDefaultActionViewItem extends BaseActionViewItem { } } +class SubmenuEntrySelectActionViewItem extends SelectActionViewItem { + + constructor( + action: SubmenuItemAction, + @IThemeService private readonly themeService: IThemeService, + @IContextViewService contextViewService: IContextViewService + ) { + super(null, action, action.actions.map(a => ({ + text: a.id === Separator.ID ? '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500' : a.label, + isDisabled: !a.enabled, + })), 0, contextViewService, { ariaLabel: action.tooltip, optionsAsChildren: true }); + this._register(attachSelectBoxStyler(this.selectBox, themeService)); + this.select(Math.max(0, action.actions.findIndex(a => a.checked))); + } + + override render(container: HTMLElement): void { + super.render(container); + this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => { + container.style.borderColor = colors.selectBorder ? `${colors.selectBorder}` : ''; + })); + } + + protected override runAction(option: string, index: number): void { + const action = (this.action as SubmenuItemAction).actions[index]; + if (action) { + this.actionRunner.run(action); + } + } + +} + /** * Creates action view items for menu actions or submenu actions. */ @@ -475,10 +508,14 @@ export function createActionViewItem(instaService: IInstantiationService, action if (action instanceof MenuItemAction) { return instaService.createInstance(MenuEntryActionViewItem, action, options); } else if (action instanceof SubmenuItemAction) { - if (action.item.rememberDefaultAction) { - return instaService.createInstance(DropdownWithDefaultActionViewItem, action, options); + if (action.item.isSelection) { + return instaService.createInstance(SubmenuEntrySelectActionViewItem, action); } else { - return instaService.createInstance(SubmenuEntryActionViewItem, action, options); + if (action.item.rememberDefaultAction) { + return instaService.createInstance(DropdownWithDefaultActionViewItem, action, options); + } else { + return instaService.createInstance(SubmenuEntryActionViewItem, action, options); + } } } else { return undefined; diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 1d64a7383ee..100e88560ed 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -32,6 +32,7 @@ export interface ISubmenuItem { when?: ContextKeyExpression; group?: 'navigation' | string; order?: number; + isSelection?: boolean; rememberDefaultAction?: boolean; // for dropdown menu: if true the last executed action is remembered as the default action } diff --git a/src/vs/workbench/contrib/output/browser/media/output.css b/src/vs/workbench/contrib/output/browser/media/output.css deleted file mode 100644 index ea0ee3e8d6b..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/output.css +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - -.monaco-workbench .part.sidebar > .title > .title-actions .switch-output, -.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-output { - border-width: 1px; - border-style: solid; -} - -.part.panel > .title > .title-actions .switch-output > .monaco-select-box { - border-width: 1px; - border-style: solid; -} - -.monaco-workbench .part.sidebar > .title > .title-actions .switch-output { - display: flex; - align-items: center; - font-size: 11px; - margin-right: 0.3em; - height: 20px; - flex-shrink: 1; - margin-top: 7px; -} - -.monaco-workbench.mac .part.sidebar > .title > .title-actions .switch-output { - border-radius: 4px; -} - -.monaco-workbench .part.sidebar > .title > .title-actions .switch-output > .monaco-select-box { - display: block !important; -} - -.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-output.action-item.select-container { - border: none !important; -} - -.monaco-workbench .part.sidebar > .title > .title-actions .switch-output > .monaco-select-box { - padding: 0 22px 0 6px; -} diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 08aebc57bca..ab7c785f4f8 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -5,14 +5,13 @@ import * as nls from 'vs/nls'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import 'vs/css!./media/output'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { ModesRegistry } from 'vs/editor/common/languages/modesRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; -import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; +import { MenuId, registerAction2, Action2, MenuRegistry } from 'vs/platform/actions/common/actions'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { OutputService, LogContentProvider } from 'vs/workbench/contrib/output/browser/outputServices'; -import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, LOG_MODE_ID, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK, IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output'; +import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, LOG_MODE_ID, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK, IOutputChannelDescriptor, IFileOutputChannelDescriptor, ACTIVE_OUTPUT_CHANNEL_CONTEXT, IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output'; import { OutputViewPane } from 'vs/workbench/contrib/output/browser/outputView'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { LogViewer, LogViewerInput } from 'vs/workbench/contrib/output/browser/logViewer'; @@ -32,6 +31,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { EditorExtensions } from 'vs/workbench/common/editor'; +import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; // Register Service registerSingleton(IOutputService, OutputService, InstantiationType.Delayed); @@ -93,204 +93,263 @@ Registry.as(EditorExtensions.EditorPane).registerEditorPane ] ); -class OutputContribution implements IWorkbenchContribution { +class OutputContribution extends Disposable implements IWorkbenchContribution { constructor( @IInstantiationService instantiationService: IInstantiationService, - @ITextModelService textModelService: ITextModelService + @ITextModelService textModelService: ITextModelService, + @IOutputService private readonly outputService: IOutputService, ) { + super(); textModelService.registerTextModelContentProvider(LOG_SCHEME, instantiationService.createInstance(LogContentProvider)); + this.registerActions(); } + + private registerActions(): void { + this.registerSwitchOutputAction(); + this.registerClearOutputAction(); + this.registerToggleAutoScrollAction(); + this.registerOpenActiveLogOutputFileAction(); + this.registerShowLogsAction(); + this.registerOpenLogFileAction(); + } + + private registerSwitchOutputAction(): void { + const switchOutputMenu = new MenuId('workbench.output.menu.switchOutput'); + this._register(MenuRegistry.appendMenuItem(MenuId.ViewTitle, { + submenu: switchOutputMenu, + title: nls.localize('switchToOutput.label', "Switch Output"), + group: 'navigation', + when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), + order: 1, + isSelection: true + })); + const registeredChannels = new Map(); + this._register(toDisposable(() => dispose(registeredChannels.values()))); + const registerOutputChannels = (channels: IOutputChannelDescriptor[]) => { + for (const channel of channels) { + let group = '0_outputchannels'; + let title = channel.label; + if (channel.log) { + title = nls.localize('logChannel', "Log ({0})", channel.label); + if (channel.extensionId) { + group = '2_extensionlogs'; + } else { + group = '1_logs'; + } + } + registeredChannels.set(channel.id, registerAction2(class extends Action2 { + constructor() { + super({ + id: channel.id, + title, + toggled: ACTIVE_OUTPUT_CHANNEL_CONTEXT.isEqualTo(channel.id), + menu: { + id: switchOutputMenu, + group, + } + }); + } + async run(accessor: ServicesAccessor): Promise { + return accessor.get(IOutputService).showChannel(this.desc.id, true); + } + })); + } + }; + registerOutputChannels(this.outputService.getChannelDescriptors()); + const outputChannelRegistry = Registry.as(Extensions.OutputChannels); + this._register(outputChannelRegistry.onDidRegisterChannel(e => { + const channel = this.outputService.getChannelDescriptor(e); + if (channel) { + registerOutputChannels([channel]); + } + })); + this._register(outputChannelRegistry.onDidRemoveChannel(e => { + registeredChannels.get(e)?.dispose(); + registeredChannels.delete(e); + })); + } + + private registerClearOutputAction(): void { + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: `workbench.output.action.clearOutput`, + title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' }, + category: Categories.View, + menu: [{ + id: MenuId.ViewTitle, + when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), + group: 'navigation', + order: 2 + }, { + id: MenuId.CommandPalette + }, { + id: MenuId.EditorContext, + when: CONTEXT_IN_OUTPUT + }], + icon: Codicon.clearAll + }); + } + async run(accessor: ServicesAccessor): Promise { + const outputService = accessor.get(IOutputService); + const activeChannel = outputService.getActiveChannel(); + if (activeChannel) { + activeChannel.clear(); + aria.status(nls.localize('outputCleared', "Output was cleared")); + } + } + })); + } + + private registerToggleAutoScrollAction(): void { + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: `workbench.output.action.toggleAutoScroll`, + title: { value: nls.localize('toggleAutoScroll', "Toggle Auto Scrolling"), original: 'Toggle Auto Scrolling' }, + tooltip: nls.localize('outputScrollOff', "Turn Auto Scrolling Off"), + menu: { + id: MenuId.ViewTitle, + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', OUTPUT_VIEW_ID)), + group: 'navigation', + order: 3, + }, + icon: Codicon.lock, + toggled: { + condition: CONTEXT_OUTPUT_SCROLL_LOCK, + icon: Codicon.unlock, + tooltip: nls.localize('outputScrollOn', "Turn Auto Scrolling On") + } + }); + } + async run(accessor: ServicesAccessor): Promise { + const outputView = accessor.get(IViewsService).getActiveViewWithId(OUTPUT_VIEW_ID)!; + outputView.scrollLock = !outputView.scrollLock; + } + })); + } + + private registerOpenActiveLogOutputFileAction(): void { + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: `workbench.action.openActiveLogOutputFile`, + title: { value: nls.localize('openActiveLogOutputFile', "Open Log Output File"), original: 'Open Log Output File' }, + menu: [{ + id: MenuId.ViewTitle, + when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), + group: 'navigation', + order: 4 + }, { + id: MenuId.CommandPalette, + when: CONTEXT_ACTIVE_LOG_OUTPUT, + }], + icon: Codicon.goToFile, + precondition: CONTEXT_ACTIVE_LOG_OUTPUT + }); + } + async run(accessor: ServicesAccessor): Promise { + const outputService = accessor.get(IOutputService); + const editorService = accessor.get(IEditorService); + const instantiationService = accessor.get(IInstantiationService); + const logFileOutputChannelDescriptor = this.getLogFileOutputChannelDescriptor(outputService); + if (logFileOutputChannelDescriptor) { + await editorService.openEditor(instantiationService.createInstance(LogViewerInput, logFileOutputChannelDescriptor), { pinned: true }); + } + } + private getLogFileOutputChannelDescriptor(outputService: IOutputService): IFileOutputChannelDescriptor | null { + const channel = outputService.getActiveChannel(); + if (channel) { + const descriptor = outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0]; + if (descriptor && descriptor.file && descriptor.log) { + return descriptor; + } + } + return null; + } + })); + } + + private registerShowLogsAction(): void { + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.showLogs', + title: { value: nls.localize('showLogs', "Show Logs..."), original: 'Show Logs...' }, + category: Categories.Developer, + menu: { + id: MenuId.CommandPalette, + }, + }); + } + async run(accessor: ServicesAccessor): Promise { + const outputService = accessor.get(IOutputService); + const quickInputService = accessor.get(IQuickInputService); + const extensionLogs = [], logs = []; + for (const channel of outputService.getChannelDescriptors()) { + if (channel.log) { + if (channel.extensionId) { + extensionLogs.push(channel); + } else { + logs.push(channel); + } + } + } + const entries: ({ id: string; label: string } | IQuickPickSeparator)[] = []; + for (const { id, label } of logs) { + entries.push({ id, label }); + } + if (extensionLogs.length && logs.length) { + entries.push({ type: 'separator', label: nls.localize('extensionLogs', "Extension Logs") }); + } + for (const { id, label } of extensionLogs) { + entries.push({ id, label }); + } + const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") }); + if (entry) { + return outputService.showChannel(entry.id); + } + } + })); + } + + private registerOpenLogFileAction(): void { + interface IOutputChannelQuickPickItem extends IQuickPickItem { + channel: IOutputChannelDescriptor; + } + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.openLogFile', + title: { value: nls.localize('openLogFile', "Open Log File..."), original: 'Open Log File...' }, + category: Categories.Developer, + menu: { + id: MenuId.CommandPalette, + }, + }); + } + async run(accessor: ServicesAccessor): Promise { + const outputService = accessor.get(IOutputService); + const quickInputService = accessor.get(IQuickInputService); + const instantiationService = accessor.get(IInstantiationService); + const editorService = accessor.get(IEditorService); + + const entries: IOutputChannelQuickPickItem[] = outputService.getChannelDescriptors().filter(c => c.file && c.log) + .map(channel => ({ id: channel.id, label: channel.label, channel })); + + const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") }); + if (entry) { + assertIsDefined(entry.channel.file); + await editorService.openEditor(instantiationService.createInstance(LogViewerInput, (entry.channel as IFileOutputChannelDescriptor)), { pinned: true }); + } + } + })); + } + } Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(OutputContribution, LifecyclePhase.Restored); -registerAction2(class extends Action2 { - constructor() { - super({ - _isFakeAction: true, - id: `workbench.output.action.switchBetweenOutputs`, - title: nls.localize('switchToOutput.label', "Switch to Output"), - menu: { - id: MenuId.ViewTitle, - when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), - group: 'navigation', - order: 1 - }, - }); - } - async run(accessor: ServicesAccessor, channelId: string): Promise { - if (typeof channelId === 'string') { - // Sometimes the action is executed with no channelId parameter, then we should just ignore it #103496 - accessor.get(IOutputService).showChannel(channelId, true); - } - } -}); -registerAction2(class extends Action2 { - constructor() { - super({ - id: `workbench.output.action.clearOutput`, - title: { value: nls.localize('clearOutput.label', "Clear Output"), original: 'Clear Output' }, - category: Categories.View, - menu: [{ - id: MenuId.ViewTitle, - when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), - group: 'navigation', - order: 2 - }, { - id: MenuId.CommandPalette - }, { - id: MenuId.EditorContext, - when: CONTEXT_IN_OUTPUT - }], - icon: Codicon.clearAll - }); - } - async run(accessor: ServicesAccessor): Promise { - const outputService = accessor.get(IOutputService); - const activeChannel = outputService.getActiveChannel(); - if (activeChannel) { - activeChannel.clear(); - aria.status(nls.localize('outputCleared', "Output was cleared")); - } - } -}); -registerAction2(class extends Action2 { - constructor() { - super({ - id: `workbench.output.action.toggleAutoScroll`, - title: { value: nls.localize('toggleAutoScroll', "Toggle Auto Scrolling"), original: 'Toggle Auto Scrolling' }, - tooltip: nls.localize('outputScrollOff', "Turn Auto Scrolling Off"), - menu: { - id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', OUTPUT_VIEW_ID)), - group: 'navigation', - order: 3, - }, - icon: Codicon.lock, - toggled: { - condition: CONTEXT_OUTPUT_SCROLL_LOCK, - icon: Codicon.unlock, - tooltip: nls.localize('outputScrollOn', "Turn Auto Scrolling On") - } - }); - } - async run(accessor: ServicesAccessor): Promise { - const outputView = accessor.get(IViewsService).getActiveViewWithId(OUTPUT_VIEW_ID)!; - outputView.scrollLock = !outputView.scrollLock; - } -}); -registerAction2(class extends Action2 { - constructor() { - super({ - id: `workbench.action.openActiveLogOutputFile`, - title: { value: nls.localize('openActiveLogOutputFile', "Open Log Output File"), original: 'Open Log Output File' }, - menu: [{ - id: MenuId.ViewTitle, - when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), - group: 'navigation', - order: 4 - }, { - id: MenuId.CommandPalette, - when: CONTEXT_ACTIVE_LOG_OUTPUT, - }], - icon: Codicon.goToFile, - precondition: CONTEXT_ACTIVE_LOG_OUTPUT - }); - } - async run(accessor: ServicesAccessor): Promise { - const outputService = accessor.get(IOutputService); - const editorService = accessor.get(IEditorService); - const instantiationService = accessor.get(IInstantiationService); - const logFileOutputChannelDescriptor = this.getLogFileOutputChannelDescriptor(outputService); - if (logFileOutputChannelDescriptor) { - await editorService.openEditor(instantiationService.createInstance(LogViewerInput, logFileOutputChannelDescriptor), { pinned: true }); - } - } - private getLogFileOutputChannelDescriptor(outputService: IOutputService): IFileOutputChannelDescriptor | null { - const channel = outputService.getActiveChannel(); - if (channel) { - const descriptor = outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0]; - if (descriptor && descriptor.file && descriptor.log) { - return descriptor; - } - } - return null; - } -}); - -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'workbench.action.showLogs', - title: { value: nls.localize('showLogs', "Show Logs..."), original: 'Show Logs...' }, - category: Categories.Developer, - menu: { - id: MenuId.CommandPalette, - }, - }); - } - async run(accessor: ServicesAccessor): Promise { - const outputService = accessor.get(IOutputService); - const quickInputService = accessor.get(IQuickInputService); - const extensionLogs = [], logs = []; - for (const channel of outputService.getChannelDescriptors()) { - if (channel.log) { - if (channel.extensionId) { - extensionLogs.push(channel); - } else { - logs.push(channel); - } - } - } - const entries: ({ id: string; label: string } | IQuickPickSeparator)[] = []; - for (const { id, label } of logs) { - entries.push({ id, label }); - } - if (extensionLogs.length && logs.length) { - entries.push({ type: 'separator', label: nls.localize('extensionLogs', "Extension Logs") }); - } - for (const { id, label } of extensionLogs) { - entries.push({ id, label }); - } - const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") }); - if (entry) { - return outputService.showChannel(entry.id); - } - } -}); - -interface IOutputChannelQuickPickItem extends IQuickPickItem { - channel: IOutputChannelDescriptor; -} - -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'workbench.action.openLogFile', - title: { value: nls.localize('openLogFile', "Open Log File..."), original: 'Open Log File...' }, - category: Categories.Developer, - menu: { - id: MenuId.CommandPalette, - }, - }); - } - async run(accessor: ServicesAccessor): Promise { - const outputService = accessor.get(IOutputService); - const quickInputService = accessor.get(IQuickInputService); - const instantiationService = accessor.get(IInstantiationService); - const editorService = accessor.get(IEditorService); - - const entries: IOutputChannelQuickPickItem[] = outputService.getChannelDescriptors().filter(c => c.file && c.log) - .map(channel => ({ id: channel.id, label: channel.label, channel })); - - const entry = await quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") }); - if (entry) { - assertIsDefined(entry.channel.file); - await editorService.openEditor(instantiationService.createInstance(LogViewerInput, (entry.channel as IFileOutputChannelDescriptor)), { pinned: true }); - } - } -}); - Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'output', order: 30, diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index e9f97c01b29..29ce15adbac 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -9,7 +9,7 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IOutputChannel, IOutputService, OUTPUT_VIEW_ID, OUTPUT_SCHEME, LOG_SCHEME, LOG_MIME, OUTPUT_MIME, OutputChannelUpdateMode, IOutputChannelDescriptor, Extensions, IOutputChannelRegistry } from 'vs/workbench/services/output/common/output'; +import { IOutputChannel, IOutputService, OUTPUT_VIEW_ID, OUTPUT_SCHEME, LOG_SCHEME, LOG_MIME, OUTPUT_MIME, OutputChannelUpdateMode, IOutputChannelDescriptor, Extensions, IOutputChannelRegistry, ACTIVE_OUTPUT_CHANNEL_CONTEXT } from 'vs/workbench/services/output/common/output'; import { OutputLinkProvider } from 'vs/workbench/contrib/output/browser/outputLinkProvider'; import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { ITextModel } from 'vs/editor/common/model'; @@ -20,6 +20,7 @@ import { IViewsService } from 'vs/workbench/common/views'; import { OutputViewPane } from 'vs/workbench/contrib/output/browser/outputView'; import { IOutputChannelModelService } from 'vs/workbench/contrib/output/common/outputChannelModelService'; import { ILanguageService } from 'vs/editor/common/languages/language'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const OUTPUT_ACTIVE_CHANNEL_KEY = 'output.activechannel'; @@ -71,6 +72,8 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private readonly _onActiveOutputChannel = this._register(new Emitter()); readonly onActiveOutputChannel: Event = this._onActiveOutputChannel.event; + private readonly activeOutputChannelContext: IContextKey; + constructor( @IStorageService private readonly storageService: IStorageService, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -78,9 +81,13 @@ export class OutputService extends Disposable implements IOutputService, ITextMo @ILogService private readonly logService: ILogService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IViewsService private readonly viewsService: IViewsService, + @IContextKeyService contextKeyService: IContextKeyService, ) { super(); this.activeChannelIdInStorage = this.storageService.get(OUTPUT_ACTIVE_CHANNEL_KEY, StorageScope.WORKSPACE, ''); + this.activeOutputChannelContext = ACTIVE_OUTPUT_CHANNEL_CONTEXT.bindTo(contextKeyService); + this.activeOutputChannelContext.set(this.activeChannelIdInStorage); + this._register(this.onActiveOutputChannel(channel => this.activeOutputChannelContext.set(channel))); // Register as text model content provider for output textModelResolverService.registerTextModelContentProvider(OUTPUT_SCHEME, this); diff --git a/src/vs/workbench/contrib/output/browser/outputView.ts b/src/vs/workbench/contrib/output/browser/outputView.ts index dd969c688c3..ca71904b6cd 100644 --- a/src/vs/workbench/contrib/output/browser/outputView.ts +++ b/src/vs/workbench/contrib/output/browser/outputView.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { IAction } from 'vs/base/common/actions'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -14,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { AbstractTextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; -import { OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, IOutputChannel, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK, IOutputChannelDescriptor, IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output'; +import { OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, IOutputChannel, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK } from 'vs/workbench/services/output/common/output'; import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -23,18 +22,13 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { CursorChangeReason } from 'vs/editor/common/cursorEvents'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { editorBackground, selectBorder } from 'vs/platform/theme/common/colorRegistry'; -import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { Dimension } from 'vs/base/browser/dom'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { IFileService } from 'vs/platform/files/common/files'; @@ -121,12 +115,6 @@ export class OutputViewPane extends ViewPane { this.editor.layout(new Dimension(width, height)); } - override getActionViewItem(action: IAction): IActionViewItem | undefined { - if (action.id === 'workbench.output.action.switchBetweenOutputs') { - return this.instantiationService.createInstance(SwitchOutputActionViewItem, action); - } - return super.getActionViewItem(action); - } private onDidChangeVisibility(visible: boolean): void { this.editor.setVisible(visible); @@ -270,85 +258,6 @@ export class OutputEditor extends AbstractTextResourceEditor { } } -type OutputChannelSelectionOptionItem = ISelectOptionItem & { readonly channel?: IOutputChannelDescriptor }; - -class SwitchOutputActionViewItem extends SelectActionViewItem { - - private static readonly SEPARATOR = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'; - - private selectionOptionItems: OutputChannelSelectionOptionItem[] = []; - - constructor( - action: IAction, - @IOutputService private readonly outputService: IOutputService, - @IThemeService private readonly themeService: IThemeService, - @IContextViewService contextViewService: IContextViewService - ) { - super(null, action, [], 0, contextViewService, { ariaLabel: nls.localize('outputChannels', "Output Channels"), optionsAsChildren: true }); - - const outputChannelRegistry = Registry.as(Extensions.OutputChannels); - this._register(outputChannelRegistry.onDidRegisterChannel(() => this.updateOptions())); - this._register(outputChannelRegistry.onDidRemoveChannel(() => this.updateOptions())); - this._register(this.outputService.onActiveOutputChannel(() => this.updateOptions())); - this._register(attachSelectBoxStyler(this.selectBox, themeService)); - - this.updateOptions(); - } - - override render(container: HTMLElement): void { - super.render(container); - container.classList.add('switch-output'); - this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => { - container.style.borderColor = colors.selectBorder ? `${colors.selectBorder}` : ''; - })); - } - - protected override getActionContext(option: string, index: number): string { - return this.selectionOptionItems[index]?.channel?.id ?? option; - } - - private updateOptions(): void { - const outputChannels = []; - const logChannels = []; - const extensionLogChannels = []; - this.selectionOptionItems = []; - for (const descriptor of this.outputService.getChannelDescriptors()) { - if (descriptor.log) { - if (descriptor.extensionId) { - extensionLogChannels.push(descriptor); - } else { - logChannels.push(descriptor); - } - } else { - outputChannels.push(descriptor); - } - } - - for (const descriptor of outputChannels) { - this.selectionOptionItems.push({ text: descriptor.label, isDisabled: false, channel: descriptor }); - } - if (outputChannels.length && logChannels.length) { - this.selectionOptionItems.push({ text: SwitchOutputActionViewItem.SEPARATOR, isDisabled: true }); - } - for (const descriptor of logChannels) { - this.selectionOptionItems.push({ text: nls.localize('logChannel', "Log ({0})", descriptor.label), isDisabled: false, channel: descriptor }); - } - if (logChannels.length && extensionLogChannels.length) { - this.selectionOptionItems.push({ text: SwitchOutputActionViewItem.SEPARATOR, isDisabled: true }); - } - for (const descriptor of extensionLogChannels) { - this.selectionOptionItems.push({ text: nls.localize('logChannel', "Log ({0})", descriptor.label), isDisabled: false, channel: descriptor }); - } - - let selected = 0; - const activeChannel = this.outputService.getActiveChannel(); - if (activeChannel) { - selected = this.selectionOptionItems.findIndex(item => item.channel?.id === activeChannel.id); - } - this.setOptions(this.selectionOptionItems, Math.max(0, selected)); - } -} - registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { // Sidebar background for the output view const sidebarBackground = theme.getColor(SIDE_BAR_BACKGROUND); diff --git a/src/vs/workbench/services/output/common/output.ts b/src/vs/workbench/services/output/common/output.ts index 93698acaa1d..5adde39b333 100644 --- a/src/vs/workbench/services/output/common/output.ts +++ b/src/vs/workbench/services/output/common/output.ts @@ -257,3 +257,5 @@ async function whenFileExists(file: URI, trial: number, fileService: IFileServic await timeout(1000, token); await whenFileExists(file, trial + 1, fileService, logService, token); } + +export const ACTIVE_OUTPUT_CHANNEL_CONTEXT = new RawContextKey('activeOutputChannel', ''); From a8fe1cc1578ee6dfb7ad8d7d4d627b0af2def1a4 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 7 Oct 2022 21:43:30 +0000 Subject: [PATCH 429/599] Debt - extract Continue On picker and contrib into separate class (#163002) Debt - extract picker and contrib into separate class --- .../editSessions/browser/continueOnPicker.ts | 160 +++++++++++++++ .../browser/editSessions.contribution.ts | 191 +----------------- 2 files changed, 168 insertions(+), 183 deletions(-) create mode 100644 src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts diff --git a/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts b/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts new file mode 100644 index 00000000000..e9b3df9ac79 --- /dev/null +++ b/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts @@ -0,0 +1,160 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { MenuRegistry } from 'vs/platform/actions/common/actions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IContinueOnPicker = createDecorator('IContinueOnPicker'); +export interface IContinueOnPicker { + _serviceBrand: undefined; + + pick(): Promise; +} + +export class ContinueOnPicker extends Disposable implements IContinueOnPicker { + _serviceBrand = undefined; + + private continueEditSessionOptions: ContinueEditSessionItem[] = []; + + constructor( + @IQuickInputService private readonly quickInputService: IQuickInputService, + @ICommandService private commandService: ICommandService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + ) { + super(); + + this.registerContributedEditSessionOptions(); + } + + private registerContributedEditSessionOptions() { + continueEditSessionExtPoint.setHandler(extensions => { + const continueEditSessionOptions: ContinueEditSessionItem[] = []; + for (const extension of extensions) { + if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) { + continue; + } + if (!Array.isArray(extension.value)) { + continue; + } + for (const contribution of extension.value) { + const command = MenuRegistry.getCommand(contribution.command); + if (!command) { + return; + } + + const icon = command.icon; + const title = typeof command.title === 'string' ? command.title : command.title.value; + + continueEditSessionOptions.push(new ContinueEditSessionItem( + ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title, + command.id, + command.source, + ContextKeyExpr.deserialize(contribution.when) + )); + } + } + this.continueEditSessionOptions = continueEditSessionOptions; + }); + } + + async pick(): Promise { + const quickPick = this.quickInputService.createQuickPick(); + + const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER + ? this.contextService.getWorkspace().folders[0].name + : this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', '); + quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`); + quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working'); + quickPick.items = this.createPickItems(); + + const command = await new Promise((resolve, reject) => { + quickPick.onDidHide(() => resolve(undefined)); + + quickPick.onDidAccept((e) => { + const selection = quickPick.activeItems[0].command; + resolve(selection); + quickPick.hide(); + }); + + quickPick.show(); + }); + + quickPick.dispose(); + + if (command === undefined) { + return undefined; + } + + try { + const uri = await this.commandService.executeCommand(command); + + // Some continue on commands do not return a URI + // to support extensions which want to be in control + // of how the destination is opened + if (uri === undefined) { return 'noDestinationUri'; } + + return URI.isUri(uri) ? uri : undefined; + } catch (ex) { + return undefined; + } + } + + private createPickItems(): ContinueEditSessionItem[] { + const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when)); + return items.sort((item1, item2) => item1.label.localeCompare(item2.label)); + } +} + +class ContinueEditSessionItem implements IQuickPickItem { + constructor( + public readonly label: string, + public readonly command: string, + public readonly description?: string, + public readonly when?: ContextKeyExpression, + ) { } +} + +interface ICommand { + command: string; + group: string; + when: string; +} + +const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'continueEditSession', + jsonSchema: { + description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'), + type: 'array', + items: { + type: 'object', + properties: { + command: { + description: localize('continueEditSessionExtPoint.command', 'Identifier of the command to execute. The command must be declared in the \'commands\'-section and return a URI representing a different environment where the current edit session can be continued.'), + type: 'string' + }, + group: { + description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'), + type: 'string' + }, + when: { + description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'), + type: 'string' + } + }, + required: ['command'] + } + } +}); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index af450bcd68e..3538149f973 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -7,7 +7,7 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Action2, IAction2Options, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { IEditSessionsStorageService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions'; @@ -20,24 +20,17 @@ import { encodeBase64 } from 'vs/base/common/buffer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { EditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/browser/editSessionsStorageService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { getFileNamesMessage, IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { getFileNamesMessage, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ContextKeyExpr, ContextKeyExpression, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtualWorkspace'; -import { Schemas } from 'vs/base/common/network'; -import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; -import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessionsLogService'; import { IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -45,20 +38,20 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews'; import { EditSessionsFileSystemProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsFileSystemProvider'; -import { isNative } from 'vs/base/common/platform'; import { WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { equals } from 'vs/base/common/objects'; import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IOutputService } from 'vs/workbench/services/output/common/output'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { sha1Hex } from 'vs/base/browser/hash'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { ContinueOnPicker, IContinueOnPicker } from 'vs/workbench/contrib/editSessions/browser/continueOnPicker'; registerSingleton(IEditSessionsLogService, EditSessionsLogService, false); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false); +registerSingleton(IContinueOnPicker, ContinueOnPicker, InstantiationType.Delayed); const continueWorkingOnCommand: IAction2Options = { id: '_workbench.editSessions.actions.continueEditSession', @@ -66,12 +59,6 @@ const continueWorkingOnCommand: IAction2Options = { precondition: WorkspaceFolderCountContext.notEqualsTo('0'), f1: true }; -const openLocalFolderCommand: IAction2Options = { - id: '_workbench.editSessions.actions.continueEditSession.openLocalFolder', - title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' }, - category: EDIT_SESSION_SYNC_CATEGORY, - precondition: IsWebContext -}; const showOutputChannelCommand: IAction2Options = { id: 'workbench.editSessions.actions.showOutputChannel', title: { value: localize('show log', 'Show Log'), original: 'Show Log' }, @@ -86,9 +73,6 @@ const queryParamName = 'editSessionId'; const useEditSessionsWithContinueOn = 'workbench.editSessions.continueOn'; export class EditSessionsContribution extends Disposable implements IWorkbenchContribution { - - private continueEditSessionOptions: ContinueEditSessionItem[] = []; - private readonly shouldShowViewsContext: IContextKey; private static APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn'; @@ -110,13 +94,11 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo @IConfigurationService private configurationService: IConfigurationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IEditSessionIdentityService private readonly editSessionIdentityService: IEditSessionIdentityService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @ICommandService private commandService: ICommandService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IFileDialogService private readonly fileDialogService: IFileDialogService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IStorageService private readonly storageService: IStorageService, @IActivityService private readonly activityService: IActivityService, + @IContinueOnPicker private readonly continueOnPicker: IContinueOnPicker, ) { super(); @@ -124,7 +106,6 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerActions(); this.registerViews(); - this.registerContributedEditSessionOptions(); this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService); @@ -237,8 +218,6 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerResumeLatestEditSessionAction(); this.registerStoreLatestEditSessionAction(); - this.registerContinueInLocalFolderAction(); - this.registerShowEditSessionViewAction(); this.registerShowEditSessionOutputChannelAction(); } @@ -292,7 +271,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo const shouldStoreEditSession = await that.shouldContinueOnWithEditSession(); - let uri = workspaceUri ?? await that.pickContinueEditSessionDestination(); + let uri = workspaceUri ?? await that.continueOnPicker.pick(); if (uri === undefined) { return; } // Run the store action to get back a ref @@ -648,162 +627,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo return false; } - - //#region Continue Edit Session extension contribution point - - private registerContributedEditSessionOptions() { - continueEditSessionExtPoint.setHandler(extensions => { - const continueEditSessionOptions: ContinueEditSessionItem[] = []; - for (const extension of extensions) { - if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) { - continue; - } - if (!Array.isArray(extension.value)) { - continue; - } - for (const contribution of extension.value) { - const command = MenuRegistry.getCommand(contribution.command); - if (!command) { - return; - } - - const icon = command.icon; - const title = typeof command.title === 'string' ? command.title : command.title.value; - - continueEditSessionOptions.push(new ContinueEditSessionItem( - ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title, - command.id, - command.source, - ContextKeyExpr.deserialize(contribution.when) - )); - } - } - this.continueEditSessionOptions = continueEditSessionOptions; - }); - } - - private registerContinueInLocalFolderAction(): void { - const that = this; - this._register(registerAction2(class ContinueInLocalFolderAction extends Action2 { - constructor() { - super(openLocalFolderCommand); - } - - async run(accessor: ServicesAccessor): Promise { - const selection = await that.fileDialogService.showOpenDialog({ - title: localize('continueEditSession.openLocalFolder.title', 'Select a local folder to continue your edit session in'), - canSelectFolders: true, - canSelectMany: false, - canSelectFiles: false, - availableFileSystems: [Schemas.file] - }); - - return selection?.length !== 1 ? undefined : URI.from({ - scheme: that.productService.urlProtocol, - authority: Schemas.file, - path: selection[0].path - }); - } - })); - } - - private async pickContinueEditSessionDestination(): Promise { - const quickPick = this.quickInputService.createQuickPick(); - - const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER - ? this.contextService.getWorkspace().folders[0].name - : this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', '); - quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`); - quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working'); - quickPick.items = this.createPickItems(); - - const command = await new Promise((resolve, reject) => { - quickPick.onDidHide(() => resolve(undefined)); - - quickPick.onDidAccept((e) => { - const selection = quickPick.activeItems[0].command; - resolve(selection); - quickPick.hide(); - }); - - quickPick.show(); - }); - - quickPick.dispose(); - - if (command === undefined) { - return undefined; - } - - try { - const uri = await this.commandService.executeCommand(command); - - // Some continue on commands do not return a URI - // to support extensions which want to be in control - // of how the destination is opened - if (uri === undefined) { return 'noDestinationUri'; } - - return URI.isUri(uri) ? uri : undefined; - } catch (ex) { - return undefined; - } - } - - private createPickItems(): ContinueEditSessionItem[] { - const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when)); - - if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) { - items.push(new ContinueEditSessionItem( - '$(folder) ' + localize('continueEditSessionItem.openInLocalFolder.v2', 'Open in Local Folder'), - openLocalFolderCommand.id, - localize('continueEditSessionItem.builtin', 'Built-in') - )); - } - - return items.sort((item1, item2) => item1.label.localeCompare(item2.label)); - } } -class ContinueEditSessionItem implements IQuickPickItem { - constructor( - public readonly label: string, - public readonly command: string, - public readonly description?: string, - public readonly when?: ContextKeyExpression, - ) { } -} - -interface ICommand { - command: string; - group: string; - when: string; -} - -const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint({ - extensionPoint: 'continueEditSession', - jsonSchema: { - description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'), - type: 'array', - items: { - type: 'object', - properties: { - command: { - description: localize('continueEditSessionExtPoint.command', 'Identifier of the command to execute. The command must be declared in the \'commands\'-section and return a URI representing a different environment where the current edit session can be continued.'), - type: 'string' - }, - group: { - description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'), - type: 'string' - }, - when: { - description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'), - type: 'string' - } - }, - required: ['command'] - } - } -}); //#endregion From 125898b774700929692ca54fe450c97756c46ef2 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 7 Oct 2022 14:48:23 -0700 Subject: [PATCH 430/599] testing: ensure discovery happens before "run at cursor" executes (#162980) With this change, when "run at cursor" is executed, we'll: 1. Save the file 2. Forcefully sync tests from the ext host (normally they're on a 300ms throttle) 3. Wait for `busy = false` on all tests whose URIs are a parent or equal to the current file. Fixes #157656 --- .../api/browser/mainThreadTesting.ts | 1 + .../workbench/api/common/extHost.protocol.ts | 2 + src/vs/workbench/api/common/extHostTesting.ts | 11 ++++++ .../testing/browser/testExplorerActions.ts | 26 ++++++++++--- .../testing/browser/testingDecorations.ts | 2 +- .../contrib/testing/common/testService.ts | 38 +++++++++++++++++-- .../contrib/testing/common/testServiceImpl.ts | 16 +++++++- 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts index e21387242da..db044029567 100644 --- a/src/vs/workbench/api/browser/mainThreadTesting.ts +++ b/src/vs/workbench/api/browser/mainThreadTesting.ts @@ -171,6 +171,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh id: controllerId, label, canRefresh, + syncTests: () => this.proxy.$syncTests(), refreshTests: token => this.proxy.$refreshTests(controllerId, token), configureRunProfile: id => this.proxy.$configureRunProfile(controllerId, id), runTests: (reqs, token) => this.proxy.$runControllerTests(reqs, token), diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8ffa6eb5e0d..21c9fb67dbe 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2195,6 +2195,8 @@ export interface ExtHostTestingShape { $configureRunProfile(controllerId: string, configId: number): void; /** Asks the controller to refresh its tests */ $refreshTests(controllerId: string, token: CancellationToken): Promise; + /** Ensures any pending test diffs are flushed */ + $syncTests(): Promise; } export interface ExtHostLocalizationShape { diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index e6f7569b906..9df368705cd 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -173,6 +173,17 @@ export class ExtHostTesting implements ExtHostTestingShape { }, token); } + /** + * @inheritdoc + */ + $syncTests(): Promise { + for (const { collection } of this.controllers.values()) { + collection.flushDiff(); + } + + return Promise.resolve(); + } + /** * @inheritdoc */ diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 8e02aecd2f5..6e1f48fa599 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -40,6 +40,8 @@ import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResu import { expandAndGetTestById, IMainThreadTestCollection, ITestService, testsInFile } from 'vs/workbench/contrib/testing/common/testService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; +import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const category = Categories.Test; @@ -679,9 +681,15 @@ abstract class ExecuteTestAtCursor extends Action2 { * @override */ public async run(accessor: ServicesAccessor) { - const control = accessor.get(IEditorService).activeTextEditorControl; - const position = control?.getPosition(); - const model = control?.getModel(); + const editorService = accessor.get(IEditorService); + const activeEditorPane = editorService.activeEditorPane; + const activeControl = editorService.activeTextEditorControl; + if (!activeEditorPane || !activeControl) { + return; + } + + const position = activeControl?.getPosition(); + const model = activeControl?.getModel(); if (!position || !model || !('uri' in model)) { return; } @@ -689,6 +697,8 @@ abstract class ExecuteTestAtCursor extends Action2 { const testService = accessor.get(ITestService); const profileService = accessor.get(ITestProfileService); const uriIdentityService = accessor.get(IUriIdentityService); + const progressService = accessor.get(IProgressService); + const configurationService = accessor.get(IConfigurationService); let bestNodes: InternalTestItem[] = []; let bestRange: Range | undefined; @@ -696,6 +706,12 @@ abstract class ExecuteTestAtCursor extends Action2 { let bestNodesBefore: InternalTestItem[] = []; let bestRangeBefore: Range | undefined; + const saveBeforeTest = getTestingConfiguration(configurationService, TestingConfigKeys.SaveBeforeTest); + if (saveBeforeTest) { + await editorService.save({ editor: activeEditorPane.input, groupId: activeEditorPane.group.id }); + await testService.syncTests(); + } + // testsInFile will descend in the test tree. We assume that as we go // deeper, ranges get more specific. We'll want to run all tests whose // range is equal to the most specific range we find (see #133519) @@ -703,8 +719,8 @@ abstract class ExecuteTestAtCursor extends Action2 { // If we don't find any test whose range contains the position, we pick // the closest one before the position. Again, if we find several tests // whose range is equal to the closest one, we run them all. - await showDiscoveringWhile(accessor.get(IProgressService), (async () => { - for await (const test of testsInFile(testService.collection, uriIdentityService, model.uri)) { + await showDiscoveringWhile(progressService, (async () => { + for await (const test of testsInFile(testService, uriIdentityService, model.uri)) { if (!test.item.range || !(profileService.capabilitiesForTest(test) & this.group)) { continue; } diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 3aaff497077..9d11b2304fa 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -414,7 +414,7 @@ export class TestingDecorations extends Disposable implements IEditorContributio this.decorations.syncDecorations(uri); (async () => { - for await (const _test of testsInFile(this.testService.collection, this.uriIdentityService, uri)) { + for await (const _test of testsInFile(this.testService, this.uriIdentityService, uri, false)) { // consume the iterator so that all tests in the file get expanded. Or // at least until the URI changes. If new items are requested, changes // will be trigged in the `onDidProcessDiff` callback. diff --git a/src/vs/workbench/contrib/testing/common/testService.ts b/src/vs/workbench/contrib/testing/common/testService.ts index 5aeb3815ed6..9da1e073307 100644 --- a/src/vs/workbench/contrib/testing/common/testService.ts +++ b/src/vs/workbench/contrib/testing/common/testService.ts @@ -23,6 +23,7 @@ export interface IMainThreadTestController { readonly id: string; readonly label: IObservableValue; readonly canRefresh: IObservableValue; + syncTests(token: CancellationToken): Promise; refreshTests(token: CancellationToken): Promise; configureRunProfile(profileId: number): void; expandTest(id: string, levels: number): Promise; @@ -156,12 +157,30 @@ export const getAllTestsInHierarchy = async (collection: IMainThreadTestCollecti ]).finally(() => l?.dispose()); }; +/** + * Waits for the test to no longer be in the "busy" state. + */ +export const waitForTestToBeIdle = (testService: ITestService, test: IncrementalTestCollectionItem) => { + if (!test.item.busy) { + return; + } + + return new Promise(resolve => { + const l = testService.onDidProcessDiff(() => { + if (testService.collection.getNodeById(test.item.extId)?.item.busy !== true) { + resolve(); // removed, or no longer busy + l.dispose(); + } + }); + }); +}; + /** * Iterator that expands to and iterates through tests in the file. Iterates * in strictly descending order. */ -export const testsInFile = async function* (collection: IMainThreadTestCollection, ident: IUriIdentityService, uri: URI): AsyncIterable { - for (const test of collection.all) { +export const testsInFile = async function* (testService: ITestService, ident: IUriIdentityService, uri: URI, waitForIdle = true): AsyncIterable { + for (const test of testService.collection.all) { if (!test.item.uri) { continue; } @@ -170,8 +189,13 @@ export const testsInFile = async function* (collection: IMainThreadTestCollectio yield test; } - if (ident.extUri.isEqualOrParent(uri, test.item.uri) && test.expand === TestItemExpandState.Expandable) { - await collection.expand(test.item.extId, 1); + if (ident.extUri.isEqualOrParent(uri, test.item.uri)) { + if (test.expand === TestItemExpandState.Expandable) { + await testService.collection.expand(test.item.extId, 1); + } + if (waitForIdle) { + await waitForTestToBeIdle(testService, test); + } } } }; @@ -262,6 +286,12 @@ export interface ITestService { */ runResolvedTests(req: ResolvedTestRunRequest, token?: CancellationToken): Promise; + /** + * Ensures the test diff from the remote ext host is flushed and waits for + * any "busy" tests to become idle before resolving. + */ + syncTests(): Promise; + /** * Cancels an ongoing test run by its ID, or all runs if no ID is given. */ diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 3b107fabf85..0467fa176c7 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -238,6 +238,18 @@ export class TestService extends Disposable implements ITestService { return this.testControllers.get(id); } + /** + * @inheritdoc + */ + public async syncTests(): Promise { + const cts = new CancellationTokenSource(); + try { + await Promise.all([...this.testControllers.values()].map(c => c.syncTests(cts.token))); + } finally { + cts.dispose(true); + } + } + /** * @inheritdoc */ @@ -255,7 +267,7 @@ export class TestService extends Disposable implements ITestService { } finally { this.testRefreshCancellations.delete(cts); this.isRefreshingTests.set(this.testRefreshCancellations.size > 0); - cts.dispose(); + cts.dispose(true); } } @@ -305,7 +317,7 @@ export class TestService extends Disposable implements ITestService { if (req.isUiTriggered === false) { return; } - const saveBeforeTest: boolean = getTestingConfiguration(this.configurationService, TestingConfigKeys.SaveBeforeTest); + const saveBeforeTest = getTestingConfiguration(this.configurationService, TestingConfigKeys.SaveBeforeTest); if (saveBeforeTest) { await editorService.saveAll(); } From 1d456337956ee8323db2f2f6d5a32c9dd28ee192 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 7 Oct 2022 15:28:36 -0700 Subject: [PATCH 431/599] Add DisposableMap helper (#163006) Adds `DisposableMap` to help manage the lifecycle of maps of disposable values. This is useful for a few reasons: - `DisposableMap` is itself disposable, so you can use it with `_register` or add it to a `DisposableStore` - The implementation of `set` on `DisposableMap` prevents leaking values on override - The `delete` implementation also makes sure it disposes of the deleted values --- src/vs/base/common/lifecycle.ts | 48 +++++++++++++++++++ .../api/browser/mainThreadCommands.ts | 22 ++++----- .../api/browser/mainThreadComments.ts | 12 +---- .../api/browser/mainThreadCustomEditors.ts | 25 ++++------ .../mainThreadDocumentContentProviders.ts | 12 ++--- .../browser/mainThreadDocumentsAndEditors.ts | 12 ++--- .../api/browser/mainThreadFileSystem.ts | 21 ++++---- .../api/browser/mainThreadLabelService.ts | 19 ++++---- .../api/browser/mainThreadLanguageFeatures.ts | 19 ++------ .../api/browser/mainThreadLanguages.ts | 10 ++-- .../mainThreadNotebookDocumentsAndEditors.ts | 8 ++-- .../api/browser/mainThreadNotebookKernels.ts | 8 ++-- .../api/browser/mainThreadWebviewPanels.ts | 22 ++------- 13 files changed, 110 insertions(+), 128 deletions(-) diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index e36513cfbfc..35dae84378c 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -443,3 +443,51 @@ export function disposeOnReturn(fn: (store: DisposableStore) => void): void { store.dispose(); } } + +/** + * A map the manages the lifecycle of the values that it stores. + */ +export class DisposableMap implements IDisposable { + + private readonly _store = new Map(); + private _isDisposed = false; + + dispose() { + this.clearAndDisposeAll(); + this._isDisposed = true; + } + + clearAndDisposeAll() { + dispose(this._store.values()); + this._store.clear(); + } + + has(key: K): boolean { + return this._store.has(key); + } + + get(key: K): V | undefined { + return this._store.get(key); + } + + set(key: K, value: V, skipDisposeOnOverwrite = false): void { + if (this._isDisposed) { + console.warn(new Error('Trying to add a disposable to a DisposableMap that has already been disposed of. The added object will be leaked!').stack); + } + + if (!skipDisposeOnOverwrite) { + this._store.get(key)?.dispose(); + } + + this._store.set(key, value); + } + + deleteAndDispose(key: K): void { + this._store.get(key)?.dispose(); + this._store.delete(key); + } + + [Symbol.iterator](): IterableIterator<[K, V]> { + return this._store[Symbol.iterator](); + } +} diff --git a/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index 0321d2202f5..175c1faa6fa 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext } from '../common/extHost.protocol'; -import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; +import { DisposableMap, IDisposable } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; +import { CommandsRegistry, ICommandHandlerDescription, ICommandService } from 'vs/platform/commands/common/commands'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { SerializableObjectWithBuffers, Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier'; +import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; +import { Dto, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier'; +import { ExtHostCommandsShape, ExtHostContext, MainContext, MainThreadCommandsShape } from '../common/extHost.protocol'; @extHostNamedCustomer(MainContext.MainThreadCommands) export class MainThreadCommands implements MainThreadCommandsShape { - private readonly _commandRegistrations = new Map(); + private readonly _commandRegistrations = new DisposableMap(); private readonly _generateCommandsDocumentationRegistration: IDisposable; private readonly _proxy: ExtHostCommandsShape; @@ -30,9 +30,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { } dispose() { - dispose(this._commandRegistrations.values()); - this._commandRegistrations.clear(); - + this._commandRegistrations.dispose(); this._generateCommandsDocumentationRegistration.dispose(); } @@ -67,11 +65,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { } $unregisterCommand(id: string): void { - const command = this._commandRegistrations.get(id); - if (command) { - command.dispose(); - this._commandRegistrations.delete(id); - } + this._commandRegistrations.deleteAndDispose(id); } $fireCommandActivationEvent(id: string): void { diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index fa493d3fbb5..77fc0e85e72 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -5,7 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -465,8 +465,7 @@ const commentsViewIcon = registerIcon('comments-view-icon', Codicon.commentDiscu @extHostNamedCustomer(MainContext.MainThreadComments) export class MainThreadComments extends Disposable implements MainThreadCommentsShape { private readonly _proxy: ExtHostCommentsShape; - private _documentProviders = new Map(); - private _workspaceProviders = new Map(); + private _handlers = new Map(); private _commentControllers = new Map(); @@ -671,11 +670,4 @@ export class MainThreadComments extends Disposable implements MainThreadComments } return this._handlers.get(handle)!; } - override dispose(): void { - super.dispose(); - this._workspaceProviders.forEach(value => dispose(value)); - this._workspaceProviders.clear(); - this._documentProviders.forEach(value => dispose(value)); - this._documentProviders.clear(); - } } diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 3be47943f1a..7e4f01b78f4 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -9,7 +9,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { isCancellationError, onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableMap, DisposableStore, IReference } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { basename } from 'vs/base/common/path'; import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resources'; @@ -24,7 +24,6 @@ import { MainThreadWebviewPanels } from 'vs/workbench/api/browser/mainThreadWebv import { MainThreadWebviews, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor'; -import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; import { CustomDocumentBackupData } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory'; import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; @@ -32,15 +31,16 @@ import { CustomTextEditorModel } from 'vs/workbench/contrib/customEditor/common/ import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy'; +import { IWorkingCopy, IWorkingCopyBackup, IWorkingCopySaveEvent, NO_TYPE_ID, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { IWorkingCopy, IWorkingCopyBackup, IWorkingCopySaveEvent, NO_TYPE_ID, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy'; -import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy'; -import { IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; const enum CustomEditorModelType { Custom, @@ -51,7 +51,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc private readonly _proxyCustomEditors: extHostProtocol.ExtHostCustomEditorsShape; - private readonly _editorProviders = new Map(); + private readonly _editorProviders = this._register(new DisposableMap()); private readonly _editorRenameBackups = new Map(); @@ -99,13 +99,6 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc this._register(workingCopyFileService.onWillRunWorkingCopyFileOperation(async e => this.onWillRunWorkingCopyFileOperation(e))); } - override dispose() { - super.dispose(); - - dispose(this._editorProviders.values()); - this._editorProviders.clear(); - } - public $registerTextEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: extHostProtocol.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities, serializeBuffersForPostMessage: boolean): void { this.registerEditorProvider(CustomEditorModelType.Text, reviveWebviewExtension(extensionData), viewType, options, capabilities, true, serializeBuffersForPostMessage); } @@ -211,13 +204,11 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc } public $unregisterEditorProvider(viewType: string): void { - const provider = this._editorProviders.get(viewType); - if (!provider) { + if (!this._editorProviders.has(viewType)) { throw new Error(`No provider for ${viewType} registered`); } - provider.dispose(); - this._editorProviders.delete(viewType); + this._editorProviders.deleteAndDispose(viewType); this._customEditorService.models.disposeAllModelsForView(viewType); } diff --git a/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts b/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts index 47e1f32ed47..a29f2f0e245 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose, DisposableMap } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Range } from 'vs/editor/common/core/range'; @@ -20,7 +20,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; @extHostNamedCustomer(MainContext.MainThreadDocumentContentProviders) export class MainThreadDocumentContentProviders implements MainThreadDocumentContentProvidersShape { - private readonly _resourceContentProvider = new Map(); + private readonly _resourceContentProvider = new DisposableMap(); private readonly _pendingUpdate = new Map(); private readonly _proxy: ExtHostDocumentContentProvidersShape; @@ -35,7 +35,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon } dispose(): void { - dispose(this._resourceContentProvider.values()); + this._resourceContentProvider.dispose(); dispose(this._pendingUpdate.values()); } @@ -56,11 +56,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon } $unregisterTextContentProvider(handle: number): void { - const registration = this._resourceContentProvider.get(handle); - if (registration) { - registration.dispose(); - this._resourceContentProvider.delete(handle); - } + this._resourceContentProvider.deleteAndDispose(handle); } $onVirtualDocumentChange(uri: UriComponents, value: string): void { diff --git a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts index dbc22090414..dc20f23f976 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { combinedDisposable, DisposableStore, DisposableMap } from 'vs/base/common/lifecycle'; import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditor } from 'vs/editor/common/editorCommon'; @@ -113,7 +113,7 @@ const enum ActiveEditorOrder { class MainThreadDocumentAndEditorStateComputer { private readonly _toDispose = new DisposableStore(); - private _toDisposeOnEditorRemove = new Map(); + private readonly _toDisposeOnEditorRemove = new DisposableMap(); private _currentState?: DocumentAndEditorState; private _activeEditorOrder: ActiveEditorOrder = ActiveEditorOrder.Editor; @@ -141,6 +141,7 @@ class MainThreadDocumentAndEditorStateComputer { dispose(): void { this._toDispose.dispose(); + this._toDisposeOnEditorRemove.dispose(); } private _onDidAddEditor(e: ICodeEditor): void { @@ -153,10 +154,9 @@ class MainThreadDocumentAndEditorStateComputer { } private _onDidRemoveEditor(e: ICodeEditor): void { - const sub = this._toDisposeOnEditorRemove.get(e.getId()); - if (sub) { - this._toDisposeOnEditorRemove.delete(e.getId()); - sub.dispose(); + const id = e.getId(); + if (this._toDisposeOnEditorRemove.has(id)) { + this._toDisposeOnEditorRemove.deleteAndDispose(id); this._updateState(); } } diff --git a/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts index 02e75eae05e..93f1ec92983 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, DisposableStore, DisposableMap } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IFileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, IFileOverwriteOptions, IFileDeleteOptions, IFileOpenOptions, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission, toFileSystemProviderErrorCode, IFilesConfiguration, IFileStatWithPartialMetadata, IFileStat } from 'vs/platform/files/common/files'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; @@ -22,9 +22,9 @@ import { rtrim } from 'vs/base/common/strings'; export class MainThreadFileSystem implements MainThreadFileSystemShape { private readonly _proxy: ExtHostFileSystemShape; - private readonly _fileProvider = new Map(); + private readonly _fileProvider = new DisposableMap(); private readonly _disposables = new DisposableStore(); - private readonly _watches = new Map(); + private readonly _watches = new DisposableMap(); constructor( extHostContext: IExtHostContext, @@ -46,9 +46,8 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { dispose(): void { this._disposables.dispose(); - dispose(this._fileProvider.values()); - dispose(this._watches.values()); - this._fileProvider.clear(); + this._fileProvider.dispose(); + this._watches.dispose(); } async $registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): Promise { @@ -56,8 +55,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $unregisterProvider(handle: number): void { - this._fileProvider.get(handle)?.dispose(); - this._fileProvider.delete(handle); + this._fileProvider.deleteAndDispose(handle); } $onFileSystemChange(handle: number, changes: IFileChangeDto[]): void { @@ -254,12 +252,9 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $unwatch(session: number): void { - const subscription = this._watches.get(session); - if (subscription) { + if (this._watches.has(session)) { this._logService.trace(`MainThreadFileSystem#$unwatch(): request to stop watching (session: ${session})`); - - subscription.dispose(); - this._watches.delete(session); + this._watches.deleteAndDispose(session); } } } diff --git a/src/vs/workbench/api/browser/mainThreadLabelService.ts b/src/vs/workbench/api/browser/mainThreadLabelService.ts index b284ef951c4..8ade55d44e5 100644 --- a/src/vs/workbench/api/browser/mainThreadLabelService.ts +++ b/src/vs/workbench/api/browser/mainThreadLabelService.ts @@ -3,20 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; +import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label'; import { MainContext, MainThreadLabelServiceShape } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; -import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @extHostNamedCustomer(MainContext.MainThreadLabelService) -export class MainThreadLabelService implements MainThreadLabelServiceShape { +export class MainThreadLabelService extends Disposable implements MainThreadLabelServiceShape { - private readonly _resourceLabelFormatters = new Map(); + private readonly _resourceLabelFormatters = this._register(new DisposableMap()); constructor( _: IExtHostContext, @ILabelService private readonly _labelService: ILabelService - ) { } + ) { + super(); + } $registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void { // Dynamicily registered formatters should have priority over those contributed via package.json @@ -26,11 +28,6 @@ export class MainThreadLabelService implements MainThreadLabelServiceShape { } $unregisterResourceLabelFormatter(handle: number): void { - dispose(this._resourceLabelFormatters.get(handle)); - this._resourceLabelFormatters.delete(handle); - } - - dispose(): void { - // noop + this._resourceLabelFormatters.deleteAndDispose(handle); } } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 4fc05b82242..e432965c8db 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -8,7 +8,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { createStringDataTransferItem, VSDataTransfer } from 'vs/base/common/dataTransfer'; import { CancellationError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { combinedDisposable, Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, DisposableMap, toDisposable } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; import { mixin } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; @@ -38,7 +38,7 @@ import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, IC export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape { private readonly _proxy: ExtHostLanguageFeaturesShape; - private readonly _registrations = new Map(); + private readonly _registrations = this._register(new DisposableMap()); constructor( extHostContext: IExtHostContext, @@ -80,21 +80,8 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread } } - override dispose(): void { - for (const registration of this._registrations.values()) { - registration.dispose(); - } - this._registrations.clear(); - - super.dispose(); - } - $unregister(handle: number): void { - const registration = this._registrations.get(handle); - if (registration) { - registration.dispose(); - this._registrations.delete(handle); - } + this._registrations.deleteAndDispose(handle); } //#region --- revive functions diff --git a/src/vs/workbench/api/browser/mainThreadLanguages.ts b/src/vs/workbench/api/browser/mainThreadLanguages.ts index fffdbc7f4db..c532913bccd 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguages.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguages.ts @@ -13,7 +13,7 @@ import { IRange, Range } from 'vs/editor/common/core/range'; import { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ILanguageStatus, ILanguageStatusService } from 'vs/workbench/services/languageStatus/common/languageStatusService'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableMap, DisposableStore } from 'vs/base/common/lifecycle'; @extHostNamedCustomer(MainContext.MainThreadLanguages) export class MainThreadLanguages implements MainThreadLanguagesShape { @@ -21,7 +21,7 @@ export class MainThreadLanguages implements MainThreadLanguagesShape { private readonly _disposables = new DisposableStore(); private readonly _proxy: ExtHostLanguagesShape; - private readonly _status = new Map(); + private readonly _status = new DisposableMap(); constructor( _extHostContext: IExtHostContext, @@ -40,11 +40,7 @@ export class MainThreadLanguages implements MainThreadLanguagesShape { dispose(): void { this._disposables.dispose(); - - for (const status of this._status.values()) { - status.dispose(); - } - this._status.clear(); + this._status.dispose(); } async $changeLanguage(resource: UriComponents, languageId: string): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts index 1c649d6f669..4207532513f 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { diffMaps, diffSets } from 'vs/base/common/collections'; -import { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, DisposableStore, DisposableMap } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MainThreadNotebookDocuments } from 'vs/workbench/api/browser/mainThreadNotebookDocuments'; @@ -85,7 +85,7 @@ export class MainThreadNotebooksAndEditors { private readonly _proxy: Pick; private readonly _disposables = new DisposableStore(); - private readonly _editorListeners = new Map(); + private readonly _editorListeners = new DisposableMap(); private _currentState?: NotebookAndEditorState; @@ -121,6 +121,7 @@ export class MainThreadNotebooksAndEditors { this._mainThreadNotebooks.dispose(); this._mainThreadEditors.dispose(); this._disposables.dispose(); + this._editorListeners.dispose(); } private _handleEditorAdd(editor: INotebookEditor): void { @@ -132,8 +133,7 @@ export class MainThreadNotebooksAndEditors { } private _handleEditorRemove(editor: INotebookEditor): void { - this._editorListeners.get(editor.getId())?.dispose(); - this._editorListeners.delete(editor.getId()); + this._editorListeners.deleteAndDispose(editor.getId()); this._updateState(); } diff --git a/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts index 30702b46cd8..e975e931400 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { combinedDisposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -104,7 +104,7 @@ abstract class MainThreadKernel implements INotebookKernel { @extHostNamedCustomer(MainContext.MainThreadNotebookKernels) export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape { - private readonly _editors = new Map(); + private readonly _editors = new DisposableMap(); private readonly _disposables = new DisposableStore(); private readonly _kernels = new Map(); @@ -143,6 +143,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape for (const [, registration] of this._kernels.values()) { registration.dispose(); } + this._editors.dispose(); } // --- kernel ipc @@ -168,8 +169,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape } private _onEditorRemove(editor: INotebookEditor) { - this._editors.get(editor)?.dispose(); - this._editors.delete(editor); + this._editors.deleteAndDispose(editor); } async $postMessage(handle: number, editorId: string | undefined, message: any): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index c3a2a739715..d33c3fba499 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { onUnexpectedError } from 'vs/base/common/errors'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -83,9 +83,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc private readonly _webviewInputs = new WebviewInputStore(); - private readonly _editorProviders = new Map(); - - private readonly _revivers = new Map(); + private readonly _revivers = this._register(new DisposableMap()); constructor( context: IExtHostContext, @@ -127,16 +125,6 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc })); } - override dispose() { - super.dispose(); - - dispose(this._editorProviders.values()); - this._editorProviders.clear(); - - dispose(this._revivers.values()); - this._revivers.clear(); - } - public get webviewInputs(): Iterable { return this._webviewInputs; } public addWebviewInput(handle: extHostProtocol.WebviewHandle, input: WebviewInput, options: { serializeBuffersForPostMessage: boolean }): void { @@ -295,13 +283,11 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc } public $unregisterSerializer(viewType: string): void { - const reviver = this._revivers.get(viewType); - if (!reviver) { + if (!this._revivers.has(viewType)) { throw new Error(`No reviver for ${viewType} registered`); } - reviver.dispose(); - this._revivers.delete(viewType); + this._revivers.deleteAndDispose(viewType); } private updateWebviewViewStates(activeEditorInput: EditorInput | undefined) { From b25b3e899908e9e37d310ba4df9fdaa9cb7114d3 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Fri, 7 Oct 2022 15:35:06 -0700 Subject: [PATCH 432/599] Lightly modernize quick pick styles (#163011) * Add padding to list border radius to selected items * More padding updates --- .../quickinput/browser/media/quickInput.css | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/media/quickInput.css b/src/vs/base/parts/quickinput/browser/media/quickInput.css index 891ab4f1e1f..46834baf60a 100644 --- a/src/vs/base/parts/quickinput/browser/media/quickInput.css +++ b/src/vs/base/parts/quickinput/browser/media/quickInput.css @@ -57,7 +57,7 @@ .quick-input-header { display: flex; - padding: 8px 8px 0px 8px; + padding: 8px 6px 0px 6px; margin-bottom: -2px; } @@ -150,12 +150,13 @@ .quick-input-list { line-height: 22px; - margin-top: 8px; - padding: 0px 1px 1px 1px; + margin-top: 6px; + padding: 1px; } .quick-input-widget.hidden-input .quick-input-list { - margin-top: 0; /* reduce margins when input box hidden */ + margin-top: 4px; /* reduce margins when input box hidden */ + padding-bottom: 4px; } .quick-input-list .monaco-list { @@ -163,6 +164,10 @@ max-height: calc(20 * 22px); } +.quick-input-list .monaco-scrollable-element { + padding: 0px 5px; +} + .quick-input-list .quick-input-list-entry { box-sizing: border-box; overflow: hidden; @@ -176,6 +181,10 @@ border-top-style: solid; } +.quick-input-list .monaco-list-row { + border-radius: 3px; +} + .quick-input-list .monaco-list-row[data-index="0"] .quick-input-list-entry.quick-input-list-separator-border { border-top-style: none; } @@ -247,7 +256,7 @@ } .quick-input-list .quick-input-list-entry .quick-input-list-separator { - margin-right: 8px; /* separate from keybindings or actions */ + margin-right: 4px; /* separate from keybindings or actions */ } .quick-input-list .quick-input-list-entry-action-bar { From a8e05690393a8b5dd9eb099c67c5937629002b25 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Oct 2022 15:39:48 -0700 Subject: [PATCH 433/599] Refactor DebugHover so it stays properly in place (#163012) * Refactor DebugHover so it stays properly in place Fix #151019 * Remove Promise.resolve --- .../debug/browser/debugEditorActions.ts | 42 ++-- .../debug/browser/debugEditorContribution.ts | 19 +- .../contrib/debug/browser/debugHover.ts | 229 +++++++++++------- .../debug/browser/media/debugHover.css | 1 - .../workbench/contrib/debug/common/debug.ts | 4 +- 5 files changed, 173 insertions(+), 122 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 9687e574a1a..021e9b52295 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -3,29 +3,28 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; -import { Range } from 'vs/editor/common/core/range'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { registerEditorAction, EditorAction, IActionOptions, EditorAction2 } from 'vs/editor/browser/editorExtensions'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, REPL_VIEW_ID, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, WATCH_VIEW_ID, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_EXCEPTION_WIDGET_VISIBLE, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_CALLSTACK_ITEM_TYPE, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug'; +import { getDomNodePagePosition } from 'vs/base/browser/dom'; +import { Action } from 'vs/base/common/actions'; +import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView'; +import { EditorAction, EditorAction2, IActionOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions'; +import { Position } from 'vs/editor/common/core/position'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; +import * as nls from 'vs/nls'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { PanelFocusContext } from 'vs/workbench/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { registerAction2, MenuId, Action2 } from 'vs/platform/actions/common/actions'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView'; +import { BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_EXCEPTION_WIDGET_VISIBLE, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_IN_DEBUG_MODE, CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IDebugConfiguration, IDebugEditorContribution, IDebugService, REPL_VIEW_ID, WATCH_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug'; import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; -import { getDomNodePagePosition } from 'vs/base/browser/dom'; -import { Position } from 'vs/editor/common/core/position'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { Action } from 'vs/base/common/actions'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; class ToggleBreakpointAction extends EditorAction { constructor() { @@ -321,13 +320,8 @@ class ShowDebugHoverAction extends EditorAction { if (!position || !editor.hasModel()) { return; } - const word = editor.getModel().getWordAtPosition(position); - if (!word) { - return; - } - const range = new Range(position.lineNumber, position.column, position.lineNumber, word.endColumn); - return editor.getContribution(EDITOR_CONTRIBUTION_ID)?.showHover(range, true); + return editor.getContribution(EDITOR_CONTRIBUTION_ID)?.showHover(position, true); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 251241bb2d5..249252a170f 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -213,7 +213,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { private toDispose: IDisposable[]; private hoverWidget: DebugHoverWidget; - private hoverRange: Range | null = null; + private hoverPosition: Position | null = null; private mouseDown = false; private exceptionWidgetVisible: IContextKey; @@ -318,10 +318,11 @@ export class DebugEditorContribution implements IDebugEditorContribution { const debugHoverWasVisible = this.hoverWidget.isVisible(); this.hoverWidget.hide(); this.enableEditorHover(); - if (debugHoverWasVisible && this.hoverRange) { + if (debugHoverWasVisible && this.hoverPosition) { // If the debug hover was visible immediately show the editor hover for the alt transition to be smooth const hoverController = this.editor.getContribution(ModesHoverController.ID); - hoverController?.showContentHover(this.hoverRange, HoverStartMode.Immediate, false); + const range = new Range(this.hoverPosition.lineNumber, this.hoverPosition.column, this.hoverPosition.lineNumber, this.hoverPosition.column); + hoverController?.showContentHover(range, HoverStartMode.Immediate, false); } const onKeyUp = new DomEmitter(document, 'keyup'); @@ -365,11 +366,11 @@ export class DebugEditorContribution implements IDebugEditorContribution { } } - async showHover(range: Range, focus: boolean): Promise { + async showHover(position: Position, focus: boolean): Promise { const sf = this.debugService.getViewModel().focusedStackFrame; const model = this.editor.getModel(); if (sf && model && this.uriIdentityService.extUri.isEqual(sf.source.uri, model.uri) && !this.altPressed) { - return this.hoverWidget.showAt(range, focus); + return this.hoverWidget.showAt(position, focus); } } @@ -391,8 +392,8 @@ export class DebugEditorContribution implements IDebugEditorContribution { private get showHoverScheduler(): RunOnceScheduler { const hoverOption = this.editor.getOption(EditorOption.hover); const scheduler = new RunOnceScheduler(() => { - if (this.hoverRange) { - this.showHover(this.hoverRange, false); + if (this.hoverPosition) { + this.showHover(this.hoverPosition, false); } }, hoverOption.delay * 2); this.toDispose.push(scheduler); @@ -443,8 +444,8 @@ export class DebugEditorContribution implements IDebugEditorContribution { return; } if (target.type === MouseTargetType.CONTENT_TEXT) { - if (target.range && !target.range.equalsRange(this.hoverRange)) { - this.hoverRange = target.range; + if (target.position && !Position.equals(target.position, this.hoverPosition)) { + this.hoverPosition = target.position; this.hideHoverScheduler.cancel(); this.showHoverScheduler.schedule(); } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 6308c2b6c5b..40afc3e611e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -3,43 +3,44 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as lifecycle from 'vs/base/common/lifecycle'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; +import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; +import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; +import { coalesce } from 'vs/base/common/arrays'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import * as lifecycle from 'vs/base/common/lifecycle'; +import { isMacintosh } from 'vs/base/common/platform'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; -import { Range, IRange } from 'vs/editor/common/core/range'; -import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; +import { IRange, Range } from 'vs/editor/common/core/range'; +import { ITextModel } from 'vs/editor/common/model'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import * as nls from 'vs/nls'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IDebugService, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug'; -import { Expression, Variable } from 'vs/workbench/contrib/debug/common/debugModel'; -import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView'; -import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; +import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils'; -import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; -import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; -import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; -import { coalesce } from 'vs/base/common/arrays'; -import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; -import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { isMacintosh } from 'vs/base/common/platform'; +import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; -import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView'; +import { IDebugService, IDebugSession, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug'; +import { Expression, Variable } from 'vs/workbench/contrib/debug/common/debugModel'; +import { getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils'; const $ = dom.$; async function doFindExpression(container: IExpressionContainer, namesToFind: string[]): Promise { if (!container) { - return Promise.resolve(null); + return null; } const children = await container.getChildren(); @@ -69,7 +70,7 @@ export class DebugHoverWidget implements IContentWidget { static readonly ID = 'debug.hoverWidget'; // editor.IContentWidget.allowEditorOverflow - allowEditorOverflow = true; + readonly allowEditorOverflow = true; private _isVisible: boolean; private showCancellationSource?: CancellationTokenSource; @@ -84,19 +85,20 @@ export class DebugHoverWidget implements IContentWidget { private treeContainer!: HTMLElement; private toDispose: lifecycle.IDisposable[]; private scrollbar!: DomScrollableElement; + private debugHoverComputer: DebugHoverComputer; constructor( private editor: ICodeEditor, @IDebugService private readonly debugService: IDebugService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IThemeService private readonly themeService: IThemeService, - @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, + @IThemeService private readonly themeService: IThemeService ) { this.toDispose = []; this._isVisible = false; this.showAtPosition = null; this.positionPreference = [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW]; + this.debugHoverComputer = this.instantiationService.createInstance(DebugHoverComputer, this.editor); } private create(): void { @@ -193,81 +195,38 @@ export class DebugHoverWidget implements IContentWidget { return this.domNode; } - async showAt(range: Range, focus: boolean): Promise { + async showAt(position: Position, focus: boolean): Promise { this.showCancellationSource?.cancel(); const cancellationSource = this.showCancellationSource = new CancellationTokenSource(); const session = this.debugService.getViewModel().focusedSession; if (!session || !this.editor.hasModel()) { - return Promise.resolve(this.hide()); + this.hide(); + return; } - const model = this.editor.getModel(); - const pos = range.getStartPosition(); - - let rng: IRange | undefined = undefined; - let matchingExpression: string | undefined; - - if (this.languageFeaturesService.evaluatableExpressionProvider.has(model)) { - const supports = this.languageFeaturesService.evaluatableExpressionProvider.ordered(model); - - const promises = supports.map(support => { - return Promise.resolve(support.provideEvaluatableExpression(model, pos, cancellationSource.token)).then(expression => { - return expression; - }, err => { - //onUnexpectedExternalError(err); - return undefined; - }); - }); - - const results = await Promise.all(promises).then(coalesce); - if (results.length > 0) { - matchingExpression = results[0].expression; - rng = results[0].range; - - if (!matchingExpression) { - const lineContent = model.getLineContent(pos.lineNumber); - matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn - 1); - } - } - - } else { // old one-size-fits-all strategy - const lineContent = model.getLineContent(pos.lineNumber); - const { start, end } = getExactExpressionStartAndEnd(lineContent, range.startColumn, range.endColumn); - - // use regex to extract the sub-expression #9821 - matchingExpression = lineContent.substring(start - 1, end); - rng = new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length); + const result = await this.debugHoverComputer.compute(position, cancellationSource.token); + if (this.isVisible() && !result.rangeChanged) { + return; } - if (!matchingExpression) { - return Promise.resolve(this.hide()); - } - - let expression; - if (session.capabilities.supportsEvaluateForHovers) { - expression = new Expression(matchingExpression); - await expression.evaluate(session, this.debugService.getViewModel().focusedStackFrame, 'hover'); - } else { - const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; - if (focusedStackFrame) { - expression = await findExpressionInStackFrame(focusedStackFrame, coalesce(matchingExpression.split('.').map(word => word.trim()))); - } + if (!result.range || cancellationSource.token.isCancellationRequested) { + this.hide(); + return; } + const expression = await this.debugHoverComputer.evaluate(session); if (cancellationSource.token.isCancellationRequested || !expression || (expression instanceof Expression && !expression.available)) { this.hide(); return; } - if (rng) { - this.highlightDecorations.set([{ - range: rng, - options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS - }]); - } + this.highlightDecorations.set([{ + range: result.range, + options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS + }]); - return this.doShow(pos, expression, focus); + return this.doShow(result.range.getStartPosition(), expression, focus); } private static readonly _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({ @@ -298,7 +257,7 @@ export class DebugHoverWidget implements IContentWidget { this.valueContainer.focus(); } - return Promise.resolve(undefined); + return undefined; } this.valueContainer.hidden = true; @@ -396,3 +355,101 @@ class DebugHoverDelegate implements IListVirtualDelegate { return VariablesRenderer.ID; } } + +interface IDebugHoverComputeResult { + rangeChanged: boolean; + range?: Range; +} + +class DebugHoverComputer { + private _currentRange: Range | undefined; + private _currentExpression: string | undefined; + + constructor( + private editor: ICodeEditor, + @IDebugService private readonly debugService: IDebugService, + @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, + ) { } + + public async compute(position: Position, token: CancellationToken): Promise { + const session = this.debugService.getViewModel().focusedSession; + + if (!session || !this.editor.hasModel()) { + return { rangeChanged: false }; + } + + const model = this.editor.getModel(); + + const result = await this.doCompute(model, position, token); + if (!result) { + return { rangeChanged: false }; + } + + const { range, matchingExpression } = result; + const rangeChanged = this._currentRange ? + !this._currentRange.equalsRange(range) : + true; + this._currentExpression = matchingExpression; + this._currentRange = Range.lift(range); + return { rangeChanged, range: this._currentRange }; + } + + private async doCompute(model: ITextModel, position: Position, token: CancellationToken): Promise<{ range: IRange; matchingExpression: string } | null> { + if (this.languageFeaturesService.evaluatableExpressionProvider.has(model)) { + const supports = this.languageFeaturesService.evaluatableExpressionProvider.ordered(model); + + const results = coalesce(await Promise.all(supports.map(async support => { + try { + return await support.provideEvaluatableExpression(model, position, token); + } catch (err) { + return undefined; + } + }))); + + if (results.length > 0) { + let matchingExpression = results[0].expression; + const range = results[0].range; + + if (!matchingExpression) { + const lineContent = model.getLineContent(position.lineNumber); + matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1); + } + + return { range, matchingExpression }; + } + } else { // old one-size-fits-all strategy + const lineContent = model.getLineContent(position.lineNumber); + const { start, end } = getExactExpressionStartAndEnd(lineContent, position.column, position.column); + + // use regex to extract the sub-expression #9821 + const matchingExpression = lineContent.substring(start - 1, end); + return { + matchingExpression, + range: new Range(position.lineNumber, start, position.lineNumber, start + matchingExpression.length) + }; + } + + return null; + } + + async evaluate(session: IDebugSession): Promise { + if (!this._currentExpression) { + throw new Error('No expression to evaluate'); + } + + if (session.capabilities.supportsEvaluateForHovers) { + const expression = new Expression(this._currentExpression); + await expression.evaluate(session, this.debugService.getViewModel().focusedStackFrame, 'hover'); + return expression; + } else { + const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; + if (focusedStackFrame) { + return await findExpressionInStackFrame( + focusedStackFrame, + coalesce(this._currentExpression.split('.').map(word => word.trim()))); + } + } + + return undefined; + } +} diff --git a/src/vs/workbench/contrib/debug/browser/media/debugHover.css b/src/vs/workbench/contrib/debug/browser/media/debugHover.css index c523256de87..3a862adbe9f 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugHover.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugHover.css @@ -5,7 +5,6 @@ .monaco-editor .debug-hover-widget { position: absolute; - margin-top: -1px; z-index: 50; animation-duration: 0.15s; animation-name: fadeIn; diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 11c3f051a43..d8feb192429 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -13,7 +13,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import severity from 'vs/base/common/severity'; import { URI as uri } from 'vs/base/common/uri'; import { IPosition, Position } from 'vs/editor/common/core/position'; -import { IRange, Range } from 'vs/editor/common/core/range'; +import { IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModel as EditorIModel } from 'vs/editor/common/model'; import * as nls from 'vs/nls'; @@ -1133,7 +1133,7 @@ export const enum BreakpointWidgetContext { } export interface IDebugEditorContribution extends editorCommon.IEditorContribution { - showHover(range: Range, focus: boolean): Promise; + showHover(range: Position, focus: boolean): Promise; addLaunchConfiguration(): Promise; closeExceptionWidget(): void; } From a3d38a03ffdcb379813cb31967799e7b4003a5d2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:21:57 -0700 Subject: [PATCH 434/599] Use for const of in onOsResume --- .../terminal/electron-sandbox/terminalNativeContribution.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts index b22ebddac85..b1c88750736 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts @@ -43,7 +43,9 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench } private _onOsResume(): void { - this._terminalService.instances.forEach(instance => instance.xterm?.forceRedraw()); + for (const instance of this._terminalService.instances) { + instance.xterm?.forceRedraw(); + } } private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise { From 06142158c6464db865f2219a85f5551ccfdb9d8b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:24:49 -0700 Subject: [PATCH 435/599] Revert change to init renderer before open This was causing problems where webgl would not get activated Reopened #162973 --- .../contrib/terminal/browser/xterm/xtermTerminal.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 94789a8f2d3..a7f8fced3d9 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -218,13 +218,6 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this.raw.loadAddon(this._decorationAddon); this._shellIntegrationAddon = this._instantiationService.createInstance(ShellIntegrationAddon, disableShellIntegrationReporting, this._telemetryService); this.raw.loadAddon(this._shellIntegrationAddon); - - // Load the relevant renderer addon ahead of open being called as it's asynchronous - if (this._shouldLoadWebgl()) { - this._enableWebglRenderer(); - } else if (this._shouldLoadCanvas()) { - this._enableCanvasRenderer(); - } } async getSelectionAsHtml(command?: ITerminalCommand): Promise { @@ -254,6 +247,12 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II if (!this._container) { this.raw.open(container); } + // TODO: Move before open to the DOM renderer doesn't initialize + if (this._shouldLoadWebgl()) { + this._enableWebglRenderer(); + } else if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + } this._container = container; // Screen must be created at this point as xterm.open is called return this._container.querySelector('.xterm-screen')!; From 85f30955f6ae6673822d8657da22bf8fcc94d65f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:26:41 -0700 Subject: [PATCH 436/599] Don't clear the texture atlas multiple times This needs xtermjs/xterm.js#4181 to be properly fixed. Part of #162996 Co-Authored-By: Megan Rogge --- src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 94789a8f2d3..d68a941b2b2 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -299,7 +299,6 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II } forceRedraw() { - this._webglAddon?.clearTextureAtlas(); this.raw.clearTextureAtlas(); } From 6483e39fb7b0ae0aeae6bb00ff42dbed3ceb618b Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 7 Oct 2022 17:13:49 -0700 Subject: [PATCH 437/599] xterm-addon-webgl@0.14.0-beta.20 (#163021) xterm-addon-webgl@0.14.0-beta.20 Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> --- package.json | 8 ++++---- remote/package.json | 8 ++++---- remote/web/package.json | 6 +++--- remote/web/yarn.lock | 24 ++++++++++++------------ remote/yarn.lock | 32 ++++++++++++++++---------------- yarn.lock | 32 ++++++++++++++++---------------- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 9a35de0240d..8c6a867e9b3 100644 --- a/package.json +++ b/package.json @@ -86,13 +86,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.27", - "xterm-addon-canvas": "0.3.0-beta.10", + "xterm": "5.1.0-beta.29", + "xterm-addon-canvas": "0.3.0-beta.13", "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.18", - "xterm-headless": "5.1.0-beta.27", + "xterm-addon-webgl": "0.14.0-beta.20", + "xterm-headless": "5.1.0-beta.29", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index eb4549d8bc9..a08e298af45 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,13 +24,13 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.27", - "xterm-addon-canvas": "0.3.0-beta.10", + "xterm": "5.1.0-beta.29", + "xterm-addon-canvas": "0.3.0-beta.13", "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-serialize": "0.9.0-beta.2", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.18", - "xterm-headless": "5.1.0-beta.27", + "xterm-addon-webgl": "0.14.0-beta.20", + "xterm-headless": "5.1.0-beta.29", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 7a0b52b469b..962f1cc0dc3 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,10 +11,10 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "5.1.0-beta.27", - "xterm-addon-canvas": "0.3.0-beta.10", + "xterm": "5.1.0-beta.29", + "xterm-addon-canvas": "0.3.0-beta.13", "xterm-addon-search": "0.11.0-beta.4", "xterm-addon-unicode11": "0.5.0-beta.1", - "xterm-addon-webgl": "0.14.0-beta.18" + "xterm-addon-webgl": "0.14.0-beta.20" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index dd89770243b..679924f51d6 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,10 +68,10 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-canvas@0.3.0-beta.10: - version "0.3.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" - integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== +xterm-addon-canvas@0.3.0-beta.13: + version "0.3.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.13.tgz#6fd23f4c8d4d013a540cb8ff1e4965ff6bf248b5" + integrity sha512-gNl2wG5zv5AttbTs1OgMRFcARs/dt0k2snFpMmrnaTKlgpi3S0k+Sh3C4nbdMuqbCZd+n7gtpAYP+F6ZXC1pdA== xterm-addon-search@0.11.0-beta.4: version "0.11.0-beta.4" @@ -83,12 +83,12 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.18: - version "0.14.0-beta.18" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" - integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== +xterm-addon-webgl@0.14.0-beta.20: + version "0.14.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.20.tgz#1bd723a58ab6414c4773d181bbae51751827768c" + integrity sha512-inUnGzw+ewMszMQY8PqO97/t6hh/qg712uyuHLLoinDOjzXN5x2IiPMrt4LL70P6YmmTU65m/Gmfp+rd2u4yWg== -xterm@5.1.0-beta.27: - version "5.1.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" - integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== +xterm@5.1.0-beta.29: + version "5.1.0-beta.29" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.29.tgz#76368661b0503800c3f4374ab380e806290038e6" + integrity sha512-qirPDkX99thKjd7bkZMBQfP6EMOWTigYQz9lFU5tIkqsoYCu7zakaakkQuC2xbVRue9nftHZItzYKeO1/ldvTA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 951e77cbc7e..056cc5a71f6 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -788,10 +788,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.3.0-beta.10: - version "0.3.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" - integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== +xterm-addon-canvas@0.3.0-beta.13: + version "0.3.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.13.tgz#6fd23f4c8d4d013a540cb8ff1e4965ff6bf248b5" + integrity sha512-gNl2wG5zv5AttbTs1OgMRFcARs/dt0k2snFpMmrnaTKlgpi3S0k+Sh3C4nbdMuqbCZd+n7gtpAYP+F6ZXC1pdA== xterm-addon-search@0.11.0-beta.4: version "0.11.0-beta.4" @@ -808,20 +808,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.18: - version "0.14.0-beta.18" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" - integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== +xterm-addon-webgl@0.14.0-beta.20: + version "0.14.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.20.tgz#1bd723a58ab6414c4773d181bbae51751827768c" + integrity sha512-inUnGzw+ewMszMQY8PqO97/t6hh/qg712uyuHLLoinDOjzXN5x2IiPMrt4LL70P6YmmTU65m/Gmfp+rd2u4yWg== -xterm-headless@5.1.0-beta.27: - version "5.1.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.27.tgz#59b9033e1f3e7e09bc9dc7d05dd1d82be7a31659" - integrity sha512-ow/0UBeMNGZMxhK+0bZy3pBK+O5so3d2Dbx2z1umjv5EWL2+Ix/Mz51OtQWd6YdSVrs9z+I1QeAd3aYWnnpG8g== +xterm-headless@5.1.0-beta.29: + version "5.1.0-beta.29" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.29.tgz#b3c2bbd934fe5d9111b2206ddaf039d604aefe95" + integrity sha512-hzIzZwYtubZplfnmtx1IQdipp2eTt09zjTT6/JZFSTcTLBUCtePlgtCZPJENUyy5v+aSJgbMTDFrfjARRBCZMw== -xterm@5.1.0-beta.27: - version "5.1.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" - integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== +xterm@5.1.0-beta.29: + version "5.1.0-beta.29" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.29.tgz#76368661b0503800c3f4374ab380e806290038e6" + integrity sha512-qirPDkX99thKjd7bkZMBQfP6EMOWTigYQz9lFU5tIkqsoYCu7zakaakkQuC2xbVRue9nftHZItzYKeO1/ldvTA== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index 3f9bb0f03ca..6c3a49eb969 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11582,10 +11582,10 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-canvas@0.3.0-beta.10: - version "0.3.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.10.tgz#5159efdcdcf689364975aa04d56dd0913c2fcd1b" - integrity sha512-2uv8zxK+7a9/Gwe79PMlRz8YjBSVm+HVBPbS3H8HC2qECGJdnlghVXrs6zYsi2xWNuUnwMabdP+BxhCJixKgZQ== +xterm-addon-canvas@0.3.0-beta.13: + version "0.3.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.3.0-beta.13.tgz#6fd23f4c8d4d013a540cb8ff1e4965ff6bf248b5" + integrity sha512-gNl2wG5zv5AttbTs1OgMRFcARs/dt0k2snFpMmrnaTKlgpi3S0k+Sh3C4nbdMuqbCZd+n7gtpAYP+F6ZXC1pdA== xterm-addon-search@0.11.0-beta.4: version "0.11.0-beta.4" @@ -11602,20 +11602,20 @@ xterm-addon-unicode11@0.5.0-beta.1: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0-beta.1.tgz#8a9e9356018e082318abbe2be1f9599fcc6b46a2" integrity sha512-uAErX4gwhW6N524stLG6oZR3yBGgPnFmZ2Tv4vyYy7tcgDuHRoc22xYSCDgO1ohz1FLlOm8JGXRjXliwO9ic3A== -xterm-addon-webgl@0.14.0-beta.18: - version "0.14.0-beta.18" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.18.tgz#cfdc0ec89c81d4688aaecd66c1d151f8813762f8" - integrity sha512-jiejt5aE4o2swL80PyoyIN7zJobGGC5e7/6foTETL45hLlzJHbBG5PLN6uxaGM9GRTnZ//sZxBWXaTDXFiz1Eg== +xterm-addon-webgl@0.14.0-beta.20: + version "0.14.0-beta.20" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.14.0-beta.20.tgz#1bd723a58ab6414c4773d181bbae51751827768c" + integrity sha512-inUnGzw+ewMszMQY8PqO97/t6hh/qg712uyuHLLoinDOjzXN5x2IiPMrt4LL70P6YmmTU65m/Gmfp+rd2u4yWg== -xterm-headless@5.1.0-beta.27: - version "5.1.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.27.tgz#59b9033e1f3e7e09bc9dc7d05dd1d82be7a31659" - integrity sha512-ow/0UBeMNGZMxhK+0bZy3pBK+O5so3d2Dbx2z1umjv5EWL2+Ix/Mz51OtQWd6YdSVrs9z+I1QeAd3aYWnnpG8g== +xterm-headless@5.1.0-beta.29: + version "5.1.0-beta.29" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.1.0-beta.29.tgz#b3c2bbd934fe5d9111b2206ddaf039d604aefe95" + integrity sha512-hzIzZwYtubZplfnmtx1IQdipp2eTt09zjTT6/JZFSTcTLBUCtePlgtCZPJENUyy5v+aSJgbMTDFrfjARRBCZMw== -xterm@5.1.0-beta.27: - version "5.1.0-beta.27" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.27.tgz#2155d6ece9f2a61955c7c00d6491e86aaf0cc330" - integrity sha512-QcwHn+6ELG3zgg8XE3ojCygPOA023Vp5xtSFbkEWGAe7gEqjygejyoExUfN2ARixuwFRflgYN3KXICrs+ut+kw== +xterm@5.1.0-beta.29: + version "5.1.0-beta.29" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0-beta.29.tgz#76368661b0503800c3f4374ab380e806290038e6" + integrity sha512-qirPDkX99thKjd7bkZMBQfP6EMOWTigYQz9lFU5tIkqsoYCu7zakaakkQuC2xbVRue9nftHZItzYKeO1/ldvTA== y18n@^3.2.1: version "3.2.2" From c3f5861ca2585a020a974c28aae45d1bce7edb62 Mon Sep 17 00:00:00 2001 From: Tomer Chachamu Date: Sat, 8 Oct 2022 13:16:45 +0100 Subject: [PATCH 438/599] Fix 'join all editor groups' for notebooks Fixes #134158 --- .../browser/services/notebookEditorServiceImpl.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts index 19d44f350d6..6e89fd39df6 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookEditorServiceImpl.ts @@ -58,12 +58,12 @@ export class NotebookEditorWidgetService implements INotebookEditorService { })); listeners.push(group.onWillMoveEditor(e => { if (e.editor instanceof NotebookEditorInput) { - this._freeWidget(e.editor, e.groupId, e.target); + this._allowWidgetMove(e.editor, e.groupId, e.target); } if (isCompositeNotebookEditorInput(e.editor)) { e.editor.editorInputs.forEach(input => { - this._freeWidget(input, e.groupId, e.target); + this._allowWidgetMove(input, e.groupId, e.target); }); } })); @@ -105,7 +105,7 @@ export class NotebookEditorWidgetService implements INotebookEditorService { domNode.remove(); } - private _freeWidget(input: NotebookEditorInput, sourceID: GroupIdentifier, targetID: GroupIdentifier): void { + private _allowWidgetMove(input: NotebookEditorInput, sourceID: GroupIdentifier, targetID: GroupIdentifier): void { const targetWidget = this._borrowableEditors.get(targetID)?.get(input.resource); if (targetWidget) { // not needed @@ -116,9 +116,10 @@ export class NotebookEditorWidgetService implements INotebookEditorService { if (!widget) { throw new Error('no widget at source group'); } + // don't allow the widget to be retrieved at its previous location any more this._borrowableEditors.get(sourceID)?.delete(input.resource); - widget.token = undefined; + // allow the widget to be retrieved at its new location let targetMap = this._borrowableEditors.get(targetID); if (!targetMap) { targetMap = new ResourceMap(); From bc647873e0000be76a2e08e0c1822b1c2e42e57f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 09:01:28 +0200 Subject: [PATCH 439/599] promote filter action to view pane (#163132) promote filter to view pane --- src/vs/base/browser/ui/toolbar/toolbar.ts | 4 + src/vs/platform/actions/browser/toolbar.ts | 2 +- src/vs/workbench/browser/panecomposite.ts | 7 +- .../browser/parts/views/media/views.css | 73 +++ .../browser/parts/views/viewFilter.ts | 257 +++++++++++ .../workbench/browser/parts/views/viewPane.ts | 100 ++++- .../contrib/comments/browser/comments.ts | 5 - .../contrib/comments/browser/commentsView.ts | 94 ++-- .../comments/browser/commentsViewActions.ts | 422 +++--------------- .../contrib/comments/browser/media/panel.css | 55 --- .../contrib/debug/browser/media/repl.css | 50 --- .../workbench/contrib/debug/browser/repl.ts | 106 ++--- .../contrib/debug/browser/replFilter.ts | 197 -------- .../markers/browser/markers.contribution.ts | 143 +++++- .../contrib/markers/browser/markers.ts | 4 - .../contrib/markers/browser/markersView.ts | 101 ++--- .../markers/browser/markersViewActions.ts | 397 ++-------------- .../contrib/markers/browser/media/markers.css | 66 --- .../contrib/markers/common/markers.ts | 6 +- 19 files changed, 786 insertions(+), 1303 deletions(-) create mode 100644 src/vs/workbench/browser/parts/views/viewFilter.ts diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index d7f39454a0f..6ebd8c2a853 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -140,6 +140,10 @@ export class ToolBar extends Disposable { return this.element; } + focus(): void { + this.actionBar.focus(); + } + getItemsWidth(): number { let itemsWidth = 0; for (let i = 0; i < this.actionBar.length(); i++) { diff --git a/src/vs/platform/actions/browser/toolbar.ts b/src/vs/platform/actions/browser/toolbar.ts index db91b1c67f7..397a14c5f4a 100644 --- a/src/vs/platform/actions/browser/toolbar.ts +++ b/src/vs/platform/actions/browser/toolbar.ts @@ -264,7 +264,7 @@ export class MenuWorkbenchToolBar extends WorkbenchToolBar { super(container, { resetMenu: menuId, ...options }, menuService, contextKeyService, contextMenuService, keybindingService, telemetryService); // update logic - const menu = this._store.add(menuService.createMenu(menuId, contextKeyService)); + const menu = this._store.add(menuService.createMenu(menuId, contextKeyService, { emitEventsForSubmenuChanges: true })); const updateToolbar = () => { const primary: IAction[] = []; const secondary: IAction[] = []; diff --git a/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts index 246e899675a..31e6e3ce2da 100644 --- a/src/vs/workbench/browser/panecomposite.ts +++ b/src/vs/workbench/browser/panecomposite.ts @@ -20,6 +20,7 @@ import { ViewPaneContainer, ViewsSubMenu } from 'vs/workbench/browser/parts/view import { IPaneComposite } from 'vs/workbench/common/panecomposite'; import { IView } from 'vs/workbench/common/views'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { VIEWPANE_FILTER_ACTION } from 'vs/workbench/browser/parts/views/viewPane'; export abstract class PaneComposite extends Composite implements IPaneComposite { @@ -89,7 +90,11 @@ export abstract class PaneComposite extends Composite implements IPaneComposite if (this.viewPaneContainer?.menuActions) { result.push(...this.viewPaneContainer.menuActions.getPrimaryActions()); if (this.viewPaneContainer.isViewMergedWithContainer()) { - result.push(...this.viewPaneContainer.panes[0].menuActions.getPrimaryActions()); + const viewPane = this.viewPaneContainer.panes[0]; + if (viewPane.shouldShowFilterInHeader()) { + result.push(VIEWPANE_FILTER_ACTION); + } + result.push(...viewPane.menuActions.getPrimaryActions()); } } return result; diff --git a/src/vs/workbench/browser/parts/views/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css index 9ed1f853826..df9b41cafaf 100644 --- a/src/vs/workbench/browser/parts/views/media/views.css +++ b/src/vs/workbench/browser/parts/views/media/views.css @@ -201,3 +201,76 @@ .customview-tree .monaco-list .monaco-list-row.focused .custom-view-tree-node-item .actions { display: block; } + +/* filter view pane */ + +.viewpane-filter-container { + cursor: default; + display: flex; +} + +.viewpane-filter-container.grow { + flex: 1; +} + +.viewpane-filter-container > .viewpane-filter { + display: flex; + align-items: center; + flex: 1; + position: relative; +} + +.viewpane-filter-container > .viewpane-filter .monaco-inputbox { + height: 24px; + font-size: 12px; + flex: 1; +} + +.pane-header .viewpane-filter-container > .viewpane-filter .monaco-inputbox .monaco-inputbox { + height: 20px; + line-height: 18px; +} + +.monaco-workbench.vs .viewpane-filter-container > .viewpane-filter .monaco-inputbox { + height: 25px; +} + +.viewpane-filter-container > .viewpane-filter > .viewpane-filter-controls { + position: absolute; + top: 0px; + bottom: 0; + right: 0px; + display: flex; + align-items: center; +} + +.viewpane-filter-container > .viewpane-filter > .viewpane-filter-controls > .viewpane-filter-badge { + margin: 4px 0px; + padding: 0px 8px; + border-radius: 2px; +} + +.viewpane-filter > .viewpane-filter-controls > .viewpane-filter-badge.hidden, +.viewpane-filter.small > .viewpane-filter-controls > .viewpane-filter-badge { + display: none; +} + +.viewpane-filter > .viewpane-filter-controls > .monaco-action-bar .action-item .action-label.codicon.filter { + padding: 2px; +} + +.panel > .title .monaco-action-bar .action-item.viewpane-filter-container { + max-width: 400px; + min-width: 300px; + margin-right: 10px; +} + +.pane-body .viewpane-filter-container:not(:empty) { + flex: 1; + margin: 10px 20px; + height: initial; +} + +.pane-body .viewpane-filter-container > .viewpane-filter > .viewpane-filter-controls .monaco-action-bar .action-item { + margin-right: 4px; +} diff --git a/src/vs/workbench/browser/parts/views/viewFilter.ts b/src/vs/workbench/browser/parts/views/viewFilter.ts new file mode 100644 index 00000000000..60bcde06cd2 --- /dev/null +++ b/src/vs/workbench/browser/parts/views/viewFilter.ts @@ -0,0 +1,257 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Delayer } from 'vs/base/common/async'; +import * as DOM from 'vs/base/browser/dom'; +import { IAction } from 'vs/base/common/actions'; +import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IThemeService, registerThemingParticipant, ICssStyleCollector, IColorTheme } from 'vs/platform/theme/common/themeService'; +import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { toDisposable } from 'vs/base/common/lifecycle'; +import { badgeBackground, badgeForeground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry'; +import { localize } from 'vs/nls'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ContextScopedHistoryInputBox } from 'vs/platform/history/browser/contextScopedHistoryWidget'; +import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Codicon } from 'vs/base/common/codicons'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; +import { MenuId, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { HiddenItemStrategy, MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; +import { SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { Widget } from 'vs/base/browser/ui/widget'; +import { Emitter } from 'vs/base/common/event'; + +const viewFilterMenu = new MenuId('menu.view.filter'); +export const viewFilterSubmenu = new MenuId('submenu.view.filter'); +MenuRegistry.appendMenuItem(viewFilterMenu, { + submenu: viewFilterSubmenu, + title: localize('more filters', "More Filters..."), + group: 'navigation', + icon: Codicon.filter, +}); + +class MoreFiltersActionViewItem extends SubmenuEntryActionViewItem { + + private _checked: boolean = false; + set checked(checked: boolean) { + if (this._checked !== checked) { + this._checked = checked; + this.updateChecked(); + } + } + + protected override updateChecked(): void { + if (this.element) { + this.element.classList.toggle('checked', this._checked); + } + } + + override render(container: HTMLElement): void { + super.render(container); + this.updateChecked(); + } + +} + +export interface IFilterWidgetOptions { + readonly text?: string; + readonly placeholder?: string; + readonly ariaLabel?: string; + readonly history?: string[]; + readonly focusContextKey?: string; +} + +export class FilterWidget extends Widget { + + readonly element: HTMLElement; + private readonly delayedFilterUpdate: Delayer; + private readonly filterInputBox: HistoryInputBox; + private readonly filterBadge: HTMLElement; + private readonly toolbar: MenuWorkbenchToolBar; + private readonly focusContextKey: IContextKey | undefined; + + private readonly _onDidChangeFilterText = this._register(new Emitter()); + readonly onDidChangeFilterText = this._onDidChangeFilterText.event; + + private moreFiltersActionViewItem: MoreFiltersActionViewItem | undefined; + private isMoreFiltersChecked: boolean = false; + + constructor( + private readonly options: IFilterWidgetOptions, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IContextViewService private readonly contextViewService: IContextViewService, + @IThemeService private readonly themeService: IThemeService, + @IContextKeyService contextKeyService: IContextKeyService, + @IKeybindingService private readonly keybindingService: IKeybindingService + ) { + super(); + this.delayedFilterUpdate = new Delayer(400); + this._register(toDisposable(() => this.delayedFilterUpdate.cancel())); + + if (options.focusContextKey) { + this.focusContextKey = new RawContextKey(options.focusContextKey, false).bindTo(contextKeyService); + } + + this.element = DOM.$('.viewpane-filter'); + this.filterInputBox = this.createInput(this.element); + + const controlsContainer = DOM.append(this.element, DOM.$('.viewpane-filter-controls')); + this.filterBadge = this.createBadge(controlsContainer); + this.toolbar = this._register(this.createToolBar(controlsContainer)); + + this.adjustInputBox(); + } + + focus(): void { + this.filterInputBox.focus(); + } + + blur(): void { + this.filterInputBox.blur(); + } + + updateBadge(message: string | undefined): void { + this.filterBadge.classList.toggle('hidden', !message); + this.filterBadge.textContent = message || ''; + this.adjustInputBox(); + } + + setFilterText(filterText: string): void { + this.filterInputBox.value = filterText; + } + + getFilterText(): string { + return this.filterInputBox.value; + } + + getHistory(): string[] { + return this.filterInputBox.getHistory(); + } + + layout(width: number): void { + this.element.parentElement?.classList.toggle('grow', width > 700); + this.element.classList.toggle('small', width < 400); + this.adjustInputBox(); + } + + checkMoreFilters(checked: boolean): void { + this.isMoreFiltersChecked = checked; + if (this.moreFiltersActionViewItem) { + this.moreFiltersActionViewItem.checked = checked; + } + } + + private createInput(container: HTMLElement): ContextScopedHistoryInputBox { + const inputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, { + placeholder: this.options.placeholder, + ariaLabel: this.options.ariaLabel, + history: this.options.history || [], + showHistoryHint: () => showHistoryKeybindingHint(this.keybindingService) + })); + this._register(attachInputBoxStyler(inputBox, this.themeService)); + if (this.options.text) { + inputBox.value = this.options.text; + } + this._register(inputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(inputBox!)))); + this._register(DOM.addStandardDisposableListener(inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, inputBox!))); + this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); + this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); + this._register(DOM.addStandardDisposableListener(inputBox.inputElement, DOM.EventType.CLICK, (e) => { + e.stopPropagation(); + e.preventDefault(); + })); + + const focusTracker = this._register(DOM.trackFocus(inputBox.inputElement)); + if (this.focusContextKey) { + this._register(focusTracker.onDidFocus(() => this.focusContextKey!.set(true))); + this._register(focusTracker.onDidBlur(() => this.focusContextKey!.set(false))); + this._register(toDisposable(() => this.focusContextKey!.reset())); + } + return inputBox; + } + + private createBadge(container: HTMLElement): HTMLElement { + const filterBadge = DOM.append(container, DOM.$('.viewpane-filter-badge.hidden')); + this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; + + filterBadge.style.backgroundColor = background; + + filterBadge.style.borderWidth = border ? '1px' : ''; + filterBadge.style.borderStyle = border ? 'solid' : ''; + filterBadge.style.borderColor = border; + filterBadge.style.color = foreground; + })); + return filterBadge; + } + + private createToolBar(container: HTMLElement): MenuWorkbenchToolBar { + return this.instantiationService.createInstance(MenuWorkbenchToolBar, container, viewFilterMenu, + { + hiddenItemStrategy: HiddenItemStrategy.NoHide, + actionViewItemProvider: (action: IAction) => { + if (action instanceof SubmenuItemAction && action.item.submenu.id === viewFilterSubmenu.id) { + this.moreFiltersActionViewItem = this.instantiationService.createInstance(MoreFiltersActionViewItem, action, undefined); + this.moreFiltersActionViewItem.checked = this.isMoreFiltersChecked; + return this.moreFiltersActionViewItem; + } + return undefined; + } + }); + } + + private onDidInputChange(inputbox: HistoryInputBox) { + inputbox.addToHistory(); + this._onDidChangeFilterText.fire(inputbox.value); + } + + private adjustInputBox(): void { + this.filterInputBox.inputElement.style.paddingRight = this.element.classList.contains('small') || this.filterBadge.classList.contains('hidden') ? '25px' : '150px'; + } + + // Action toolbar is swallowing some keys for action items which should not be for an input box + private handleKeyboardEvent(event: StandardKeyboardEvent) { + if (event.equals(KeyCode.Space) + || event.equals(KeyCode.LeftArrow) + || event.equals(KeyCode.RightArrow) + ) { + event.stopPropagation(); + } + } + + private onInputKeyDown(event: StandardKeyboardEvent, filterInputBox: HistoryInputBox) { + let handled = false; + if (event.equals(KeyCode.Tab)) { + this.toolbar.focus(); + handled = true; + } + if (handled) { + event.stopPropagation(); + event.preventDefault(); + } + } + +} + +registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { + const inputActiveOptionBorderColor = theme.getColor(inputActiveOptionBorder); + if (inputActiveOptionBorderColor) { + collector.addRule(`.viewpane-filter > .viewpane-filter-controls .monaco-action-bar .action-label.codicon.codicon-filter.checked { border-color: ${inputActiveOptionBorderColor}; }`); + } + const inputActiveOptionForegroundColor = theme.getColor(inputActiveOptionForeground); + if (inputActiveOptionForegroundColor) { + collector.addRule(`.viewpane-filter > .viewpane-filter-controls .monaco-action-bar .action-label.codicon.codicon-filter.checked { color: ${inputActiveOptionForegroundColor}; }`); + } + const inputActiveOptionBackgroundColor = theme.getColor(inputActiveOptionBackground); + if (inputActiveOptionBackgroundColor) { + collector.addRule(`.viewpane-filter > .viewpane-filter-controls .monaco-action-bar .action-label.codicon.codicon-filter.checked { background-color: ${inputActiveOptionBackgroundColor}; }`); + } +}); diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index feba32556f0..f5b42f9b8a1 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -9,9 +9,9 @@ import { Event, Emitter } from 'vs/base/common/event'; import { foreground } from 'vs/platform/theme/common/colorRegistry'; import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl } from 'vs/base/browser/dom'; +import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl, Dimension, reset } from 'vs/base/browser/dom'; import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IAction, IActionRunner } from 'vs/base/common/actions'; +import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { Registry } from 'vs/platform/registry/common/platform'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -42,6 +42,9 @@ import { Codicon } from 'vs/base/common/codicons'; import { CompositeMenuActions } from 'vs/workbench/browser/actions'; import { IDropdownMenuActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; +import { FilterWidget, IFilterWidgetOptions } from 'vs/workbench/browser/parts/views/viewFilter'; +import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; export interface IViewPaneOptions extends IPaneOptions { id: string; @@ -50,6 +53,12 @@ export interface IViewPaneOptions extends IPaneOptions { donotForwardArgs?: boolean; } +export interface IFilterViewPaneOptions extends IViewPaneOptions { + filterOptions: IFilterWidgetOptions; +} + +export const VIEWPANE_FILTER_ACTION = new Action('viewpane.action.filter'); + type WelcomeActionClassification = { owner: 'joaomoreno'; viewId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The view ID in which the welcome view button was clicked.' }; @@ -501,7 +510,11 @@ export abstract class ViewPane extends Pane implements IView { private setActions(): void { if (this.toolbar) { - this.toolbar.setActions(prepareActions(this.menuActions.getPrimaryActions()), prepareActions(this.menuActions.getSecondaryActions())); + const primaryActions = [...this.menuActions.getPrimaryActions()]; + if (this.shouldShowFilterInHeader()) { + primaryActions.unshift(VIEWPANE_FILTER_ACTION); + } + this.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions())); this.toolbar.context = this.getActionsContext(); } } @@ -520,6 +533,18 @@ export abstract class ViewPane extends Pane implements IView { } getActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined { + if (action.id === VIEWPANE_FILTER_ACTION.id) { + const that = this; + return new class extends BaseActionViewItem { + constructor() { super(null, action); } + override setFocusable(): void { /* noop input elements are focusable by default */ } + override get trapsArrowNavigation(): boolean { return true; } + override render(container: HTMLElement): void { + container.classList.add('viewpane-filter-container'); + append(container, that.getFilterWidget()!.element); + } + }; + } return createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } }); } @@ -626,6 +651,75 @@ export abstract class ViewPane extends Pane implements IView { shouldShowWelcome(): boolean { return false; } + + getFilterWidget(): FilterWidget | undefined { + return undefined; + } + + shouldShowFilterInHeader(): boolean { + return false; + } +} + +export abstract class FilterViewPane extends ViewPane { + + readonly filterWidget: FilterWidget; + private dimension: Dimension | undefined; + private filterContainer: HTMLElement | undefined; + + constructor( + options: IFilterViewPaneOptions, + @IKeybindingService keybindingService: IKeybindingService, + @IContextMenuService contextMenuService: IContextMenuService, + @IConfigurationService configurationService: IConfigurationService, + @IContextKeyService contextKeyService: IContextKeyService, + @IViewDescriptorService viewDescriptorService: IViewDescriptorService, + @IInstantiationService instantiationService: IInstantiationService, + @IOpenerService openerService: IOpenerService, + @IThemeService themeService: IThemeService, + @ITelemetryService telemetryService: ITelemetryService, + ) { + super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); + const scopedContextKeyService = this._register(contextKeyService.createScoped(this.element)); + scopedContextKeyService.createKey('view', options.id); + this.filterWidget = this._register(instantiationService.createChild(new ServiceCollection([IContextKeyService, scopedContextKeyService])).createInstance(FilterWidget, options.filterOptions)); + } + + override getFilterWidget(): FilterWidget { + return this.filterWidget; + } + + protected override renderBody(container: HTMLElement): void { + super.renderBody(container); + this.filterContainer = append(container, $('.viewpane-filter-container')); + } + + protected override layoutBody(height: number, width: number): void { + super.layoutBody(height, width); + + this.dimension = new Dimension(width, height); + const wasFilterShownInHeader = !this.filterContainer?.hasChildNodes(); + const shouldShowFilterInHeader = this.shouldShowFilterInHeader(); + if (wasFilterShownInHeader !== shouldShowFilterInHeader) { + if (shouldShowFilterInHeader) { + reset(this.filterContainer!); + } + this.updateActions(); + if (!shouldShowFilterInHeader) { + append(this.filterContainer!, this.filterWidget.element); + height = height - 44; + } + } + this.filterWidget.layout(width); + this.layoutBodyContent(height, width); + } + + override shouldShowFilterInHeader(): boolean { + return !(this.dimension && this.dimension.width < 600 && this.dimension.height > 100); + } + + protected abstract layoutBodyContent(height: number, width: number): void; + } export abstract class ViewAction extends Action2 { diff --git a/src/vs/workbench/contrib/comments/browser/comments.ts b/src/vs/workbench/contrib/comments/browser/comments.ts index 82c3e009faa..7ccfc5706e4 100644 --- a/src/vs/workbench/contrib/comments/browser/comments.ts +++ b/src/vs/workbench/contrib/comments/browser/comments.ts @@ -3,20 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event } from 'vs/base/common/event'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IView } from 'vs/workbench/common/views'; import { CommentsFilters } from 'vs/workbench/contrib/comments/browser/commentsViewActions'; export const CommentsViewFilterFocusContextKey = new RawContextKey('commentsFilterFocus', false); -export const CommentsViewSmallLayoutContextKey = new RawContextKey(`commentsView.smallLayout`, false); export interface ICommentsView extends IView { - readonly onDidFocusFilter: Event; - readonly onDidClearFilterText: Event; readonly filters: CommentsFilters; - readonly onDidChangeFilterStats: Event<{ total: number; filtered: number }>; focusFilter(): void; clearFilterText(): void; getFilterStats(): { total: number; filtered: number }; diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index d597a84eef2..4f31b2605e4 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -18,7 +18,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { CommentsList, COMMENTS_VIEW_ID, COMMENTS_VIEW_TITLE, Filter } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; -import { ViewPane, IViewPaneOptions, ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; +import { IViewPaneOptions, ViewAction, FilterViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -31,11 +31,8 @@ import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { Codicon } from 'vs/base/common/codicons'; import { IEditor } from 'vs/editor/common/editorCommon'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { Action, IAction } from 'vs/base/common/actions'; -import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CommentsViewSmallLayoutContextKey, ICommentsView } from 'vs/workbench/contrib/comments/browser/comments'; -import { CommentsFilterActionViewItem, CommentsFilters, CommentsFiltersChangeEvent } from 'vs/workbench/contrib/comments/browser/commentsViewActions'; -import { Event, Emitter } from 'vs/base/common/event'; +import { CommentsViewFilterFocusContextKey, ICommentsView } from 'vs/workbench/contrib/comments/browser/comments'; +import { CommentsFilters, CommentsFiltersChangeEvent } from 'vs/workbench/contrib/comments/browser/commentsViewActions'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { FilterOptions } from 'vs/workbench/contrib/comments/browser/commentsFilterOptions'; @@ -43,7 +40,7 @@ import { FilterOptions } from 'vs/workbench/contrib/comments/browser/commentsFil const CONTEXT_KEY_HAS_COMMENTS = new RawContextKey('commentsView.hasComments', false); const VIEW_STORAGE_ID = 'commentsViewState'; -export class CommentsPanel extends ViewPane implements ICommentsView { +export class CommentsPanel extends FilterViewPane implements ICommentsView { private treeLabels!: ResourceLabels; private tree: CommentsList | undefined; private treeContainer!: HTMLElement; @@ -51,10 +48,8 @@ export class CommentsPanel extends ViewPane implements ICommentsView { private commentsModel!: CommentsModel; private totalComments: number = 0; private readonly hasCommentsContextKey: IContextKey; - private readonly smallLayoutContextKey: IContextKey; private readonly filter: Filter; readonly filters: CommentsFilters; - private filterActionBar: ActionBar | undefined; private currentHeight = 0; private currentWidth = 0; @@ -64,13 +59,6 @@ export class CommentsPanel extends ViewPane implements ICommentsView { readonly onDidChangeVisibility = this.onDidChangeBodyVisibility; - private readonly _onDidFocusFilter: Emitter = this._register(new Emitter()); - readonly onDidFocusFilter: Event = this._onDidFocusFilter.event; - private readonly _onDidClearFilterText: Emitter = this._register(new Emitter()); - readonly onDidClearFilterText: Event = this._onDidClearFilterText.event; - private _onDidChangeFilterStats = this._register(new Emitter<{ total: number; filtered: number }>()); - readonly onDidChangeFilterStats: Event<{ total: number; filtered: number }> = this._onDidChangeFilterStats.event; - constructor( options: IViewPaneOptions, @IInstantiationService instantiationService: IInstantiationService, @@ -87,20 +75,27 @@ export class CommentsPanel extends ViewPane implements ICommentsView { @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @IStorageService readonly storageService: IStorageService ) { - super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); + const stateMemento = new Memento(VIEW_STORAGE_ID, storageService); + const viewState = stateMemento.getMemento(StorageScope.WORKSPACE, StorageTarget.USER); + super({ + ...options, + filterOptions: { + placeholder: nls.localize('comments.filter.placeholder', "Filter (e.g. text, author)"), + ariaLabel: nls.localize('comments.filter.ariaLabel', "Filter comments"), + history: viewState['filterHistory'] || [], + text: viewState['filter'] || '', + focusContextKey: CommentsViewFilterFocusContextKey.key + } + }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); this.hasCommentsContextKey = CONTEXT_KEY_HAS_COMMENTS.bindTo(contextKeyService); - this.smallLayoutContextKey = CommentsViewSmallLayoutContextKey.bindTo(this.contextKeyService); - this.stateMemento = new Memento(VIEW_STORAGE_ID, storageService); - this.viewState = this.stateMemento.getMemento(StorageScope.WORKSPACE, StorageTarget.USER); + this.stateMemento = stateMemento; + this.viewState = viewState; this.filters = this._register(new CommentsFilters({ - filterText: this.viewState['filter'] || '', - filterHistory: this.viewState['filterHistory'] || [], showResolved: this.viewState['showResolved'] !== false, showUnresolved: this.viewState['showUnresolved'] !== false, - layout: new dom.Dimension(0, 0) - })); - this.filter = new Filter(new FilterOptions(this.filters.filterText, this.filters.showResolved, this.filters.showUnresolved)); + }, this.contextKeyService)); + this.filter = new Filter(new FilterOptions(this.filterWidget.getFilterText(), this.filters.showResolved, this.filters.showUnresolved)); this._register(this.commentService.onDidSetAllCommentThreads(e => { this.totalComments = e.commentThreads.length; @@ -112,15 +107,16 @@ export class CommentsPanel extends ViewPane implements ICommentsView { })); this._register(this.filters.onDidChange((event: CommentsFiltersChangeEvent) => { - if (event.filterText || event.showResolved || event.showUnresolved) { + if (event.showResolved || event.showUnresolved) { this.updateFilter(); } })); + this._register(this.filterWidget.onDidChangeFilterText(() => this.updateFilter())); } override saveState(): void { - this.viewState['filter'] = this.filters.filterText; - this.viewState['filterHistory'] = this.filters.filterHistory; + this.viewState['filter'] = this.filterWidget.getFilterText(); + this.viewState['filterHistory'] = this.filterWidget.getHistory(); this.viewState['showResolved'] = this.filters.showResolved; this.viewState['showUnresolved'] = this.filters.showUnresolved; this.stateMemento.saveMemento(); @@ -128,11 +124,11 @@ export class CommentsPanel extends ViewPane implements ICommentsView { } public focusFilter(): void { - this._onDidFocusFilter.fire(); + this.filterWidget.focus(); } public clearFilterText(): void { - this._onDidClearFilterText.fire(); + this.filterWidget.setFilterText(''); } public getFilterStats(): { total: number; filtered: number } { @@ -147,30 +143,21 @@ export class CommentsPanel extends ViewPane implements ICommentsView { } private updateFilter() { - this.filter.options = new FilterOptions(this.filters.filterText, this.filters.showResolved, this.filters.showUnresolved); + this.filter.options = new FilterOptions(this.filterWidget.getFilterText(), this.filters.showResolved, this.filters.showUnresolved); this.tree?.filterComments(); this.cachedFilterStats = undefined; - this._onDidChangeFilterStats.fire(this.getFilterStats()); + const { total, filtered } = this.getFilterStats(); + this.filterWidget.updateBadge(total === filtered || total === 0 ? undefined : nls.localize('showing filtered results', "Showing {0} of {1}", filtered, total)); + this.filterWidget.checkMoreFilters(!this.filters.showResolved || !this.filters.showUnresolved); } - private createFilterActionBar(parent: HTMLElement): void { - this.filterActionBar = this._register(new ActionBar(parent, { actionViewItemProvider: action => this.getActionViewItem(action) })); - this.filterActionBar.getContainer().classList.add('comments-panel-filter-container'); - this.filterActionBar.getContainer().classList.toggle('hide', !this.smallLayout); - } - - private get smallLayout(): boolean { return !!this.smallLayoutContextKey.get(); } - private set smallLayout(smallLayout: boolean) { this.smallLayoutContextKey.set(smallLayout); } - public override renderBody(container: HTMLElement): void { super.renderBody(container); container.classList.add('comments-panel'); const domContainer = dom.append(container, dom.$('.comments-panel-container')); - this.createFilterActionBar(domContainer); - this.filterActionBar!.push(new Action(`workbench.actions.treeView.${this.id}.filter`)); this.treeContainer = dom.append(domContainer, dom.$('.tree-container')); this.treeContainer.classList.add('file-icon-themable-tree', 'show-file-icons'); @@ -255,20 +242,11 @@ export class CommentsPanel extends ViewPane implements ICommentsView { return !!this.tree; } - public override layoutBody(height: number = this.currentHeight, width: number = this.currentWidth): void { - super.layoutBody(height, width); - const wasSmallLayout = this.smallLayout; - this.smallLayout = width < 600 && height > 100; - if (this.smallLayout !== wasSmallLayout) { - this.filterActionBar?.getContainer().classList.toggle('hide', !this.smallLayout); - } - const contentHeight = this.smallLayout ? height - 44 : height; + public override layoutBodyContent(height: number = this.currentHeight, width: number = this.currentWidth): void { if (this.messageBoxContainer) { - this.messageBoxContainer.style.height = `${contentHeight}px`; + this.messageBoxContainer.style.height = `${height}px`; } - this.tree?.layout(contentHeight, width); - this.filters.layout = new dom.Dimension(this.smallLayout ? width : width - 200, height); - + this.tree?.layout(height, width); this.currentHeight = height; this.currentWidth = width; } @@ -421,12 +399,6 @@ export class CommentsPanel extends ViewPane implements ICommentsView { } } - public override getActionViewItem(action: IAction): IActionViewItem | undefined { - if (action.id === `workbench.actions.treeView.${this.id}.filter`) { - return this.instantiationService.createInstance(CommentsFilterActionViewItem, action, this); - } - return super.getActionViewItem(action); - } } CommandsRegistry.registerCommand({ diff --git a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts index 420029d895e..7720d37c9e3 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts @@ -3,50 +3,31 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Delayer } from 'vs/base/common/async'; -import * as DOM from 'vs/base/browser/dom'; -import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; -import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IThemeService, registerThemingParticipant, ICssStyleCollector, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { toDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { badgeBackground, badgeForeground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry'; +import { Disposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { ContextScopedHistoryInputBox } from 'vs/platform/history/browser/contextScopedHistoryWidget'; -import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; -import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; -import { Codicon } from 'vs/base/common/codicons'; -import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; -import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; -import { CommentsViewFilterFocusContextKey, CommentsViewSmallLayoutContextKey, ICommentsView } from 'vs/workbench/contrib/comments/browser/comments'; -import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { CommentsViewFilterFocusContextKey, ICommentsView } from 'vs/workbench/contrib/comments/browser/comments'; +import { registerAction2 } from 'vs/platform/actions/common/actions'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { COMMENTS_VIEW_ID } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; import { FocusedViewContext } from 'vs/workbench/common/contextkeys'; +import { viewFilterSubmenu } from 'vs/workbench/browser/parts/views/viewFilter'; + +const CONTEXT_KEY_SHOW_RESOLVED = new RawContextKey('commentsView.showResolvedFilter', true); +const CONTEXT_KEY_SHOW_UNRESOLVED = new RawContextKey('commentsView.showUnResolvedFilter', true); export interface CommentsFiltersChangeEvent { - filterText?: boolean; showResolved?: boolean; showUnresolved?: boolean; - layout?: boolean; } export interface CommentsFiltersOptions { - filterText: string; - filterHistory: string[]; showResolved: boolean; showUnresolved: boolean; - layout: DOM.Dimension; } export class CommentsFilters extends Disposable { @@ -54,323 +35,34 @@ export class CommentsFilters extends Disposable { private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(options: CommentsFiltersOptions) { + constructor(options: CommentsFiltersOptions, private readonly contextKeyService: IContextKeyService) { super(); - this._filterText = options.filterText; - this._showResolved = options.showResolved; - this._showUnresolved = options.showUnresolved; - this.filterHistory = options.filterHistory; - this._layout = options.layout; + this._showResolved.set(options.showResolved); + this._showUnresolved.set(options.showUnresolved); } - private _filterText: string; - get filterText(): string { - return this._filterText; - } - set filterText(filterText: string) { - if (this._filterText !== filterText) { - this._filterText = filterText; - this._onDidChange.fire({ filterText: true }); - } - } - - filterHistory: string[]; - - private _showUnresolved: boolean = true; + private readonly _showUnresolved = CONTEXT_KEY_SHOW_UNRESOLVED.bindTo(this.contextKeyService); get showUnresolved(): boolean { - return this._showUnresolved; + return !!this._showUnresolved.get(); } set showUnresolved(showUnresolved: boolean) { - if (this._showUnresolved !== showUnresolved) { - this._showUnresolved = showUnresolved; + if (this._showUnresolved.get() !== showUnresolved) { + this._showUnresolved.set(showUnresolved); this._onDidChange.fire({ showUnresolved: true }); } } - private _showResolved: boolean = true; + private _showResolved = CONTEXT_KEY_SHOW_RESOLVED.bindTo(this.contextKeyService); get showResolved(): boolean { - return this._showResolved; + return !!this._showResolved.get(); } set showResolved(showResolved: boolean) { - if (this._showResolved !== showResolved) { - this._showResolved = showResolved; + if (this._showResolved.get() !== showResolved) { + this._showResolved.set(showResolved); this._onDidChange.fire({ showResolved: true }); } } - private _layout: DOM.Dimension = new DOM.Dimension(0, 0); - get layout(): DOM.Dimension { - return this._layout; - } - set layout(layout: DOM.Dimension) { - if (this._layout.width !== layout.width || this._layout.height !== layout.height) { - this._layout = layout; - this._onDidChange.fire({ layout: true }); - } - } -} - -class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem { - - constructor( - action: IAction, private filters: CommentsFilters, actionRunner: IActionRunner, - @IContextMenuService contextMenuService: IContextMenuService - ) { - super(action, - { getActions: () => this.getActions() }, - contextMenuService, - { - actionRunner, - classNames: action.class, - anchorAlignmentProvider: () => AnchorAlignment.RIGHT, - menuAsChild: true - } - ); - } - - override render(container: HTMLElement): void { - super.render(container); - this.updateChecked(); - } - - private getActions(): IAction[] { - return [ - { - checked: this.filters.showResolved, - class: undefined, - enabled: true, - id: 'showResolved', - label: localize('showResolved', "Show Resolved"), - run: async () => this.filters.showResolved = !this.filters.showResolved, - tooltip: '' - }, - { - checked: this.filters.showUnresolved, - class: undefined, - enabled: true, - id: 'showUnresolved', - label: localize('showUnresolved', "Show Unresolved"), - run: async () => this.filters.showUnresolved = !this.filters.showUnresolved, - tooltip: '' - } - ]; - } - - override updateChecked(): void { - this.element!.classList.toggle('checked', this._action.checked); - } -} - - -const filterIcon = registerIcon('comments-view-filter', Codicon.filter, localize('comments.filterIcon', 'Icon for the filter configuration in the Comments view.')); - -export class CommentsFilterActionViewItem extends BaseActionViewItem { - - private delayedFilterUpdate: Delayer; - private container: HTMLElement | null = null; - private filterInputBox: HistoryInputBox | null = null; - private filterBadge: HTMLElement | null = null; - private focusContextKey: IContextKey; - private readonly filtersAction: IAction; - private actionbar: ActionBar | null = null; - private keybindingService; - - constructor( - action: IAction, - private commentsView: ICommentsView, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IContextViewService private readonly contextViewService: IContextViewService, - @IThemeService private readonly themeService: IThemeService, - @IContextKeyService contextKeyService: IContextKeyService, - @IKeybindingService keybindingService: IKeybindingService - ) { - super(null, action); - this.keybindingService = keybindingService; - this.focusContextKey = CommentsViewFilterFocusContextKey.bindTo(contextKeyService); - this.delayedFilterUpdate = new Delayer(400); - this._register(toDisposable(() => this.delayedFilterUpdate.cancel())); - this._register(commentsView.onDidFocusFilter(() => this.focus())); - this._register(commentsView.onDidClearFilterText(() => this.clearFilterText())); - this.filtersAction = new Action('commentsFiltersAction', localize('commentsFiltersAction', "More Filters..."), 'comments-filters ' + ThemeIcon.asClassName(filterIcon)); - this.filtersAction.checked = this.hasFiltersChanged(); - this._register(commentsView.filters.onDidChange(e => this.onDidFiltersChange(e))); - } - - override render(container: HTMLElement): void { - this.container = container; - this.container.classList.add('comments-panel-action-filter-container'); - - this.element = DOM.append(this.container, DOM.$('')); - this.element.className = this.class; - this.createInput(this.element); - this.createControls(this.element); - this.updateClass(); - - this.adjustInputBox(); - } - - override focus(): void { - if (this.filterInputBox) { - this.filterInputBox.focus(); - } - } - - override blur(): void { - if (this.filterInputBox) { - this.filterInputBox.blur(); - } - } - - override setFocusable(): void { - // noop input elements are focusable by default - } - - override get trapsArrowNavigation(): boolean { - return true; - } - - private clearFilterText(): void { - if (this.filterInputBox) { - this.filterInputBox.value = ''; - } - } - - private onDidFiltersChange(e: CommentsFiltersChangeEvent): void { - this.filtersAction.checked = this.hasFiltersChanged(); - if (e.layout) { - this.updateClass(); - } - } - - private hasFiltersChanged(): boolean { - return !this.commentsView.filters.showResolved || !this.commentsView.filters.showUnresolved; - } - - private createInput(container: HTMLElement): void { - this.filterInputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, { - placeholder: localize('comments.filter.placeholder', "Filter (e.g. text, author)"), - ariaLabel: localize('comments.filter.ariaLabel', "Filter comments"), - history: this.commentsView.filters.filterHistory, - showHistoryHint: () => showHistoryKeybindingHint(this.keybindingService) - })); - this._register(attachInputBoxStyler(this.filterInputBox, this.themeService)); - this.filterInputBox.value = this.commentsView.filters.filterText; - this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox!)))); - this._register(this.commentsView.filters.onDidChange((event: CommentsFiltersChangeEvent) => { - if (event.filterText) { - this.filterInputBox!.value = this.commentsView.filters.filterText; - } - })); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox!))); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.CLICK, (e) => { - e.stopPropagation(); - e.preventDefault(); - })); - - const focusTracker = this._register(DOM.trackFocus(this.filterInputBox.inputElement)); - this._register(focusTracker.onDidFocus(() => this.focusContextKey.set(true))); - this._register(focusTracker.onDidBlur(() => this.focusContextKey.set(false))); - this._register(toDisposable(() => this.focusContextKey.reset())); - } - - private createControls(container: HTMLElement): void { - const controlsContainer = DOM.append(container, DOM.$('.comments-panel-filter-controls')); - this.createBadge(controlsContainer); - this.createFilters(controlsContainer); - } - - private createBadge(container: HTMLElement): void { - const filterBadge = this.filterBadge = DOM.append(container, DOM.$('.comments-panel-filter-badge')); - this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; - - filterBadge.style.backgroundColor = background; - - filterBadge.style.borderWidth = border ? '1px' : ''; - filterBadge.style.borderStyle = border ? 'solid' : ''; - filterBadge.style.borderColor = border; - filterBadge.style.color = foreground; - })); - this.updateBadge(); - this._register(this.commentsView.onDidChangeFilterStats(() => this.updateBadge())); - } - - private createFilters(container: HTMLElement): void { - this.actionbar = this._register(new ActionBar(container, { - actionViewItemProvider: action => { - if (action.id === this.filtersAction.id) { - return this.instantiationService.createInstance(FiltersDropdownMenuActionViewItem, action, this.commentsView.filters, this.actionRunner); - } - return undefined; - } - })); - this.actionbar.push(this.filtersAction, { icon: true, label: false }); - } - - private onDidInputChange(inputbox: HistoryInputBox) { - inputbox.addToHistory(); - this.commentsView.filters.filterText = inputbox.value; - this.commentsView.filters.filterHistory = inputbox.getHistory(); - } - - private updateBadge(): void { - if (this.filterBadge) { - const { total, filtered } = this.commentsView.getFilterStats(); - this.filterBadge.classList.toggle('hidden', (total === filtered && !this.filterInputBox?.value) || total === 0); - this.filterBadge.textContent = localize('showing filtered comments', "Showing {0} of {1}", filtered, total); - this.adjustInputBox(); - } - } - - private adjustInputBox(): void { - if (this.element && this.filterInputBox && this.filterBadge) { - this.filterInputBox.inputElement.style.paddingRight = this.element.classList.contains('small') || this.filterBadge.classList.contains('hidden') ? '25px' : '150px'; - } - } - - // Action toolbar is swallowing some keys for action items which should not be for an input box - private handleKeyboardEvent(event: StandardKeyboardEvent) { - if (event.equals(KeyCode.Space) - || event.equals(KeyCode.LeftArrow) - || event.equals(KeyCode.RightArrow) - ) { - event.stopPropagation(); - } - } - - private onInputKeyDown(event: StandardKeyboardEvent, filterInputBox: HistoryInputBox) { - let handled = false; - if (event.equals(KeyCode.Tab)) { - this.actionbar?.focus(); - handled = true; - } - if (handled) { - event.stopPropagation(); - event.preventDefault(); - } - } - - protected override updateClass(): void { - if (this.element && this.container) { - this.element.className = this.class; - this.container.classList.toggle('grow', this.element.classList.contains('grow')); - this.adjustInputBox(); - } - } - - protected get class(): string { - if (this.commentsView.filters.layout.width > 600) { - return 'comments-panel-action-filter grow'; - } else if (this.commentsView.filters.layout.width < 400) { - return 'comments-panel-action-filter small'; - } else { - return 'comments-panel-action-filter'; - } - } } registerAction2(class extends ViewAction { @@ -409,23 +101,6 @@ registerAction2(class extends ViewAction { } }); -registerAction2(class extends Action2 { - constructor() { - super({ - _isFakeAction: true, - id: `workbench.actions.treeView.${COMMENTS_VIEW_ID}.filter`, - title: localize('filter', "Filter"), - menu: { - id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', COMMENTS_VIEW_ID), CommentsViewSmallLayoutContextKey.negate()), - group: 'navigation', - order: 1, - }, - }); - } - async run(): Promise { } -}); - registerAction2(class extends ViewAction { constructor() { super({ @@ -444,17 +119,52 @@ registerAction2(class extends ViewAction { } }); -registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { - const inputActiveOptionBorderColor = theme.getColor(inputActiveOptionBorder); - if (inputActiveOptionBorderColor) { - collector.addRule(`.comments-panel-action-filter > .comments-panel-filter-controls > .monaco-action-bar .action-label.comments-filters.checked { border-color: ${inputActiveOptionBorderColor}; }`); +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${COMMENTS_VIEW_ID}.toggleUnResolvedComments`, + title: localize('toggle unresolved', "Toggle Unresolved Comments"), + category: localize('comments', "Comments"), + toggled: { + condition: CONTEXT_KEY_SHOW_UNRESOLVED, + title: localize('unresolved', "Show Unresolved"), + }, + menu: { + id: viewFilterSubmenu, + group: '1_filter', + when: ContextKeyExpr.equals('view', COMMENTS_VIEW_ID), + order: 1 + }, + viewId: COMMENTS_VIEW_ID + }); } - const inputActiveOptionForegroundColor = theme.getColor(inputActiveOptionForeground); - if (inputActiveOptionForegroundColor) { - collector.addRule(`.comments-panel-action-filter > .comments-panel-filter-controls > .monaco-action-bar .action-label.comments-filters.checked { color: ${inputActiveOptionForegroundColor}; }`); - } - const inputActiveOptionBackgroundColor = theme.getColor(inputActiveOptionBackground); - if (inputActiveOptionBackgroundColor) { - collector.addRule(`.comments-panel-action-filter > .comments-panel-filter-controls > .monaco-action-bar .action-label.comments-filters.checked { background-color: ${inputActiveOptionBackgroundColor}; }`); + + async runInView(serviceAccessor: ServicesAccessor, view: ICommentsView): Promise { + view.filters.showUnresolved = !view.filters.showUnresolved; + } +}); + +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${COMMENTS_VIEW_ID}.toggleResolvedComments`, + title: localize('toggle resolved', "Toggle Resolved Comments"), + category: localize('comments', "Comments"), + toggled: { + condition: CONTEXT_KEY_SHOW_RESOLVED, + title: localize('resolved', "Show Resolved"), + }, + menu: { + id: viewFilterSubmenu, + group: '1_filter', + when: ContextKeyExpr.equals('view', COMMENTS_VIEW_ID), + order: 1 + }, + viewId: COMMENTS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: ICommentsView): Promise { + view.filters.showResolved = !view.filters.showResolved; } }); diff --git a/src/vs/workbench/contrib/comments/browser/media/panel.css b/src/vs/workbench/contrib/comments/browser/media/panel.css index db53571f495..1492f1dfee4 100644 --- a/src/vs/workbench/contrib/comments/browser/media/panel.css +++ b/src/vs/workbench/contrib/comments/browser/media/panel.css @@ -109,61 +109,6 @@ padding-left: 16px; } -.comments-panel-container .monaco-action-bar.comments-panel-filter-container .action-item.comments-panel-action-filter-container, -.panel > .title .monaco-action-bar .action-item.comments-panel-action-filter-container.grow { - flex: 1; -} - -.comments-panel-container .monaco-action-bar.comments-panel-filter-container { - margin: 10px 20px; - height: initial; -} - -.comments-panel-action-filter > .comments-panel-filter-controls { - position: absolute; - top: 0px; - bottom: 0; - right: 0px; - display: flex; - align-items: center; -} - -.comments-panel-action-filter > .comments-panel-filter-controls > .comments-panel-filter-badge { - margin: 4px 0px; - padding: 0px 8px; - border-radius: 2px; -} - -.comments-panel-action-filter > .comments-panel-filter-controls > .comments-panel-filter-badge.hidden, -.comments-panel-action-filter.small > .comments-panel-filter-controls > .comments-panel-filter-badge { - display: none; -} - -.comments-panel-action-filter > .comments-panel-filter-controls > .monaco-action-bar .action-item .action-label.codicon.comments-filters { - padding: 2px; -} - -.panel > .title .monaco-action-bar .action-item.comments-panel-action-filter-container { - max-width: 400px; - min-width: 300px; - margin-right: 10px; -} - -.monaco-action-bar .comments-panel-action-filter .monaco-inputbox { - height: 24px; - font-size: 12px; - flex: 1; -} - -.pane-header .monaco-action-bar .comments-panel-action-filter .monaco-inputbox { - height: 20px; - line-height: 18px; -} - -.monaco-workbench.vs .monaco-action-bar .comments-panel-action-filter .monaco-inputbox { - height: 25px; -} - .comments-panel .hide { display: none; } diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 6803c044720..b8ec701f315 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -142,53 +142,3 @@ } .monaco-workbench .repl .repl-tree .output.expression .code-subscript { vertical-align: sub; font-size: smaller; line-height: normal; } .monaco-workbench .repl .repl-tree .output.expression .code-superscript { vertical-align: super; font-size: smaller; line-height: normal; } - -.monaco-action-bar .action-item.repl-panel-filter-container { - cursor: default; - display: flex; -} - -.monaco-action-bar .panel-action-tree-filter{ - display: flex; - align-items: center; - flex: 1; -} - -.monaco-action-bar .panel-action-tree-filter .monaco-inputbox { - height: 24px; - font-size: 12px; - flex: 1; -} - -.pane-header .monaco-action-bar .panel-action-tree-filter .monaco-inputbox { - height: 20px; - line-height: 18px; -} - -.monaco-workbench.vs .monaco-action-bar .panel-action-tree-filter .monaco-inputbox { - height: 25px; -} - -.panel > .title .monaco-action-bar .action-item.repl-panel-filter-container { - min-width: 300px; - margin-right: 10px; -} - -.repl-panel-filter-container .repl-panel-filter-controls { - position: absolute; - top: 0px; - bottom: 0; - right: 0px; - display: flex; - align-items: center; -} - -.repl-panel-filter-container .repl-panel-filter-controls > .repl-panel-filter-badge { - margin: 4px; - padding: 0px 8px; - border-radius: 2px; -} - -.repl-panel-filter-container .repl-panel-filter-controls > .repl-panel-filter-badge.hidden { - display: none; -} diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 971f1e341f8..a1e6de4c6b7 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -44,7 +44,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { registerAndCreateHistoryNavigationContext } from 'vs/platform/history/browser/contextScopedHistoryWidget'; -import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -55,13 +54,13 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { IViewPaneOptions, ViewAction, ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; +import { FilterViewPane, IViewPaneOptions, ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views'; import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; import { debugConsoleClearAll, debugConsoleEvaluationPrompt } from 'vs/workbench/contrib/debug/browser/debugIcons'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; -import { ReplFilter, ReplFilterActionViewItem, ReplFilterState } from 'vs/workbench/contrib/debug/browser/replFilter'; +import { ReplFilter } from 'vs/workbench/contrib/debug/browser/replFilter'; import { ReplAccessibilityProvider, ReplDataSource, ReplDelegate, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplGroupRenderer, ReplRawObjectsRenderer, ReplSimpleElementsRenderer, ReplVariablesRenderer } from 'vs/workbench/contrib/debug/browser/replViewer'; import { CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_REPL, CONTEXT_MULTI_SESSION_REPL, DEBUG_SCHEME, getStateLabel, IDebugConfiguration, IDebugService, IDebugSession, IReplConfiguration, IReplElement, IReplOptions, REPL_VIEW_ID, State } from 'vs/workbench/contrib/debug/common/debug'; import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; @@ -74,7 +73,6 @@ const HISTORY_STORAGE_KEY = 'debug.repl.history'; const FILTER_HISTORY_STORAGE_KEY = 'debug.repl.filterHistory'; const FILTER_VALUE_STORAGE_KEY = 'debug.repl.filterValue'; const DECORATION_KEY = 'replinputdecoration'; -const FILTER_ACTION_ID = `workbench.actions.treeView.repl.filter`; function revealLastElement(tree: WorkbenchAsyncDataTree) { tree.scrollTop = tree.scrollHeight - tree.renderHeight; @@ -84,7 +82,7 @@ function revealLastElement(tree: WorkbenchAsyncDataTree) { const sessionsToIgnore = new Set(); const identityProvider = { getId: (element: IReplElement) => element.getId() }; -export class Repl extends ViewPane implements IHistoryNavigationWidget { +export class Repl extends FilterViewPane implements IHistoryNavigationWidget { declare readonly _serviceBrand: undefined; private static readonly REFRESH_DELAY = 50; // delay in ms to refresh the repl for new elements to show @@ -99,7 +97,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { private treeContainer!: HTMLElement; private replInput!: CodeEditorWidget; private replInputContainer!: HTMLElement; - private dimension!: dom.Dimension; + private bodyContentDimension: dom.Dimension | undefined; private replInputLineCount = 1; private model: ITextModel | undefined; private setHistoryNavigationEnablement!: (enabled: boolean) => void; @@ -109,8 +107,6 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { private completionItemProvider: IDisposable | undefined; private modelChangeListener: IDisposable = Disposable.None; private filter: ReplFilter; - private filterState: ReplFilterState; - private filterActionViewItem: ReplFilterActionViewItem | undefined; private multiSessionRepl: IContextKey; private menu: IMenu; @@ -134,14 +130,21 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { @IMenuService menuService: IMenuService, @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, ) { - super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); + const filterText = storageService.get(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE, ''); + super({ + ...options, + filterOptions: { + placeholder: localize({ key: 'workbench.debug.filter.placeholder', comment: ['Text in the brackets after e.g. is not localizable'] }, "Filter (e.g. text, !exclude)"), + text: filterText, + history: JSON.parse(storageService.get(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')) as string[], + } + }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); this.menu = menuService.createMenu(MenuId.DebugConsoleContext, contextKeyService); this._register(this.menu); this.history = new HistoryNavigator(JSON.parse(this.storageService.get(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')), 50); this.filter = new ReplFilter(); - this.filterState = new ReplFilterState(this); - this.filter.filterQuery = this.filterState.filterText = this.storageService.get(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE, ''); + this.filter.filterQuery = filterText; this.multiSessionRepl = CONTEXT_MULTI_SESSION_REPL.bindTo(contextKeyService); this.replOptions = this._register(this.instantiationService.createInstance(ReplOptions, this.id, () => this.getBackgroundColor())); this._register(this.replOptions.onDidChange(() => this.onDidStyleChange())); @@ -186,7 +189,6 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.replInput.setModel(this.model); this.updateInputDecoration(); this.refreshReplElements(true); - this.layoutBody(this.dimension.height, this.dimension.width); } })); this._register(this.configurationService.onDidChangeConfiguration(e => { @@ -208,8 +210,8 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.setMode(); })); - this._register(this.filterState.onDidChange(() => { - this.filter.filterQuery = this.filterState.filterText; + this._register(this.filterWidget.onDidChangeFilterText(() => { + this.filter.filterQuery = this.filterWidget.getFilterText(); this.tree.refilter(); revealLastElement(this.tree); })); @@ -318,7 +320,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } focusFilter(): void { - this.filterActionViewItem?.focus(); + this.filterWidget.focus(); } private setMode(): void { @@ -364,8 +366,8 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.tree.rerender(); - if (this.dimension) { - this.layoutBody(this.dimension.height, this.dimension.width); + if (this.bodyContentDimension) { + this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); } } } @@ -431,9 +433,9 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.replInput.setValue(''); const shouldRelayout = this.replInputLineCount > 1; this.replInputLineCount = 1; - if (shouldRelayout) { + if (shouldRelayout && this.bodyContentDimension) { // Trigger a layout to shrink a potential multi line input - this.layoutBody(this.dimension.height, this.dimension.width); + this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); } } } @@ -458,9 +460,8 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { return removeAnsiEscapeCodes(text); } - protected override layoutBody(height: number, width: number): void { - super.layoutBody(height, width); - this.dimension = new dom.Dimension(width, height); + protected override layoutBodyContent(height: number, width: number): void { + this.bodyContentDimension = new dom.Dimension(width, height); const replInputHeight = Math.min(this.replInput.getContentHeight(), height); if (this.tree) { const lastElementVisible = this.tree.scrollTop + this.tree.renderHeight >= this.tree.scrollHeight; @@ -476,6 +477,10 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.replInput.layout({ width: width - 30, height: replInputHeight }); } + override shouldShowFilterInHeader(): boolean { + return true; + } + collapseAll(): void { this.tree.collapseAll(); } @@ -492,11 +497,6 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { if (action.id === selectReplCommandId) { const session = (this.tree ? this.tree.getInput() : undefined) ?? this.debugService.getViewModel().focusedSession; return this.instantiationService.createInstance(SelectReplActionViewItem, action, session); - } else if (action.id === FILTER_ACTION_ID) { - const filterHistory = JSON.parse(this.storageService.get(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')) as string[]; - this.filterActionViewItem = this.instantiationService.createInstance(ReplFilterActionViewItem, action, - localize({ key: 'workbench.debug.filter.placeholder', comment: ['Text in the brackets after e.g. is not localizable'] }, "Filter (e.g. text, !exclude)"), this.filterState, filterHistory, () => showHistoryKeybindingHint(this.keybindingService)); - return this.filterActionViewItem; } return super.getActionViewItem(action); @@ -538,7 +538,8 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { await autoExpandElements(session.getReplElements()); } // Repl elements count changed, need to update filter stats on the badge - this.filterState.updateFilterStats(); + const { total, filtered } = this.getFilterStats(); + this.filterWidget.updateBadge(total === filtered || total === 0 ? undefined : localize('showing filtered repl lines', "Showing {0} of {1}", filtered, total)); }, Repl.REFRESH_DELAY); } @@ -645,7 +646,9 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { const lineCount = model ? Math.min(10, model.getLineCount()) : 1; if (lineCount !== this.replInputLineCount) { this.replInputLineCount = lineCount; - this.layoutBody(this.dimension.height, this.dimension.width); + if (this.bodyContentDimension) { + this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); + } } })); // We add the input decoration only when the focus is in the input #61126 @@ -712,19 +715,17 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } else { this.storageService.remove(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE); } - if (this.filterActionViewItem) { - const filterHistory = this.filterActionViewItem.getHistory(); - if (filterHistory.length) { - this.storageService.store(FILTER_HISTORY_STORAGE_KEY, JSON.stringify(filterHistory), StorageScope.WORKSPACE, StorageTarget.USER); - } else { - this.storageService.remove(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE); - } - const filterValue = this.filterState.filterText; - if (filterValue) { - this.storageService.store(FILTER_VALUE_STORAGE_KEY, filterValue, StorageScope.WORKSPACE, StorageTarget.USER); - } else { - this.storageService.remove(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE); - } + const filterHistory = this.filterWidget.getHistory(); + if (filterHistory.length) { + this.storageService.store(FILTER_HISTORY_STORAGE_KEY, JSON.stringify(filterHistory), StorageScope.WORKSPACE, StorageTarget.USER); + } else { + this.storageService.remove(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE); + } + const filterValue = this.filterWidget.getFilterText(); + if (filterValue) { + this.storageService.store(FILTER_VALUE_STORAGE_KEY, filterValue, StorageScope.WORKSPACE, StorageTarget.USER); + } else { + this.storageService.remove(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE); } super.saveState(); @@ -876,27 +877,6 @@ function getReplView(viewsService: IViewsService): Repl | undefined { return viewsService.getActiveViewWithId(REPL_VIEW_ID) as Repl ?? undefined; } -registerAction2(class extends Action2 { - constructor() { - super({ - _isFakeAction: true, - id: FILTER_ACTION_ID, - title: localize('filter', "Filter"), - f1: false, - menu: { - id: MenuId.ViewTitle, - group: 'navigation', - when: ContextKeyExpr.equals('view', REPL_VIEW_ID), - order: 10 - }, - }); - } - - run(_accessor: ServicesAccessor) { - // noop this action is just a placeholder for the filter action view item - } -}); - const selectReplCommandId = 'workbench.action.debug.selectRepl'; registerAction2(class extends ViewAction { constructor() { diff --git a/src/vs/workbench/contrib/debug/browser/replFilter.ts b/src/vs/workbench/contrib/debug/browser/replFilter.ts index 368979c2d24..ad5370e9fdc 100644 --- a/src/vs/workbench/contrib/debug/browser/replFilter.ts +++ b/src/vs/workbench/contrib/debug/browser/replFilter.ts @@ -7,23 +7,7 @@ import { matchesFuzzy } from 'vs/base/common/filters'; import { splitGlobAware } from 'vs/base/common/glob'; import { ITreeFilter, TreeVisibility, TreeFilterResult } from 'vs/base/browser/ui/tree/tree'; import { IReplElement } from 'vs/workbench/contrib/debug/common/debug'; -import * as DOM from 'vs/base/browser/dom'; -import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { Delayer } from 'vs/base/common/async'; -import { IAction } from 'vs/base/common/actions'; -import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { toDisposable } from 'vs/base/common/lifecycle'; -import { Event, Emitter } from 'vs/base/common/event'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { ContextScopedHistoryInputBox } from 'vs/platform/history/browser/contextScopedHistoryWidget'; -import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { ReplEvaluationResult, ReplEvaluationInput } from 'vs/workbench/contrib/debug/common/replModel'; -import { localize } from 'vs/nls'; import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; @@ -79,184 +63,3 @@ export class ReplFilter implements ITreeFilter { return includeQueryPresent ? includeQueryMatched : (typeof parentVisibility !== 'undefined' ? parentVisibility : TreeVisibility.Visible); } } - -export interface IFilterStatsProvider { - getFilterStats(): { total: number; filtered: number }; -} - -export class ReplFilterState { - - constructor(private filterStatsProvider: IFilterStatsProvider) { } - - private readonly _onDidChange: Emitter = new Emitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - private readonly _onDidStatsChange: Emitter = new Emitter(); - get onDidStatsChange(): Event { - return this._onDidStatsChange.event; - } - - private _filterText = ''; - private _stats = { total: 0, filtered: 0 }; - - get filterText(): string { - return this._filterText; - } - - get filterStats(): { total: number; filtered: number } { - return this._stats; - } - - set filterText(filterText: string) { - if (this._filterText !== filterText) { - this._filterText = filterText; - this._onDidChange.fire(); - this.updateFilterStats(); - } - } - - updateFilterStats(): void { - const { total, filtered } = this.filterStatsProvider.getFilterStats(); - if (this._stats.total !== total || this._stats.filtered !== filtered) { - this._stats = { total, filtered }; - this._onDidStatsChange.fire(); - } - } -} - -export class ReplFilterActionViewItem extends BaseActionViewItem { - - private delayedFilterUpdate: Delayer; - private container!: HTMLElement; - private filterBadge!: HTMLElement; - private filterInputBox!: HistoryInputBox; - - constructor( - action: IAction, - private placeholder: string, - private filters: ReplFilterState, - private history: string[], - private showHistoryHint: () => boolean, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IThemeService private readonly themeService: IThemeService, - @IContextViewService private readonly contextViewService: IContextViewService) { - super(null, action); - this.delayedFilterUpdate = new Delayer(400); - this._register(toDisposable(() => this.delayedFilterUpdate.cancel())); - } - - override render(container: HTMLElement): void { - this.container = container; - this.container.classList.add('repl-panel-filter-container'); - - this.element = DOM.append(this.container, DOM.$('')); - this.element.className = this.class; - this.createInput(this.element); - this.createBadge(this.element); - this.updateClass(); - } - - override focus(): void { - this.filterInputBox?.focus(); - } - - override blur(): void { - this.filterInputBox?.blur(); - } - - override setFocusable(): void { - // noop input elements are focusable by default - } - - getHistory(): string[] { - return this.filterInputBox.getHistory(); - } - - override get trapsArrowNavigation(): boolean { - return true; - } - - private clearFilterText(): void { - this.filterInputBox.value = ''; - } - - private createInput(container: HTMLElement): void { - this.filterInputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, { - placeholder: this.placeholder, - history: this.history, - showHistoryHint: this.showHistoryHint - })); - this._register(attachInputBoxStyler(this.filterInputBox, this.themeService)); - this.filterInputBox.value = this.filters.filterText; - - this._register(this.filterInputBox.onDidChange(() => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox!)))); - this._register(this.filters.onDidChange(() => { - this.filterInputBox.value = this.filters.filterText; - })); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e))); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.CLICK, (e) => { - e.stopPropagation(); - e.preventDefault(); - })); - } - - private onDidInputChange(inputbox: HistoryInputBox) { - inputbox.addToHistory(); - this.filters.filterText = inputbox.value; - } - - // Action toolbar is swallowing some keys for action items which should not be for an input box - private handleKeyboardEvent(event: StandardKeyboardEvent) { - if (event.equals(KeyCode.Space) - || event.equals(KeyCode.LeftArrow) - || event.equals(KeyCode.RightArrow) - || event.equals(KeyCode.Escape) - ) { - event.stopPropagation(); - } - } - - private onInputKeyDown(event: StandardKeyboardEvent) { - if (event.equals(KeyCode.Escape)) { - this.clearFilterText(); - event.stopPropagation(); - event.preventDefault(); - } - } - - private createBadge(container: HTMLElement): void { - const controlsContainer = DOM.append(container, DOM.$('.repl-panel-filter-controls')); - const filterBadge = this.filterBadge = DOM.append(controlsContainer, DOM.$('.repl-panel-filter-badge')); - this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; - - filterBadge.style.backgroundColor = background; - - filterBadge.style.borderWidth = border ? '1px' : ''; - filterBadge.style.borderStyle = border ? 'solid' : ''; - filterBadge.style.borderColor = border; - filterBadge.style.color = foreground; - })); - this.updateBadge(); - this._register(this.filters.onDidStatsChange(() => this.updateBadge())); - } - - private updateBadge(): void { - const { total, filtered } = this.filters.filterStats; - const filterBadgeHidden = total === filtered || total === 0; - - this.filterBadge.classList.toggle('hidden', filterBadgeHidden); - this.filterBadge.textContent = localize('showing filtered repl lines', "Showing {0} of {1}", filtered, total); - this.filterInputBox.inputElement.style.paddingRight = filterBadgeHidden ? '4px' : '150px'; - } - - protected get class(): string { - return 'panel-action-tree-filter'; - } -} diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index d31a252577c..275a84b8c9a 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -32,6 +32,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { viewFilterSubmenu } from 'vs/workbench/browser/parts/views/viewFilter'; KeybindingsRegistry.registerCommandAndKeybindingRule({ id: Markers.MARKER_OPEN_ACTION_ID, @@ -196,6 +197,131 @@ registerAction2(class extends ViewAction { } }); +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${Markers.MARKERS_VIEW_ID}.toggleErrors`, + title: localize('toggle errors', "Toggle Errors"), + category: localize('problems', "Problems"), + toggled: { + condition: MarkersContextKeys.ShowErrorsFilterContextKey, + title: localize('errors', "Show Errors") + }, + menu: { + id: viewFilterSubmenu, + group: '1_filter', + when: ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), + order: 1 + }, + viewId: Markers.MARKERS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { + view.filters.showErrors = !view.filters.showErrors; + } +}); + +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${Markers.MARKERS_VIEW_ID}.toggleWarnings`, + title: localize('toggle warnings', "Toggle Warnings"), + category: localize('problems', "Problems"), + toggled: { + condition: MarkersContextKeys.ShowWarningsFilterContextKey, + title: localize('warnings', "Show Warnings") + }, + menu: { + id: viewFilterSubmenu, + group: '1_filter', + when: ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), + order: 2 + }, + viewId: Markers.MARKERS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { + view.filters.showWarnings = !view.filters.showWarnings; + } +}); + +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${Markers.MARKERS_VIEW_ID}.toggleInfos`, + title: localize('toggle infos', "Toggle Infos"), + category: localize('problems', "Problems"), + toggled: { + condition: MarkersContextKeys.ShowInfoFilterContextKey, + title: localize('Infos', "Show Infos") + }, + menu: { + id: viewFilterSubmenu, + group: '1_filter', + when: ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), + order: 3 + }, + viewId: Markers.MARKERS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { + view.filters.showInfos = !view.filters.showInfos; + } +}); + +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${Markers.MARKERS_VIEW_ID}.toggleActiveFile`, + title: localize('toggle active file', "Toggle Active File"), + category: localize('problems', "Problems"), + toggled: { + condition: MarkersContextKeys.ShowActiveFileFilterContextKey, + title: localize('Active File', "Show Active File Only") + }, + menu: { + id: viewFilterSubmenu, + group: '2_filter', + when: ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), + order: 1 + }, + viewId: Markers.MARKERS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { + view.filters.activeFile = !view.filters.activeFile; + } +}); + +registerAction2(class extends ViewAction { + constructor() { + super({ + id: `workbench.actions.${Markers.MARKERS_VIEW_ID}.toggleExcludedFiles`, + title: localize('toggle Excluded Files', "Toggle Excluded Files"), + category: localize('problems', "Problems"), + toggled: { + condition: MarkersContextKeys.ShowExcludedFilesFilterContextKey, + title: localize('Excluded Files', "Hide Excluded Files") + }, + menu: { + id: viewFilterSubmenu, + group: '2_filter', + when: ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), + order: 2 + }, + viewId: Markers.MARKERS_VIEW_ID + }); + } + + async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { + view.filters.excludedFiles = !view.filters.excludedFiles; + } +}); + registerAction2(class extends Action2 { constructor() { super({ @@ -406,23 +532,6 @@ registerAction2(class extends ViewAction { } }); -registerAction2(class extends Action2 { - constructor() { - super({ - _isFakeAction: true, - id: `workbench.actions.treeView.${Markers.MARKERS_VIEW_ID}.filter`, - title: localize('filter', "Filter"), - menu: { - id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersViewSmallLayoutContextKey.negate()), - group: 'navigation', - order: 1, - }, - }); - } - async run(): Promise { } -}); - registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts index 0969177554d..d1d3f5cf7f6 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.ts @@ -4,17 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { MarkersFilters } from 'vs/workbench/contrib/markers/browser/markersViewActions'; -import { Event } from 'vs/base/common/event'; import { IView } from 'vs/workbench/common/views'; import { MarkerElement, ResourceMarkers } from 'vs/workbench/contrib/markers/browser/markersModel'; import { MarkersViewMode } from 'vs/workbench/contrib/markers/common/markers'; export interface IMarkersView extends IView { - readonly onDidFocusFilter: Event; - readonly onDidClearFilterText: Event; readonly filters: MarkersFilters; - readonly onDidChangeFilterStats: Event<{ total: number; filtered: number }>; focusFilter(): void; clearFilterText(): void; getFilterStats(): { total: number; filtered: number }; diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index bf9a407742a..f54ff823334 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -7,12 +7,12 @@ import 'vs/css!./media/markers'; import { URI } from 'vs/base/common/uri'; import * as dom from 'vs/base/browser/dom'; -import { IAction, Action, Separator } from 'vs/base/common/actions'; +import { IAction, Separator } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { Marker, ResourceMarkers, RelatedInformation, MarkerChangesEvent, MarkersModel, compareMarkersByUri, MarkerElement, MarkerTableItem } from 'vs/workbench/contrib/markers/browser/markersModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { MarkersFilterActionViewItem, MarkersFilters, IMarkersFiltersChangeEvent } from 'vs/workbench/contrib/markers/browser/markersViewActions'; +import { MarkersFilters, IMarkersFiltersChangeEvent } from 'vs/workbench/contrib/markers/browser/markersViewActions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; import { RangeHighlightDecorations } from 'vs/workbench/browser/codeeditor'; @@ -23,7 +23,7 @@ import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Iterable } from 'vs/base/common/iterator'; import { ITreeElement, ITreeNode, ITreeContextMenuEvent, ITreeRenderer, ITreeEvent } from 'vs/base/browser/ui/tree/tree'; -import { Relay, Event, Emitter } from 'vs/base/common/event'; +import { Relay, Event } from 'vs/base/common/event'; import { WorkbenchObjectTree, IListService, IWorkbenchObjectTreeOptions, IOpenEvent } from 'vs/platform/list/browser/listService'; import { FilterOptions } from 'vs/workbench/contrib/markers/browser/markersFilterOptions'; import { IExpression } from 'vs/base/common/glob'; @@ -31,7 +31,6 @@ import { deepClone } from 'vs/base/common/objects'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, MarkersWidgetAccessibilityProvider, MarkersViewModel } from 'vs/workbench/contrib/markers/browser/markersTreeViewer'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { MenuId } from 'vs/platform/actions/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -42,7 +41,7 @@ import { MementoObject, Memento } from 'vs/workbench/common/memento'; import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { KeyCode } from 'vs/base/common/keyCodes'; import { editorLightBulbForeground, editorLightBulbAutoFixForeground } from 'vs/platform/theme/common/colorRegistry'; -import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane'; +import { IViewPaneOptions, FilterViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IOpenerService, withSelection } from 'vs/platform/opener/common/opener'; import { Codicon } from 'vs/base/common/codicons'; @@ -94,7 +93,7 @@ export interface IProblemsWidget { updateMarker(marker: Marker): void; } -export class MarkersView extends ViewPane implements IMarkersView { +export class MarkersView extends FilterViewPane implements IMarkersView { private lastSelectedRelativeTop: number = 0; private currentActiveResource: URI | null = null; @@ -109,7 +108,6 @@ export class MarkersView extends ViewPane implements IMarkersView { private widgetContainer!: HTMLElement; private widgetIdentityProvider: IIdentityProvider; private widgetAccessibilityProvider: MarkersWidgetAccessibilityProvider; - private filterActionBar: ActionBar | undefined; private messageBoxContainer: HTMLElement | undefined; private ariaLabelElement: HTMLElement | undefined; readonly filters: MarkersFilters; @@ -118,24 +116,13 @@ export class MarkersView extends ViewPane implements IMarkersView { private currentWidth = 0; private readonly panelState: MementoObject; - private _onDidChangeFilterStats = this._register(new Emitter<{ total: number; filtered: number }>()); - readonly onDidChangeFilterStats: Event<{ total: number; filtered: number }> = this._onDidChangeFilterStats.event; private cachedFilterStats: { total: number; filtered: number } | undefined = undefined; private currentResourceGotAddedToMarkersData: boolean = false; private readonly markersViewModel: MarkersViewModel; - private readonly smallLayoutContextKey: IContextKey; - private get smallLayout(): boolean { return !!this.smallLayoutContextKey.get(); } - private set smallLayout(smallLayout: boolean) { this.smallLayoutContextKey.set(smallLayout); } readonly onDidChangeVisibility = this.onDidChangeBodyVisibility; - private readonly _onDidFocusFilter: Emitter = this._register(new Emitter()); - readonly onDidFocusFilter: Event = this._onDidFocusFilter.event; - - private readonly _onDidClearFilterText: Emitter = this._register(new Emitter()); - readonly onDidClearFilterText: Event = this._onDidClearFilterText.event; - constructor( options: IViewPaneOptions, @IInstantiationService instantiationService: IInstantiationService, @@ -153,9 +140,18 @@ export class MarkersView extends ViewPane implements IMarkersView { @IOpenerService openerService: IOpenerService, @IThemeService themeService: IThemeService, ) { - super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); - this.smallLayoutContextKey = MarkersContextKeys.MarkersViewSmallLayoutContextKey.bindTo(this.contextKeyService); - this.panelState = new Memento(Markers.MARKERS_VIEW_STORAGE_ID, storageService).getMemento(StorageScope.WORKSPACE, StorageTarget.USER); + const panelState = new Memento(Markers.MARKERS_VIEW_STORAGE_ID, storageService).getMemento(StorageScope.WORKSPACE, StorageTarget.USER); + super({ + ...options, + filterOptions: { + ariaLabel: Messages.MARKERS_PANEL_FILTER_ARIA_LABEL, + placeholder: Messages.MARKERS_PANEL_FILTER_PLACEHOLDER, + focusContextKey: MarkersContextKeys.MarkerViewFilterFocusContextKey.key, + text: panelState['filter'] || '', + history: panelState['filterHistory'] || [] + } + }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); + this.panelState = panelState; this.markersModel = this._register(instantiationService.createInstance(MarkersModel)); this.markersViewModel = this._register(instantiationService.createInstance(MarkersViewModel, this.panelState['multiline'], this.panelState['viewMode'] ?? this.getDefaultViewMode())); @@ -171,15 +167,13 @@ export class MarkersView extends ViewPane implements IMarkersView { this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); this.filters = this._register(new MarkersFilters({ - filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], showErrors: this.panelState['showErrors'] !== false, showWarnings: this.panelState['showWarnings'] !== false, showInfos: this.panelState['showInfos'] !== false, excludedFiles: !!this.panelState['useFilesExclude'], activeFile: !!this.panelState['activeFile'], - layout: new dom.Dimension(0, 0) - })); + }, this.contextKeyService)); // Update filter, whenever the "files.exclude" setting is changed this._register(this.configurationService.onDidChangeConfiguration(e => { @@ -203,9 +197,6 @@ export class MarkersView extends ViewPane implements IMarkersView { this.createArialLabelElement(panelContainer); - this.createFilterActionBar(panelContainer); - this.filterActionBar!.push(new Action(`workbench.actions.treeView.${this.id}.filter`)); - this.createMessageBox(panelContainer); this.widgetContainer = dom.append(panelContainer, dom.$('.widget-container')); @@ -219,19 +210,11 @@ export class MarkersView extends ViewPane implements IMarkersView { return Messages.MARKERS_PANEL_TITLE_PROBLEMS; } - public override layoutBody(height: number = this.currentHeight, width: number = this.currentWidth): void { - super.layoutBody(height, width); - const wasSmallLayout = this.smallLayout; - this.smallLayout = width < 600 && height > 100; - if (this.smallLayout !== wasSmallLayout) { - this.filterActionBar?.getContainer().classList.toggle('hide', !this.smallLayout); - } - const contentHeight = this.smallLayout ? height - 44 : height; + public override layoutBodyContent(height: number = this.currentHeight, width: number = this.currentWidth): void { if (this.messageBoxContainer) { - this.messageBoxContainer.style.height = `${contentHeight}px`; + this.messageBoxContainer.style.height = `${height}px`; } - this.widget.layout(contentHeight, width); - this.filters.layout = new dom.Dimension(this.smallLayout ? width : width - 200, height); + this.widget.layout(height, width); this.currentHeight = height; this.currentWidth = width; @@ -251,11 +234,19 @@ export class MarkersView extends ViewPane implements IMarkersView { } public focusFilter(): void { - this._onDidFocusFilter.fire(); + this.filterWidget.focus(); + } + + public updateBadge(total: number, filtered: number): void { + this.filterWidget.updateBadge(total === filtered || total === 0 ? undefined : localize('showing filtered problems', "Showing {0} of {1}", filtered, total)); + } + + public checkMoreFilters(): void { + this.filterWidget.checkMoreFilters(!this.filters.showErrors || !this.filters.showWarnings || !this.filters.showInfos || this.filters.excludedFiles || this.filters.activeFile); } public clearFilterText(): void { - this._onDidClearFilterText.fire(); + this.filterWidget.setFilterText(''); } public showQuickFixes(marker: Marker): void { @@ -323,7 +314,8 @@ export class MarkersView extends ViewPane implements IMarkersView { this.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); - this._onDidChangeFilterStats.fire(this.getFilterStats()); + this.updateBadge(total, filtered); + this.checkMoreFilters(); } } @@ -336,7 +328,7 @@ export class MarkersView extends ViewPane implements IMarkersView { } private updateFilter() { - this.filter.options = new FilterOptions(this.filters.filterText, this.getFilesExcludeExpressions(), this.filters.showWarnings, this.filters.showErrors, this.filters.showInfos, this.uriIdentityService); + this.filter.options = new FilterOptions(this.filterWidget.getFilterText(), this.getFilesExcludeExpressions(), this.filters.showWarnings, this.filters.showErrors, this.filters.showInfos, this.uriIdentityService); this.widget.filterMarkers(this.getResourceMarkers(), this.filter.options); this.cachedFilterStats = undefined; @@ -344,7 +336,8 @@ export class MarkersView extends ViewPane implements IMarkersView { this.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); - this._onDidChangeFilterStats.fire(this.getFilterStats()); + this.updateBadge(total, filtered); + this.checkMoreFilters(); } private getDefaultViewMode(): MarkersViewMode { @@ -389,12 +382,6 @@ export class MarkersView extends ViewPane implements IMarkersView { return resourceMarkers; } - private createFilterActionBar(parent: HTMLElement): void { - this.filterActionBar = this._register(new ActionBar(parent, { actionViewItemProvider: action => this.getActionViewItem(action) })); - this.filterActionBar.getContainer().classList.add('markers-panel-filter-container'); - this.filterActionBar.getContainer().classList.toggle('hide', !this.smallLayout); - } - private createMessageBox(parent: HTMLElement): void { this.messageBoxContainer = dom.append(parent, dom.$('.message-box-container')); this.messageBoxContainer.setAttribute('aria-labelledby', 'markers-panel-arialabel'); @@ -558,10 +545,11 @@ export class MarkersView extends ViewPane implements IMarkersView { disposables.push(this.filters.onDidChange((event: IMarkersFiltersChangeEvent) => { if (event.activeFile) { this.refreshPanel(); - } else if (event.filterText || event.excludedFiles || event.showWarnings || event.showErrors || event.showInfos) { + } else if (event.excludedFiles || event.showWarnings || event.showErrors || event.showInfos) { this.updateFilter(); } })); + disposables.push(this.filterWidget.onDidChangeFilterText(e => this.updateFilter())); disposables.push(toDisposable(() => { this.cachedFilterStats = undefined; })); disposables.push(toDisposable(() => this.rangeHighlightDecorations.removeHighlightRange())); @@ -744,7 +732,7 @@ export class MarkersView extends ViewPane implements IMarkersView { } private clearFilters(): void { - this.filters.filterText = ''; + this.filterWidget.setFilterText(''); this.filters.excludedFiles = false; this.filters.showErrors = true; this.filters.showWarnings = true; @@ -862,13 +850,6 @@ export class MarkersView extends ViewPane implements IMarkersView { return this.markersModel.resourceMarkers; } - public override getActionViewItem(action: IAction): IActionViewItem | undefined { - if (action.id === `workbench.actions.treeView.${this.id}.filter`) { - return this.instantiationService.createInstance(MarkersFilterActionViewItem, action, this); - } - return super.getActionViewItem(action); - } - getFilterStats(): { total: number; filtered: number } { if (!this.cachedFilterStats) { this.cachedFilterStats = { @@ -882,11 +863,11 @@ export class MarkersView extends ViewPane implements IMarkersView { private toggleVisibility(hide: boolean): void { this.widget.toggleVisibility(hide); - this.layoutBody(); + this.layoutBodyContent(); } override saveState(): void { - this.panelState['filter'] = this.filters.filterText; + this.panelState['filter'] = this.filterWidget.getFilterText(); this.panelState['filterHistory'] = this.filters.filterHistory; this.panelState['showErrors'] = this.filters.showErrors; this.panelState['showWarnings'] = this.filters.showWarnings; diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index 3b0da4b071d..65d23126b72 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -3,54 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; -import { Action, IAction, IActionRunner, Separator } from 'vs/base/common/actions'; -import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { Action, IAction } from 'vs/base/common/actions'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; -import { IThemeService, registerThemingParticipant, ICssStyleCollector, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { toDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { badgeBackground, badgeForeground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry'; -import { localize } from 'vs/nls'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ContextScopedHistoryInputBox } from 'vs/platform/history/browser/contextScopedHistoryWidget'; +import { registerThemingParticipant, ICssStyleCollector, IColorTheme } from 'vs/platform/theme/common/themeService'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry'; import { Marker } from 'vs/workbench/contrib/markers/browser/markersModel'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; -import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { Codicon } from 'vs/base/common/codicons'; -import { BaseActionViewItem, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; -import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { IMarkersView } from 'vs/workbench/contrib/markers/browser/markers'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; +import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { MarkersContextKeys } from 'vs/workbench/contrib/markers/common/markers'; export interface IMarkersFiltersChangeEvent { - filterText?: boolean; excludedFiles?: boolean; showWarnings?: boolean; showErrors?: boolean; showInfos?: boolean; activeFile?: boolean; - layout?: boolean; } export interface IMarkersFiltersOptions { - filterText: string; filterHistory: string[]; showErrors: boolean; showWarnings: boolean; showInfos: boolean; excludedFiles: boolean; activeFile: boolean; - layout: DOM.Dimension; } export class MarkersFilters extends Disposable { @@ -58,384 +39,74 @@ export class MarkersFilters extends Disposable { private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(options: IMarkersFiltersOptions) { + constructor(options: IMarkersFiltersOptions, private readonly contextKeyService: IContextKeyService) { super(); - this._filterText = options.filterText; - this._showErrors = options.showErrors; - this._showWarnings = options.showWarnings; - this._showInfos = options.showInfos; - this._excludedFiles = options.excludedFiles; - this._activeFile = options.activeFile; - this.filterHistory = options.filterHistory; - this._layout = options.layout; - } - private _filterText: string; - get filterText(): string { - return this._filterText; - } - set filterText(filterText: string) { - if (this._filterText !== filterText) { - this._filterText = filterText; - this._onDidChange.fire({ filterText: true }); - } + this._showErrors.set(options.showErrors); + this._showWarnings.set(options.showWarnings); + this._showInfos.set(options.showInfos); + this._excludedFiles.set(options.excludedFiles); + this._activeFile.set(options.activeFile); + this.filterHistory = options.filterHistory; } filterHistory: string[]; - private _excludedFiles: boolean; + private readonly _excludedFiles = MarkersContextKeys.ShowExcludedFilesFilterContextKey.bindTo(this.contextKeyService); get excludedFiles(): boolean { - return this._excludedFiles; + return !!this._excludedFiles.get(); } set excludedFiles(filesExclude: boolean) { - if (this._excludedFiles !== filesExclude) { - this._excludedFiles = filesExclude; + if (this._excludedFiles.get() !== filesExclude) { + this._excludedFiles.set(filesExclude); this._onDidChange.fire({ excludedFiles: true }); } } - private _activeFile: boolean; + private readonly _activeFile = MarkersContextKeys.ShowActiveFileFilterContextKey.bindTo(this.contextKeyService); get activeFile(): boolean { - return this._activeFile; + return !!this._activeFile.get(); } set activeFile(activeFile: boolean) { - if (this._activeFile !== activeFile) { - this._activeFile = activeFile; + if (this._activeFile.get() !== activeFile) { + this._activeFile.set(activeFile); this._onDidChange.fire({ activeFile: true }); } } - private _showWarnings: boolean = true; + private readonly _showWarnings = MarkersContextKeys.ShowWarningsFilterContextKey.bindTo(this.contextKeyService); get showWarnings(): boolean { - return this._showWarnings; + return !!this._showWarnings.get(); } set showWarnings(showWarnings: boolean) { - if (this._showWarnings !== showWarnings) { - this._showWarnings = showWarnings; + if (this._showWarnings.get() !== showWarnings) { + this._showWarnings.set(showWarnings); this._onDidChange.fire({ showWarnings: true }); } } - private _showErrors: boolean = true; + private readonly _showErrors = MarkersContextKeys.ShowErrorsFilterContextKey.bindTo(this.contextKeyService); get showErrors(): boolean { - return this._showErrors; + return !!this._showErrors.get(); } set showErrors(showErrors: boolean) { - if (this._showErrors !== showErrors) { - this._showErrors = showErrors; + if (this._showErrors.get() !== showErrors) { + this._showErrors.set(showErrors); this._onDidChange.fire({ showErrors: true }); } } - private _showInfos: boolean = true; + private readonly _showInfos = MarkersContextKeys.ShowInfoFilterContextKey.bindTo(this.contextKeyService); get showInfos(): boolean { - return this._showInfos; + return !!this._showInfos.get(); } set showInfos(showInfos: boolean) { - if (this._showInfos !== showInfos) { - this._showInfos = showInfos; + if (this._showInfos.get() !== showInfos) { + this._showInfos.set(showInfos); this._onDidChange.fire({ showInfos: true }); } } - private _layout: DOM.Dimension = new DOM.Dimension(0, 0); - get layout(): DOM.Dimension { - return this._layout; - } - set layout(layout: DOM.Dimension) { - if (this._layout.width !== layout.width || this._layout.height !== layout.height) { - this._layout = layout; - this._onDidChange.fire({ layout: true }); - } - } -} - -class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem { - - constructor( - action: IAction, private filters: MarkersFilters, actionRunner: IActionRunner, - @IContextMenuService contextMenuService: IContextMenuService - ) { - super(action, - { getActions: () => this.getActions() }, - contextMenuService, - { - actionRunner, - classNames: action.class, - anchorAlignmentProvider: () => AnchorAlignment.RIGHT, - menuAsChild: true - } - ); - } - - override render(container: HTMLElement): void { - super.render(container); - this.updateChecked(); - } - - private getActions(): IAction[] { - return [ - { - checked: this.filters.showErrors, - class: undefined, - enabled: true, - id: 'showErrors', - label: Messages.MARKERS_PANEL_FILTER_LABEL_SHOW_ERRORS, - run: async () => this.filters.showErrors = !this.filters.showErrors, - tooltip: '' - }, - { - checked: this.filters.showWarnings, - class: undefined, - enabled: true, - id: 'showWarnings', - label: Messages.MARKERS_PANEL_FILTER_LABEL_SHOW_WARNINGS, - run: async () => this.filters.showWarnings = !this.filters.showWarnings, - tooltip: '' - }, - { - checked: this.filters.showInfos, - class: undefined, - enabled: true, - id: 'showInfos', - label: Messages.MARKERS_PANEL_FILTER_LABEL_SHOW_INFOS, - run: async () => this.filters.showInfos = !this.filters.showInfos, - tooltip: '' - }, - new Separator(), - { - checked: this.filters.activeFile, - class: undefined, - enabled: true, - id: 'activeFile', - label: Messages.MARKERS_PANEL_FILTER_LABEL_ACTIVE_FILE, - run: async () => this.filters.activeFile = !this.filters.activeFile, - tooltip: '' - }, - { - checked: this.filters.excludedFiles, - class: undefined, - enabled: true, - id: 'useFilesExclude', - label: Messages.MARKERS_PANEL_FILTER_LABEL_EXCLUDED_FILES, - run: async () => this.filters.excludedFiles = !this.filters.excludedFiles, - tooltip: '' - }, - ]; - } - - override updateChecked(): void { - this.element!.classList.toggle('checked', this._action.checked); - } - -} - - -const filterIcon = registerIcon('markers-view-filter', Codicon.filter, localize('filterIcon', 'Icon for the filter configuration in the markers view.')); - -export class MarkersFilterActionViewItem extends BaseActionViewItem { - - private delayedFilterUpdate: Delayer; - private container: HTMLElement | null = null; - private filterInputBox: HistoryInputBox | null = null; - private filterBadge: HTMLElement | null = null; - private focusContextKey: IContextKey; - private readonly filtersAction: IAction; - private actionbar: ActionBar | null = null; - private keybindingService; - - constructor( - action: IAction, - private markersView: IMarkersView, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IContextViewService private readonly contextViewService: IContextViewService, - @IThemeService private readonly themeService: IThemeService, - @IContextKeyService contextKeyService: IContextKeyService, - @IKeybindingService keybindingService: IKeybindingService - ) { - super(null, action); - this.keybindingService = keybindingService; - this.focusContextKey = MarkersContextKeys.MarkerViewFilterFocusContextKey.bindTo(contextKeyService); - this.delayedFilterUpdate = new Delayer(400); - this._register(toDisposable(() => this.delayedFilterUpdate.cancel())); - this._register(markersView.onDidFocusFilter(() => this.focus())); - this._register(markersView.onDidClearFilterText(() => this.clearFilterText())); - this.filtersAction = new Action('markersFiltersAction', Messages.MARKERS_PANEL_ACTION_TOOLTIP_MORE_FILTERS, 'markers-filters ' + ThemeIcon.asClassName(filterIcon)); - this.filtersAction.checked = this.hasFiltersChanged(); - this._register(markersView.filters.onDidChange(e => this.onDidFiltersChange(e))); - } - - override render(container: HTMLElement): void { - this.container = container; - this.container.classList.add('markers-panel-action-filter-container'); - - this.element = DOM.append(this.container, DOM.$('')); - this.element.className = this.class; - this.createInput(this.element); - this.createControls(this.element); - this.updateClass(); - - this.adjustInputBox(); - } - - override focus(): void { - this.filterInputBox?.focus(); - } - - override blur(): void { - this.filterInputBox?.blur(); - } - - override setFocusable(): void { - // noop input elements are focusable by default - } - - override get trapsArrowNavigation(): boolean { - return true; - } - - private clearFilterText(): void { - if (this.filterInputBox) { - this.filterInputBox.value = ''; - } - } - - private onDidFiltersChange(e: IMarkersFiltersChangeEvent): void { - this.filtersAction.checked = this.hasFiltersChanged(); - if (e.layout) { - this.updateClass(); - } - } - - private hasFiltersChanged(): boolean { - return !this.markersView.filters.showErrors || !this.markersView.filters.showWarnings || !this.markersView.filters.showInfos || this.markersView.filters.excludedFiles || this.markersView.filters.activeFile; - } - - private createInput(container: HTMLElement): void { - this.filterInputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, { - placeholder: Messages.MARKERS_PANEL_FILTER_PLACEHOLDER, - ariaLabel: Messages.MARKERS_PANEL_FILTER_ARIA_LABEL, - history: this.markersView.filters.filterHistory, - showHistoryHint: () => showHistoryKeybindingHint(this.keybindingService) - })); - this._register(attachInputBoxStyler(this.filterInputBox, this.themeService)); - this.filterInputBox.value = this.markersView.filters.filterText; - this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox!)))); - this._register(this.markersView.filters.onDidChange((event: IMarkersFiltersChangeEvent) => { - if (event.filterText) { - this.filterInputBox!.value = this.markersView.filters.filterText; - } - })); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox!))); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.CLICK, (e) => { - e.stopPropagation(); - e.preventDefault(); - })); - - const focusTracker = this._register(DOM.trackFocus(this.filterInputBox.inputElement)); - this._register(focusTracker.onDidFocus(() => this.focusContextKey.set(true))); - this._register(focusTracker.onDidBlur(() => this.focusContextKey.set(false))); - this._register(toDisposable(() => this.focusContextKey.reset())); - } - - private createControls(container: HTMLElement): void { - const controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls')); - this.createBadge(controlsContainer); - this.createFilters(controlsContainer); - } - - private createBadge(container: HTMLElement): void { - const filterBadge = this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); - this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; - - filterBadge.style.backgroundColor = background; - - filterBadge.style.borderWidth = border ? '1px' : ''; - filterBadge.style.borderStyle = border ? 'solid' : ''; - filterBadge.style.borderColor = border; - filterBadge.style.color = foreground; - })); - this.updateBadge(); - this._register(this.markersView.onDidChangeFilterStats(() => this.updateBadge())); - } - - private createFilters(container: HTMLElement): void { - this.actionbar = this._register(new ActionBar(container, { - actionViewItemProvider: action => { - if (action.id === this.filtersAction.id) { - return this.instantiationService.createInstance(FiltersDropdownMenuActionViewItem, action, this.markersView.filters, this.actionRunner); - } - return undefined; - } - })); - this.actionbar.push(this.filtersAction, { icon: true, label: false }); - } - - private onDidInputChange(inputbox: HistoryInputBox) { - inputbox.addToHistory(); - this.markersView.filters.filterText = inputbox.value; - this.markersView.filters.filterHistory = inputbox.getHistory(); - } - - private updateBadge(): void { - if (this.filterBadge) { - const { total, filtered } = this.markersView.getFilterStats(); - this.filterBadge.classList.toggle('hidden', total === filtered || total === 0); - this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); - this.adjustInputBox(); - } - } - - private adjustInputBox(): void { - if (this.element && this.filterInputBox && this.filterBadge) { - this.filterInputBox.inputElement.style.paddingRight = this.element.classList.contains('small') || this.filterBadge.classList.contains('hidden') ? '25px' : '150px'; - } - } - - // Action toolbar is swallowing some keys for action items which should not be for an input box - private handleKeyboardEvent(event: StandardKeyboardEvent) { - if (event.equals(KeyCode.Space) - || event.equals(KeyCode.LeftArrow) - || event.equals(KeyCode.RightArrow) - ) { - event.stopPropagation(); - } - } - - private onInputKeyDown(event: StandardKeyboardEvent, filterInputBox: HistoryInputBox) { - let handled = false; - if (event.equals(KeyCode.Tab)) { - this.actionbar?.focus(); - handled = true; - } - if (handled) { - event.stopPropagation(); - event.preventDefault(); - } - } - - protected override updateClass(): void { - if (this.element && this.container) { - this.element.className = this.class; - this.container.classList.toggle('grow', this.element.classList.contains('grow')); - this.adjustInputBox(); - } - } - - protected get class(): string { - if (this.markersView.filters.layout.width > 600) { - return 'markers-panel-action-filter grow'; - } else if (this.markersView.filters.layout.width < 400) { - return 'markers-panel-action-filter small'; - } else { - return 'markers-panel-action-filter'; - } - } } export class QuickFixAction extends Action { diff --git a/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css index 4a47972350e..c03346efbd4 100644 --- a/src/vs/workbench/contrib/markers/browser/media/markers.css +++ b/src/vs/workbench/contrib/markers/browser/media/markers.css @@ -3,67 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-action-bar .action-item.markers-panel-action-filter-container { - cursor: default; - display: flex; -} - -.monaco-action-bar .markers-panel-action-filter { - display: flex; - align-items: center; - flex: 1; -} - -.monaco-action-bar .markers-panel-action-filter .monaco-inputbox { - height: 24px; - font-size: 12px; - flex: 1; -} - -.pane-header .monaco-action-bar .markers-panel-action-filter .monaco-inputbox { - height: 20px; - line-height: 18px; -} - -.monaco-workbench.vs .monaco-action-bar .markers-panel-action-filter .monaco-inputbox { - height: 25px; -} - -.markers-panel-action-filter > .markers-panel-filter-controls { - position: absolute; - top: 0px; - bottom: 0; - right: 0px; - display: flex; - align-items: center; -} - -.markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-badge { - margin: 4px 0px; - padding: 0px 8px; - border-radius: 2px; -} - -.markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-badge.hidden, -.markers-panel-action-filter.small > .markers-panel-filter-controls > .markers-panel-filter-badge { - display: none; -} - -.markers-panel-action-filter > .markers-panel-filter-controls > .monaco-action-bar .action-item .action-label.codicon.markers-filters { - padding: 2px; -} - -.panel > .title .monaco-action-bar .action-item.markers-panel-action-filter-container { - max-width: 400px; - min-width: 300px; - margin-right: 10px; -} - -.markers-panel-container .monaco-action-bar.markers-panel-filter-container .action-item.markers-panel-action-filter-container, -.panel > .title .monaco-action-bar .action-item.markers-panel-action-filter-container.grow { - flex: 1; -} - .markers-panel .markers-panel-container { height: 100%; } @@ -72,11 +11,6 @@ display: none; } -.markers-panel-container .monaco-action-bar.markers-panel-filter-container { - margin: 10px 20px; - height: initial; -} - .markers-panel .markers-panel-container .message-box-container { line-height: 22px; padding-left: 20px; diff --git a/src/vs/workbench/contrib/markers/common/markers.ts b/src/vs/workbench/contrib/markers/common/markers.ts index 6f3efbbeec6..17496243cb3 100644 --- a/src/vs/workbench/contrib/markers/common/markers.ts +++ b/src/vs/workbench/contrib/markers/common/markers.ts @@ -31,9 +31,13 @@ export namespace Markers { export namespace MarkersContextKeys { export const MarkersViewModeContextKey = new RawContextKey('problemsViewMode', MarkersViewMode.Tree); - export const MarkersViewSmallLayoutContextKey = new RawContextKey(`problemsView.smallLayout`, false); export const MarkersTreeVisibilityContextKey = new RawContextKey('problemsVisibility', false); export const MarkerFocusContextKey = new RawContextKey('problemFocus', false); export const MarkerViewFilterFocusContextKey = new RawContextKey('problemsFilterFocus', false); export const RelatedInformationFocusContextKey = new RawContextKey('relatedInformationFocus', false); + export const ShowErrorsFilterContextKey = new RawContextKey('problems.filter.errors', true); + export const ShowWarningsFilterContextKey = new RawContextKey('problems.filter.warnings', true); + export const ShowInfoFilterContextKey = new RawContextKey('problems.filter.info', true); + export const ShowActiveFileFilterContextKey = new RawContextKey('problems.filter.activeFile', false); + export const ShowExcludedFilesFilterContextKey = new RawContextKey('problems.filter.excludedFiles', true); } From 150b7f9d0ba9d3cdd294a47b164bd22fb5017ed2 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Mon, 10 Oct 2022 09:19:04 +0200 Subject: [PATCH 440/599] Define classifier rule (#163146) --- .github/classifier.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/classifier.json b/.github/classifier.json index 179d8dafcdd..ca0e4f86467 100644 --- a/.github/classifier.json +++ b/.github/classifier.json @@ -58,6 +58,7 @@ "editor-scrollbar": {"assign": ["alexdima"]}, "editor-symbols": {"assign": ["jrieken"]}, "editor-synced-region": {"assign": ["aeschli"]}, + "editor-sticky-scroll": {"assign": ["jrieken"]}, "editor-textbuffer": {"assign": ["alexdima", "rebornix"]}, "editor-theming": {"assign": ["alexdima"]}, "editor-wordnav": {"assign": ["alexdima"]}, From 8e1235ee25e3aad3598ab58016c071b5596b826a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 10 Oct 2022 02:30:14 -0700 Subject: [PATCH 441/599] Revert "update inno_updater to 0.9.0 (#162933)" (#163156) This reverts commit f4fb3f3e58c886461239452c34b1de1543a521df. --- build/win32/inno_updater.exe | Bin 443904 -> 403456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index fea47a59c9dae3b351f96a05c4d4d1e9040fe9df..8c532b9eb5eab2fe843d29b8d488676263e4c1d7 100644 GIT binary patch literal 403456 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

xi8_O&2bA zb7TUH>D#iHm}Ta^hqlAr&d@}6c&43W+v3CFhp%&5Y0FRsJU=bTN?VG4BPP~L)f7XO ze?8(Zux5|3Ole+~Ex~q|?a%yv$xp%<$+A7nPteB17db`Egva$Tz1=7xg$r&3><%58 zcob%dy!H+H`!EU4XrGSG%J}KW>>uX0X~DhpL#s`K`F)eztf-HDjGA4+fr?)FXWtaC zX~jDwr*Ds%j0Kz<0SO9F^W&UBmp7WRJw>hcUt`+YK-(klWP4V`E zBPx0JGvOk8ewzr!QD)epYOIcaS2yH##xIFv+Kc4glmE50NRBo_-^mcgL07Dz!(rqj zp^;+sdS((=6^Rz_fi7%bO@;mj)+XnFtw*${91ITJYL3j9 zJTYEAJ=#k@YNq%;(OV`PX&f9Po={`5%+3d*{|3$bsmfHnS8>jaV8W6|gs#=MgeJ=N z!kN4G9oo&r=w%DEIrJ}~8V+sYYed!H`NHAJtq=dmA-Alat;hMX3ENS-k=+W$AJ5!f zv*0wH=^GuW^d0q$*rv!j1!omFl|1KrD$&~q*1|i%zu?R??(Br$kG6cc_-n%+*ei^OSudKHl6&#ulL=> z*Y%cf{QmAdyP2DLANCd|dFSG1eWPyxMb)=CZOl+YiAs#HQKzP@=sfg#3>SDiseLIV z1GRMMqPX1VaGZIRq4(Awb?Dfkogk{(Vz{Hnt?BxR%=m^=y3yWlt*RJIi>}Z&Mqh`_ zcS}=P(LvA=$CdgY%djazey=wbCEqnTC%C7v<}N2J=N|v+Q~oyl+`~}&2@bjGbSgzF zUgw>r)%I4fPA+(HtgXlv`!qDd3HOt~x?+T~S*TRMdAlhhxB5v8-RcfMhRI*8xHVin z$VpOqboK@DN%^a1Ph)Vmz$k``Q|#Er5hMF3IowY->^p0EX790KX3C z#OYT~&E0*02J~COX@(;DD5`-XX<{lutp%s-3CqCT%h;M^%q_$m##ZBJZ10%aV$I4o zw#VASoph<@Hm5MuOsLiV))ckr*G6rSh48u6nHy@x#e&;>{iBmj{hvV7Y5izc3p*<9 zsh>+>N%rQeK@htk{`n#Wkk!CH{|uoY5MuuN=bxVDYm7|e?Ob}VhHC}`TM*RLN2x%HMb&RxM=5+ z;h)B5Zs6g{`g$A>XBqp!?sPX*Rr*(|Q6KvqfpOzU`3?!$hTm#lrRWH(`di4=(W!=3> z7P87yieMmp>{{8XC`OS|jgAf(A9cc&Los33g_)X!X4zOQ7;VW~H@lRzOITOOy8y^$ z-`LUgs!=jKhUvI|o8i<;gx)}F6xEUIc-c^y5+OC?()AKZO^(S895enhP-fGT`>F16 zeii&A{9}FsrZ~S?)K|@%>7X5U7kuI^-Pw#_m>rNt ztu@hSJ8(=~#%sY3>Am6%+l;-i$n^3%LS~cE#DU^wQ)3QYMHVM1(rcK1or7`}nHiem z(068S(iU=A#Aeqx?B$M&78HIfvY47XzE-w`RwVfsWFQDHA%)(E)ro~yleK`8;ePT= z(W-`!#+K?4n18vlDE4k5w@|rOdnv4L=aA#MdGXGc2$`*_UuKv7X+e>BbF;ccR_;)V zTdb~gFXvXIY?Hr3iCE_`xUFEk zKqjdm&Zg4RE3Sb0}pL?NXIg&y6U`$&ik4NL*U^m%uO?06+DaH<+Z| z0lCN;`5AF0u=RC7GJKZ;V+)EGz;s%=lkS@qiAwbMNhd4Dz6H`-^+>qb?NlHLh`290 z{y)@%4QnkR2X^euT8ybKnPL~MFv+a&RWoaY(H9LfxJdz!_j-UM-3LI;c96*y*+;en zZ`gy_>KUhAlUrkA9#Y_k>A5`+U9IaRUXJps4T-TmubaZsh=+wa_ zsoK)UXhCSad&oGq??$}UNrhW{m%eUiKA5rCsxV`{hbK%dH9q}gT!n&?hn9=OH+zH^r#~+?EABwrj}W>T$~3S)Q^?MZZYyU3D})A z4iD7rcCL<#ksrr}_kA-%aU(ygpEr&Ctm0`I`S}MyKtcz;F+ci5|24nVE4GUg>ix$0M29sYU%UxG zPcCfAE?qpLW-?I|ZYyH;7Po{4n66A^{;J6>mo_I_+PbEHj)eO;j0b>qhvvFNDIAE2 z!>^UUjK##^*Vl;B#o^ar{IfD$ZUWazV?CG)V1u$ieMRVAOi?SVPNT>x7M6zcw17W| zpz&?~DBxd9p#2L|`<{e;N)Kv*3#*F(9JnWNkMG7m<9(MEiXbal9$=1br8rgR7`U!}uB=6J(io zsr>ImL{YRO|6ycGaz)1N9m8sC*G~l+lk`1w0Qd>>6Zk~Iuuxi;f7m-T!A$}HJSlDx zZV}*l?-Ibt9g#cX@%1kO)!~lvbL+YP!A+2uepuix#VXb}d?JgQi$13|nf?vt%Ed6Z zd`jA?RdolJ(P?Dh{O*&^lx+BXjPbf~0qV6#L5}RokaW6<6O}Cxe%@JS%g46CX4UN$b)2K4`o~@$%5>8?WtODEQvT= z{mMcCS?(h}WsTYl(yt9WQ2y>81QCS`8;Bl>oC&1N$t(-x+q^ktfya_;-Yg!NRl5?) zA%s$Fz8%p^@gB-KfA9q5$^uUgr1YF5-{;03f5N53Y-z(XLV|%uK?x{FubW!cjqh&P z@x<2KNb|MR5cTYFhuFdp_RihwDl6mVl5wOk1tTFnJ??Pwr>ikqKA<#<##*#WNtQ+Nk&sPB*r4C zfq}DmAHPG5)$fU56d#MoB|nCwt(|xT8j%(^eC%o`1y6lVM6@pm`>{gUk9(#Xsq6GO zrFd#5$(3u>gJ#$qdMI?Wh~ zr!sw>Q=jT;<_&H|96%Zwr$94NDRS$PxJuEZqlET!Yz^(63_=WeG(0!0X!sk4!JUU&l9XEHOe^ErJZVw#oxPdYD_wZ z5nf^`9Muqr6cVk~&a&5?I8kg{iTg=ga@s!@_e6YisP0pVLWR+$Y>n3Kl-C~eDz@|M z*2rs5dHsXDzR{lfd3pU!d#Wz4&&g{yLeU@9Eg~F!v~IRU3GWo0S@#18ca`vrx{2-a z6YGYyhfC_NmarHJj}ETuBVkcBk6vHbL&9PSIeKMXX9yKe^{|FF(;Hn#)gYhCR*i=ll{8Fz{K1=1$@SRox7r zp~}#=aPbF)>2VnXxCDhW?gPthV7Z1oLI|_VG#|C&GQoU~VO*e{Z20IIt1>V-xN0i! z(XxOGmWKPjqS(-m3WZ<8zJ~bsO@sFlLUikoEgUK#a6ZFm@-uSLw?Mh_(yBxX6iQKU z(CC|hRDD>0FAcz>*s6zVfh^~8GGZ}!^i6m@q1xCSW&x~;o$Tq4Fl2A))&JTFY*flWK75O1cl7{I){d{Ne%svs~L;=(lpbV8M=ki zFyp%vF{%86gy741>4WsC4!zvDDoBF^ad+yH+q{MT$nkT=LdH??{{x^6gGAC0MlMjL zjtM${BS8KSpfUH>Z-mCZCNvf(Xgs~xg2rM33K}IH&`8mbB=jpz;_Ac@`YJJrZpO&? zQZkJmWrWf(Nr_ohy&>yperv@|_Or7e3A=3ho3x^%RmbPu56Fh&Z>BdNGu_7wCq!fc z{$?tqU^FR|46BnKP8-I~{|@Jr38jYjmuj<>ThE-D-e~+YWFgzf1iZiE@vWw|622>S&Q)ju@A`lDC ztA1g&`SUkz(8Lq6Ub(&f%hOM?pZ<$#x3@>7a4GILZGD(?YlR!*YL<-|Fj@Vba_1e! z4wX|2&H@*Q+DXy^--DbpDa32-m{MaFRego^1;F3c<(}ZnA(Dtr>%z#MPW&wa3avwsp87~lRCP36Nu4jZ^!p;_(w6g>BmLb zsB+BS7ii7&Qq)iDwS_N|v9fh|4&g=55Y{&|9H#PTKe!G>zqS-DAY#Pay>Ii^ru{Ce zp4&e@-hLbSLv2*#s*D}4W{>6Gd?K$!XRnrFi@2gsPdKQoHG-gOzR1_In(~j$UJAkP zk6*aU=XCQIHR*q@cpGb}SxjETH~Z5>O2 znq($@&tv+J(YGUl!k@3b{1yi%n{%y`&Es7(*gvnwEyU904+Vgk4Eo_tbMXh$Ywt_oaau7V{>F6*s_gby^ z%kU^WJIvy>+@w%>wS_+fK(rx$%iFSSX``$UYE}1+m0>adY&j(=+bLb|l$%7-+YQUlFbPh}N_i;t!sfDuH60;_*elqf^G191P zkNtgA9$NLocNh~Wt(vmj?nAbE!N78JZe3tap29P|CEB#y9{qv?>s5UfE=lF@LZB{+ zFByh3b*jEg9b(EH($NJ3_w_Bwv|D-{y+(~cn-464f!^t%5gF!CLJIF%qF~ zwuC2b`{&$9{6MYtmeDxej0;WLj?B)~DH$X)<&u zc2G%X-uxfl;|0u~a?&CF2X4;T0XTfeH1FM&JWS$V3x*52Att_JlwG!b!G!{)-4>hz z>+IUw^?@T9c(Dr{=?vuE%R1=}k7=_dv1+#D#W3%JYf|BVXoT6)+5fqv*zZCjuLTZ~ zt!`F7On9P-HOoF|P`EHDoR;e=fkG~H)B4J`Z^_JGbeu1T_0{C;0Abk@$XdT~gL;c5 z+`l6m$=H#o+B?@3?j~jO*Xdh*ztUE0T=i-HQ8rG5uSB30{MWqv^YUx8|JL_N|FVv1 z)#x|b!UM0kVw5e<&Y6Eu)PAgjkL@%Qa6b@SK+Ck+*>?ZG79fek8CJtb&QvjRN+plI z8<8!5^frm!Zk66jh3EBljP&+O>Zxq|Jz2CxeN}INK+ePlqW_oJ-@Rl_OlEwfzfwx| z_XX*1w<{C-du2ig=M4=H{M}V%=e)V`j_orerDMMrz<*Q68vkhbPLGJJKOAtMJsKP8 zKAU8l{he^&P^UAop@&ks+GY<62l}V+(jS(1c5XN@Blis2z1?SD%_ix<*`fVF6mOq! zAnPuP&YG=-0~^Oku#2_`qWOPkr?aaicUp_5}`uzCS^+*JLd}ZaiNaBb(Ks3V-{;W zEbd(#Y9qDSx=Jv`xJN~rySf;nPR?4tN4$sMwfrVQ2jpFT6@(Y@6RPiy*#S>}F1iQ`?Nxz2WB`L#h)9AD-~p8g?o zP01Sf5NOZRS+cOwjU!jiI+j#X^ z>p0D7;soRGv>?8_dJlizpcnmjwRi5?fYpEU$#F!Qc^qMRyB_Z}9^7Te|J!^EFbxFS z%YL!Y1kAORH34JtYxh~+s=U2QjU=fTFGl_G%;D?9F>Lfo(_8p*3YQumQ6I?_2aRWF zi0m_F10B?4CIWO=fMR6V+Z4seBi#h?&F0fWgaG4BEaUxE~P#4PmU)+Wh z!|NpDs}w0U-Wx8ph*`Sh_`6>^Pj6^DqDJcR&tD&HQn>NB(QV)3^`rfKqV<1%ciTk{O{Gj>RB z<;gHDG|YH%se=7wChSK$?4gtpSE-n_k;4Ga)@Rf4Ej6?>7 z)JRzKk@H1YsE5MmMMZ3@y!G3H=^hUVt*Y5v5)*jwdJu8>PDI3dAXWu zkxBG4cA6>oc3=o)4*nPvnd5o+w}Q6f4DzHjMTDNl95uD-3a`Yw+I__$B=t`Q6~`7-5OB67)wj^!vee};15Xn|FqLD}jBtf>W=grA54CR> zMeMCa;jFUE3TG3SAG!1Daj#nUZOm>TEw3i`l$j3Wn38EL6>(%h&l6kzl1l1i>@t(k zpH8*aOv89s@Lp!RxP--Qx_q2Y;DJ}HEEZ;j3SF2fB$k`K``GF#J6(wAp={~0>q#mv zJg0p$g?5Q!TiN)#R~3;;BYWA(#}F!|WmC=1v!zR4Zm(?nl!4QJ+{oYXs*iR9uvm_^ z=rpg%d2a`=MY#US@~)99X+TY(+%I*@M;+zM&im*&4vG05-iV<~3F6A&3 zoct9!YGxqnH3d5>#G9<>o%=lg`KkEc3#I%A-@}(No5sjSZ_lml;AdGX%hk=*r>f^W zBf<^`+Qu*FA*!xdawW#w7om}NX7si|TdB8OpzVj=g37iP^vpMCd1`cG?)vCB>N)^W zCn!|b8zJn@$To6Rwh3-{U6pMgG39;E<=vuJE_X)zEq6!zEbkJ%ba_g&=km_c?#ms~ zF3XdnDa$)Wla?o;zb{THl95mdHmIIY2I8NvwlGx$;-CsZKv`;{xL-KBsvO{y&*ION znVpSy%zXZNols_WcyB`4w&`^{I{yNcc69KiTBs21e17w1m}e;7o)9I6F@CNkj2ufq z1pji)q;bi2K(=rHm!FLHf6H@zdhUOz^ZfksK9FDjdF6)kE|-qt`9~#$zeV^~esPkZ z<~#OCEhEyg37M=$3G-djq}OutGvq@UZ1gEQ_C-v z*M-)rySzWI(K%92m+~7VJX6Bm%JU^W!;CMH@I(o_%1b3&BH^y((^h?c{+km;#5 z)C2d>7PFIne03&wOi9!~eD@k2CqC51Mk~*_32O^who@pqd7QEGuFFz_#D8oklup>+>nB}Ms@&f0{^$bqjr={vL)o3s^+Q!OXc1*gmO zu?1(t3r^2{HPCkd{48z7>hr3|+Muo2fTNN2Lgbh0WTvIK0Q<7=KWMCfbx!r9g4p;- zo%GJ#?sb|wr2PwRxT`{yYW*;s)SkXfWQ0Tb19*DI zAt9YQvEA}lUC$?&Lqzs8q#v>RgC}1Zf8FCeH-gbS!c<%-T%=M|EZT$k`G<=X<1?! zyo{YuTu$EbQJ273bX8xZI$@^$`JZc5OL!@hwP%sUg5p~37`wjCbEIIIZ?3$<__@N9 zk;4@xnS19z{TXfKT8`oLwP?3-bQHl_QQ#=W?K@17h#VokuN6f^38g2b38-g#wBVoQ z3nH*`8qJTQ3L(Nl*#sWug%(taFgFqbdE?a{tr%kenu{AmB~~d%6!3XNL;Z~fQjgL@ z_?@c6I~Y@Pk2pe)$jMY^QAM#E`go@p8N+G(9(J3Y4k-rTD3+q~`P)@VUsL=(|3l17 zHtn8x`nOfO=@3)z9OCMu^qNm(MR0;#F(R-QHT&z%YvbjrjdYuf zvcoaOsjZN6q6U%Fp=r8N@_p2$;ZSgAVTk3Ysdm@g?gM@7jhkK^Bgco-?;`jS? z*8qTyb{xaml7F<~I{R0%?-7`9#L7z5-g)DJ_vN7*42{N_3MT{29;8Qa3;lo8y$N_! zRkrtC6^c-S(o<;EpiyI6Y9h2I8ih1b!;Fd$WOT%Cm5z#vPz5+)g-Vb^8RdGl=Rw=< zw!3e?-Hr$}YC?bj4&aPK%b?;Z%K=cC6!QN5`<$v&K<&Qwe&6$aADTLQ9@bua?X}ll zd+l!NBb^;LdIyv3I7nPcyC-qB^ZP{7nIw{+W5_?4%n; zuLH38oRsl-3z|D0in(471Q^G1XTDf6qZ<+O$9jRIvW`}0V~BcazXM`J&1Z~EBytYTmE;)<6W+7}o44~cV-cK@=(ntd&skKqQ$ z;5A8<(rUw4J%&Mv7IPZahnpeM^Ww9P^+ikKvySt@hzv?eKY-*7TJTI7#m6>Qyq!J? z)4>heh8pAGVOSR?ooe#M{;`oeDDL$*jH^25cdv7$%{e&=Yg<1>WZo2fS zymSHgFYYiZcgb0y9{qaEDzp|ZYuR{M!7lJ+3?K=Q=BId^a|y8LwT9>+00LnY*9@?< zb6n~^!Ss$BV0d_f(S3y2$V=P=(OFIvapTf;_GfAky^Nis#>A@B$Jptq3Xwn4mM*DV za07&6+%9E1WO~x*FtVvGq-gwvllTc#>s9BD3a9yNulIx=&*R8Q%e;ZkjCaN!`l8wz z+I`TpJfAh88ErxAE0|+8LP3@?P95}9ViX@RWpWjr0P!vY7s3^9YiaTAZ1J&TM}JJl z5p}*A_lbwKx2fh3t2r`GCJ$f0XrggXtkqL|b${{|@PgqHZjss?jYuEuRMX}T5Sjr= z-{71`XhpMX1=Y)?nNa9nYp%4%3;V0vhO)*A6v7mrJ-(R08hd<^J+g#c5pH4V3UD8L zWF_8Gdt^U8{p_LSt8p_7ZW}t>xJHh!kI7ic%mOWAKYnBV$IbK>yI3`lT>ayK?hUK- zF5|aKdD4*Z&#fD|q!hl8XXY>F@4Vn-Yj(30zPOZ#^ZHrgYiC*EAJtjmB|oD8EBu%? z$m~U|vR_5Y$xh0Na)({_aJfs2`xk<^yjy9i75>GaJg?7p)G5$B0JeQiZ_eE3`-m%zBZ7`1sld8nn&J%{2;!63w&mfjbSj6Jq4~$xc z$)rrN+Dz0de4W(18hI7bgn2o_WSa7zsv(J7XcUwNqWpV|K(LT5M@UJp0aBE1q zji6ZO&QLW(x-UI1$9m%(BP)gI2185lGuTO6`*F7^qHu$uJ;#r=h}$Yy_Z&G`;RZK* z-Vn8VPQJ?O`HbkK)pKEk`TXPweaNuRWVrkH#*4v0~b%**^T|ei(TNx zzVF38;KoXtqLQb&vC>>pYvOKfr59W4#!8D#u~)dUlD;Z$xf?500>#$2u~9EJ?8aW@ z#g@3S_j$1fV|(7+;Klmf*eASLgRwpD{=FBwQEl(}lUKc1gRwpDUhc&Vg1PneD>V2{4&ya3t>`^ zkxAH;Cmd>Aie`J$uMBmo6PELOsYM`ZCbu`*~X88hCw&#fbUlGFRgT5k`D1>MK-(uX;{ z2yqv?j)fvavC-a>Svi-VkvYClvb+68Vp%y>?+PQyo5JY(E#5_^5U2&4p3*#LI$>Y~ zb?>k8XI$KLpQSJi^gnf^40U1gWd+~pE!I;q>>`+8?&Y8A(2oh?I&^N(Sc391L5XF0 zsscyuZ1mHQi5TAkR(S5~ir88~s>aoPr>jKa^yQvrmNK3N%eQE6BIJ@srs7 zDpOrh)9sJOI~8u@k;?Y*#k#8xvO+!W$V`0CY-C{_E+pz{wmRfWuIeBal^nq@T(2SrQ(6%Af*HS`mOSt!-};3Cb~ zE`?2B10?iE2I*d6s)+cuVL@ViDHLaYKqGmcfy6aj-s^xwDgy~P^QI{W<(aWy+uAr+ ztnA19h_!!B?Hd)W8inp>6K?ytK~{r!mdvFK>E{b!xEI*4M2Y)4AE5a+MsKykP}Vx# zt`y?CCt*e%o7QCR5i+JtBYFliV@T&zw{}SfB+BbZbf^-IQlf6@tIVZFF29{0rvI68 zbvu!}{WE0mMW6$-SEBKk=1(?_$PD;c|0;X~G{P{_k@0CwD8~ z*Z9jaw^@2w%YA*!ZIah_nRzhyYm#%~KTy|XxfXN`HrQe(rM3_X%mXWj9mDo%($OZV zG}*i)R)bcqey!G>OO-OvIB}4B<(LdU_g1e~8uwQ3w5O}PMi-mgyo4d3e()LH=8gU_ zrNfELeHRHUsFD4IK{u#H2x~INg20Y=#)7~~3G^4K^)uPL4J#H+nK^F z0}m>8#H;ePHS|Th;5GV7V$vYA_t&YVAA#XF@%C;&%0vFGRa7?fn3OD*tIp_B#-Jm{ zn!64BU|RLT#!J^{jk6Nyc(@Qhfu+)8hw(zMM3pfV6~lesIqtton1FgMLa(xiSwvkyp?mz%6Y z$s~Pap{ZCsKTpJSP3#Z`t4mvcSL)5&4o1(5`^j-Y)c%2Dxj=m`OB@gJ$``9iuX8K1 zKhL&k#A!jSF1hg~=|{dHJ}(m=y*FtA2#*=y6}IugdFDQS$A#vhy3jn*TxcFzoYM0( z+_=_)aXrxTgc73&1_UN5nCv-seVY+i zJJvKqXAxI*g>SQZaNGB5v!+g7Af9X-`R?KGYYN~Npik;Sx}zZX3w)2|PgbbU3M03zuSZ*$%bO}A#X9&Zv$-Oh9 zD>EUMW{zQN0%v_l+S&b^7MMe|Jshe@0Ny2Zf7IltF=ZW4(2_$)WbUh6-kR7o>W-qO z;rnEeFCo#&lCUB_VC>v~txc$SW}-0M>2$kyCUxxCfQpzAKUP070Jg8Lv9 zq>C=Nb=SmPbiu9TUUS1TZ#_#Oj2?QH zIXo*{q8l&f?hC1U$gMjx>O$98Xo-#$%zYgqO;dCM=5p?*XophAn2ENo;O`~={>dK# zXWy6nO(0I>L-$q=;;$EfQsR&@QU!le{;G*r8FGKupYnfK{5Qp^-fs&3uCPqobJM6_ z>R%>IeayJkAN4OIPa({C?mzuqJm){H7FE0KQC;0Xo z&T}XXCy#yv4@|Fn2rh%o&Y_oNZj&5^i`CqHkFT{&LM9&<0{P`*R)L3C z^9i?K7~+a_VHuVvN!1E#pkq5bH(LvqS^u#T5jp*^<~>am`mT*n^5xDZC#TUm?FW*l zJO9ZFikvSXrXs8r`Y{4np)cby#&rQIOP^@E;GBFzd;9qIBj}-StVFL&+`*0K3!E_| zAD_M;*~PA0W#6_c&^{>Wrr$${(O)~usqku0;eAcvv4`N&bi)Icp?N$pn&({5Dmvrj zE2(R+-H%hMZy}d~s5S|5?(!XF0y4wp?SBdvKLLcCNmJU}A6$xye)N)@so_F~H(9>5 zJ>RxPbFD z@|0^!)wY0F#3shhHC_QyP@InoM{PAm+Gx)Tx78F1VcKeni1AHst10G4v8IGOr!Wl^ zpFi0idK{&*#2mkJXavKz)JE6|gazgeJt=xDz?prn)1Z0{Ozy%3{C;4UKO|7PkUas& z>h64@85K9ICt-^>0@-GI_; zzzo+H}vdesH44`uZ0~tb`W2mBS8#2OSo|a#_O;KUh5>h>@9htvO%f zsRq^Ol1PVCsHA+!+U{S^^}QQVhf6FEqPQ0J$F5=rRH%(~QLJlXZ+=vdtQ1nL50yAG zQL6p(HbptHy8r`7meq(VnNP0--7NOwKoFdrj2RG2KfxKsDnCAbg3eo^CWVbVRBH4* z|L1D`oPp#=yzxB}d2{?|oX#Qq7`RwCOu}9yGURu=5`( z(;ON8+$-~0sxp_ckCQ{Uw&if@vI(bp34fAF=-t{r*j}ND)pfExqyU`jHg8CeMKC^; z0XObG+Jk7NH+!YBH>cHlTS+!UTvqJnZyi0R)_%_U=~bW(Bm&H{Ck1;5?~pqbth6ia zYXX_W4Oh?ih<7!sQ0X7}v6)_rsvv%OCNPImZiD(W_tXVF)x84@%zM=r)8jnd3{0q@b5Bx51)IC*iv7-I;q zp;$jdyZa!s5jAirTFbhTIhjpzoOeO6>hl@30L5Nkwn_&2e?_f+b_Y^s@W0K)jX|6i zTJzWsx+lFw&OgVnpVaY`P{BtVgbL=Y%p4Go3Z^g9M48V#@kh_pT)Cgjw!|kvGcCrC zaV|pHj!B``NH40EX%W&1b~tu!Vt0OQa7A-^Frt8fz;6!>*ynk7?$c*8y$UP*tJt`X zZ;x>Tyq--h!$nB}Y`V8m6BoT?dP0w^=zNu(BR8A!Y)q}47tBcRoVulEU~0fhXT&@1 zP`V>@wu#9dp&a;Lk-R;`x&2r+QvDE%HGHodU>Oobq@jzh>d)9@d15we^f{?@#5s># z=n={PgTvn7Jix~c-mh^en@V|y4Od52tMMn~r8nhZ+z7PO z0azIGTk+Y2c`>Z%lc7UGN>O2r@o`-sSwoA=4J@-B@WK`_;mMATUCLS*wZW^*2Da?E z#CzSa)i{v<*V8kMl$K#4svCti1-ds?{(!Jz9hsVoW0kh-R{h{>`dh-c-QHkt@2Fe! zr#ChELvF3cdawa- z6oL;$)D$x5wS8ur29Xy5^R*8Qi24p=_gU=+Nz0<$NZv<=6ssV?rz#v0JO*yWY_%Df zGu?$~sP}Z&iDFc~N}g>V@0t_D=PW{g-9Gc{lwY}YfT#;Cx=gK$-YW+c`JK5~Qg%mi zRQ%S$JfhK&Tt#K9UE~N=ZCeRL5v`S*0Wi%Ka;ppNHSB|}#zR=rQ-9;9GyF}dDvy$^ zM%`@hC@=Pikfw4)>#TZb%2aZ^oUU+6hfl_y+Eb>0+;Hy=G+Bd0f{1> z?%5v_mnh1GLqg`HoJU51|EYdB8BeON^uM@3D4$0yBS*#ib=N~LpLTA4?w~hX05J6z z`bhq!=)vusBDX`)Qcc;&eVrm-Q{>caGlmK? z8n-BIsd~o50wjgxxqlf}aqnLld>!|l|A)?q&iz5417r<6Lw~>8U8B)wfgubbh$%k< z#?(L|KhpJokVc4AjPbu$cCM!lgYDf-xAko=)4R(4>lw!L$ zLQDxWa|ASLICEQi+Jm{OIT5$yLe(>7Hx1uKEwv;pri)k|+$BMUe;2uGh^VwyHow|* z$1bas9YkcXHQ}Iet6q$J^`H{I*0>gHY}axVGP`B6HMMypXMxKK)-;XW#bAz5!;%O) zZ;@|!(?z?eqNM3Uo>$*xHH=fgs9FiZ#^JOpVBNW$Ze#coGlFy>VCg=ae^+m_4nQ)r z`Y1epTQ`x7HF$A~Y(SOe+}j;^S`91kiE6Zdjd9Bal<4ckvae+s9bmiJAtiTw9s9k% z6*DYtF2$JhB8Z-1_0mBl8?lo1zV198=FMXXPm-45DFK(2_=;MbPdT>IYM0uL515*} zN18oZ`#6#jKS<<&_z$`_UDzJ`j5oSp^s2l>Rc=(dkh7K9mgrJaO0rZ6ECEOX|2{9n z$%^?qF-}Ys&ooTzRGdoX{1As(J}$?hM$p?3)Bw1bW}0E|k`>W&DZ;OHzm4hE_#21~ zk92D4qo6RsP|6iNL&dbGgh)G-jAeK+d{e0~{tH<+uW~*|iNJ3S2+h>D0o_qwM3P6Mt z+(x1c!BV!;y*aIg>od&7XS{-fS`^ck`#PtY_#FQ5rN>RFYNgA4G@F22?jv))*aw@i zFX}X<{XB+Y7ot`H?g`-#WP)1`^M^&6h6ORPUbrN%kES| zA|=)hgn;-lm~e)lUq+c<>>iDCp3XN~>{=5apv?{Qf(Af(~X~?^N4boFN$}HAeYnjD|uj(Bp+|B18Ica5%IwzYAN=Dz=%85>sD>mMWZWwc*vB4A%B0=U`RH(NjlEy zmrW|@xwz9{l7cUuz7_j{a59Efn&jc_v2c4VAOWa(?>^ZFj_#-(P9 z9;nWXjneCGAO;k&Gj*i*=Xkw;XBZ@a-oMJ%BT#E`lGABXlsf;60w{-94v?;2o@Km+ z**WbiN)8DnZ_g@X^ZeAzgC&D82goU%KV}{mD>jddW#1J;zCgOJW`~#l@mcN2zi0L~ zFGE@GBWX;x{U1r|N{)Q9xlNzJqf&ZLN@9vm4@z}CFk3#^x-EiL(1~W$oj0}Poh_fc zuw)5$fqDIW^eqKC7(K90(7aH4Ic-J01DEa|>f+K|z8)^s;{+;XcBU#;0KHye6a_#> z1=yTsh$--N%`uiRpNp3iGxI^{9D9u4WQx&w6aI_+tgE4%Gag|!GvG^k7Gr!~FaLKK z^Oqqm#{7=2hcUm#DU7*CQR?7b3iw8hVfo11Z)kxF0)aD{)h?aPwJ)Ro|F`VRtVP0| z=xkrc*ar$PZbtIvESP{ea}}np!}nk^fjS*Tdh+91fX6P_+|u@2T3ex1e8WpDFLN~mjUOJY!O#_ zMchjfoduM$f}VhKWlfl+wL=owlVXrW9=Z}GM$3~#9!40F$Rk`y9!zIlL1Y{e$I7yooFI z8HsYYGw`=dzMxvIw&Nx^SD52HX^{r?PJy;r2tHUhVn-+T<;RNJ2L*T(t|SP z+sj%ufpFXEVR3YJy{h1K@hb(}q8Gc5YDo3nzt&zMHHy#JuB1!iOvl+1#JpI} zC>3KEj0vWg=q-l15JzR03pt#Vvx!b~6OGGdEDlZH^wC;m@w2QKc+_DRFI z)_Jmvw_5Y4$GPjxDjlLSSERm+!C?Y)Fm@lB07I}`e9Q84r_v;+^rCOz=L$3YTpbhZ zf6UK)^0iLYjf`V|e(sPOfM@u*BXRvZ{M<$qK3#A-xRm2t__?RD37_>6{y)yoeF4o; z3v&3m(Ep5|>rNBJ&*ky;*5JKogU90MKE+`$JB_0gKX)6czmuQ)PqVh@;&=yQY=!sGDRxO)J}Y56d(q8971k?@7J6O5VNPgyEZkps z$s;bNg&%Ogg_2%?d18{ax|2?JI|4F)OF=<4?_sOF4SU1z1Cevb*AhyBjhr^vfH73Yv2<1*770Cp0OJ)L@dIwVk6R4gH|8fH9 z(aioi6X;YkfqFU3XKDiVvOmn3EwK~Rb?c%<@oIGIuQhp`DcsiL~5v)=^B%&GSd zM9vGjCpfw|vD}?g%%>lvq^Io7rz(ts99Z1HGoL0I5mC;3x_rBtPt}3gWzOcU-%{+q znn(p5rD`H|r%bk-rM&!;oja&Un(4#&3(sx*zd3iR|ERf>gX-u1CWGoZ{CQ=v%v@2t zG?ItX{`uV0c5QYi_M+%vOvXE$qZ)HXKLmd>)|}47%KjNHq9c^`$NDF*<}@gGM~G_G zV$Ebs9-*@k`<=PX>6&|5)=!xKMWu`R&Cc(tTn<-Se~6E-`~mxJjt?OYA{>UOqn~1X z4T+s7mkwqFwnOR1Q2Kl6`~^<(Np0)Mg{t%RyfryS*!VDi&(8 z_P$m}uVZKZsDCcEbhkOhiws6dso_<;->2U6bD8@ai$8;&EIFBi>x$dahiymx4t;05 z`ruu1sv<5`#FlJChgGJ>P?;p95xmb>Dz}7UEFGLwV;?pUdEd2@6yPvV5Hy;7d`o0M z2|=CizQ_(!sj-v970x9MR0TkdDNoO!5{nT@4E1)lJtR~zSkv*N{ayXXvl!##(#TzW zIDwgWB44btzW6jl=`-TZ=;6-2r+KvampC*g+cnVMB0?qQq}2_KQv0n5&Xdm?NH8R& zY_MfsxST5>Ncq`q)Apihkuxw;-uXD#uT$a!lxRwr;x0{@QdQ!W*%Db=p*=E1RlMY% zU4X^l%vGFg{m#-tSyu$TFpn%!vTIU7a(20YcXK)w}{~tKe z;6K82H5zvQpwyKSC4K;B{c>T5%QkqIr&@n5lyxpev9}X_`Y#inMKIQ5UNCxpmupi5 zk#vYbb-9Rj_8Qz$Y5Q*iL^>D9X~pLAJg`L8?QnrTw< ziO8$^{3?Px#%Hfos!i@yMSJ@g=Xf^++`r3Q&Bf6W`575-+!u)} z=O%j(Yww82RFi0)iDQp2i@>pwD@;_K^ADMGtB!PaUpwVkwuV!N?55d%XXH6Ruun(!$qQT^?K25irkyd%P?=|S%^=;C^&Hy+ zMp@mYGkWJvSq+T9+tFX3zs~*wgYwNJ#!&yQ!Q}Y?h-0v+a92}Zu;s%pynZ2KXO;z& z%c9eeU-#e!=#j}WfkbQ2Sxd&m3h99~w#Pn5kDRY5_?PX z7H;!|nuc|OF>xM*XxQ&1-rH)wGXZlVqsKUZVuuTQj$wb?J|;wU^yqlgh3-xlHFic2 z9pc?5GpZwlp5ntce3>mCNCbW+3%EZD0~77;o=!v$;igAR(D@;T{=M^xPf=%njEshO z{T)a4Sq?ovR|H*@hD0RUZ%4jA%I>)+Ilh=JUm)W2F}56yo;kEO!=r>fTaSin*E&bA zbkcfhYe*R;c?5ewj!x{C3R8_HAS(7a+f8ADUNIi(RzWtnm zmT$(Hixcl2HOStzbCbOd8#31{t0Ab6lp`pWwD58lN9o#y(eT*eCB@|gmRu!7N)Lj;1PP^Rb~rJ>S_-1U zM)b0hbeq}H6zFU3ncrOos8`SGWbhvP{8rVn=tW-S&D*di9pAlidJi7s8vIJtve=gN zS@GSU#ELwB^wfd80rx_@|8HlkN;Ok@RV#+J2B(|G`MD7?_%*#&_V=dq{8h`iCQSB+ zaeA|0i|mz-GY@tViufG_F#jL%o% zYZ~gmv#a2kInTSSRYqi@o1GmedFemLk$yQtJo%dE6U~0dev#eyv9-=XiqzJ=Ogo+k zJDy~4K;!B=PD%ZdPPki}4|{8C)5}db{SBwBkGr*bj}#{L?AxW)Z#CXS0IWtJv!N=+ z{w*y~@h3`h&=xyZFPUS7_oVb4ZrMpw_S0^v>2EpLQ8s!{&Cy#)7Q47jZ?(2FKM2W~ z>5KT0JXLd&sCO@I~fLlSa!UK;6OFUML z7eCpjNC3F&gzOUVIZnsn$565laJWTfF=G6KuYy3&l;1i~eE5*97mjX!9k?wP+xbEn z4DDA~AI@3D&H1|fK9{e)-(H^&;`9k=Gb4^cp&@Re;v$b_?Vzt$Jg)P@p$rIt`3Wq-5Xv$_&7Iq-pK|6fpotGXT9h5TZX? zQ@UTJ3);&9VjpCxX|X}DuE{D&=C zKe<1;6#e@g@IQa;EN2usDw?TVgE+eVLM?<@{)qjB`(9P;gOv;{v*wsuM>T3hN-_1j z&EJFjI>#iM(L(w9^2=HmE1A=^R72C(O*eggCU37==Xk;><#>A~z24`K{V+G%izg|Y z&m@Wc)4Ah#_H`xNB;AQiT%>MRL8>@+CSkZkjk$m-DSav=_VbQ5T z1^_MyC$w)aTJkG5rIFZ@!^}lz9egwdq=ek&lAyDJ1t@ng3_TSCnVeaa%t!dI=TDa) zo6+;9JHE#-U(b&j=4)|ell)XkfYK`j<}Qwur=?CNWDDv(2DP&$WV7Sz>bFp*dA(Jp zZmqg6l``{O47;A{0}W(CltVx!R5#YgXwNj~EK+z1KxOo}-l)g@yl*myC-!0|B3H)H z?Xk%~F=|eh!XO^(I3=F&;sYF+)P%3YYv|$&3K#bxlMCfwP?z-IfO{oF({FlC^%kVdQFXOw0yHKp6XGKIPsU=LK3DbjiG`=*gQ zTQxFPgA8;e8zO(DI`&k)lH*oc4G-hk(HeFgJXessBWz3&(TgWYXY<5nvvq8oRKBJs zB1~%Ddthpz^y<1P6Cc{EIWPWJ9z773U(NoimRid2W8zx$XOw zW@Y!wo!j^4Z){%?F#iVl`Q70C+xL;%>~Cq`^TZmBU!J@_cCc=h%f3@XNQ3CwcWRb> zr(K?Xr{=^)f7!Zp!6NZUxwoCzjG`SkuQZvT6 z46a!m!`}(j-tQ8=&MBF~dgGw35PJ+1v3;ov`SHNmG1`I;@Vxk6!}Hus-UYgN!8HKJ zxAPc$xc?X!Nw*n>+zLC7$0WpXKv3h+oAJyUkE@UL#^VMYW;}Y5;Je48{^1O;YYecz zVLaY_B9r7>$0Oa#8xIG^e&ccDo=o3+BJ^05=?cdtJeUE37d~5%DWcn98uz#P`o9rMCTiZdf71eR>Ha4PD z=OPp6`aF}{@BpiEK!>$5n1i)elx@7l!C;RZ$TN>=kQa!Nbo_9xuMNa0jj!wRPJv=G(F?F6X~<9AvXSs*S0 zJL5~u5{P=}D10nn?+d;5m&#iW$1B#m!q*MA^T`p6OG?CpX&o@{t)@pO5$W3N?6uZk zR|Q)>GY2fz@7sbc8!;R6a=|kD=78PPOg7;2R|+uj`7@3V_?X5DR?a1qo$1i8-82Vu zs4r^f;zOT19(l3{5W#<6zmr`xm@eKe;8XcbJ+DU zE)m*aQn`8OUKeb`_2~N|Q+&^l7O~+WF}sW6FwdzzaMwVgv9pYV>El7z+in9(jrhOS zSx9LZA8#859N1(D=?+9p#Lk&9yp;4B!?Aq5F&u@{8O)Dq{{S2?;X81Nm*O z-ubGfl7rT3f4iD@VD_=6F$RE~8#oScY+n4p?E~5Uud!F%*;R?`jkWDBi6}Wi3Qz2s z6*~b!7)loS?JZ?ibK2mz~$_(7azvPYDpzMsvCjJDQA;RRHq%F*^hDk zlLyYMId7BHUIWQw*P7S_&ZD8lh6PlVdIxw`Xm4U6EON%*?&26bmzW-`3P4zb&K@dH z9`ue{ywY?mkVpNJ89VnEn~s&=o$Z*CO&CwV-e#8Olha^D7aT?gID%bVAaB|bQTzi4 zMb3CUf2cbi%lUfa@hnc~34Y9YJc8i`;aBA5vuE#Q?ASB+vL*33tSfs=L1<;XQ7`qwJLrDcbope#xtA+h6Au zWbN;xbo?VjMWruF(5SInW|l^8Abqqi;+t2VnmWBXZUYjJ^pBd zbKi!{a2N7Oj`UN2d=bN{o4Zq&Tubw=?czMsY*I<0|2LBCXob=FGme%tr1v@hHZJnd z*@2%&MAycCpSoMc43132zI{z``!xP9YS;6fNPI$e%Oi-tt;Q*&N%iJOdWl1l14Ec8 zG~5kbS)s`c7Y9m8?o|x@#jTa#j>zr2a5MpKNex>LrKF=(<-kH?0IAk$c$qK?nL>u) z%8;BIO4dlER->Yuc;Ks9?Dy-EF)_sa#nGoZCz90F$pde&zVCTQsPrG_a7=g zsVa_8V`VgCEu3d5I6s;Q?8m7M*btgHTzuHCl=pvl=}|`ayodmvNpWJ%KaO z%IFkpp^ukK)05TYmJjpM{n}cwBa>+Q+X|+Hek~t{3O>uWV)}K6N!YLIX1^X9*6Jz+ z6ifh|&0-^tas#H!;Gf77k)i(W)Aq--nYj0Hk|zLnZS!Y{W+`&bLHM6+@oN1xW6W65HSrtRGP zSe_LhhIhy)|JLbmq^fap9?AW64m+eqLeF`5Tm8OoS=mbV69yod)VZ%YxQ-*1lr{H_ zo}j>3xUY}m)rUT7-Q9+t{urP(G-EZE3;C2#WIHx??vLasdhYkBCW&mRFyh}DuP!3f zQ3_!aH3g2K&gvb0wAmo5BYbAP?UU5QQ_s^q()4SuaA${R*a%flNhr?{Rmoho8pV-T zT^bq7g%w=ZQ$u`bO=2dHj0ao@Ny!kUA)vozaHf!Nc>m#ru?2Wa=ZCF@%diGEZ-b@T zR%bQNV8j%YMFJ#26va%Wp_(P2#DXxz!(qgKp#I~r+w3oQZrJ%x`aXC*kD;_QtiJi= z^qC(1`&T7)S=OD9`}U^55B!d1!v*B>QqDSfVAF6NB~9CudK$FDz(-T`41d+T(ZSZj zTl^e%B|bbSvGLgW?hP{p<-z{f{htzBg>~D3ngAc>7wpujmV`xv{V(}byvsYtTG)MH zV$(V48X8(%(eCD-+00|S=|fG>j!eGkt6DaO3S^aFu-gu6&N!Nyt~AM3CpPM}@Rp5- z6toqrt%soivrS^FVIDx^d^wZrSaopfZx^%Ybm*$FU$A67X||1XCb@egyRoZ-PRki*o0e z|DQ1I7(AFwIrGP{o$IP1N^Q>I!5M4enueEQl;;f*TC|@+zbmmd3*Rd|s8ir>Fy{;Q zI;dixhCxXE-gUGCy$-o=_eI9kMy!VUN{X^Z_xSCBX6vq6lkQcMt`VV;(hXF)S$J~N zNitHu_f3=Ta+ofqyKpG!M&rpz2ct&1cTKuyy>uhSlJ2q2>DGfX^?Tnl=}LlbdBc?M zP&_&1Jz~;1Cf!~y-3YaBYv*+HOuA1<7cDSttBsgvYBVX`N6=Ewk)s3P3&5^je&$SN z6x6@n-!w!B3xm7G(CeN|*2*d;I+cgYYZC9BlfJHHOMc3x7JFUfSZm={W>=~V@MD?L znxoncJe%f$4e{H%0NIC?7Ckg@pokC#ekrCTE8ec(yNy=Hrl;d1L$?&+pe(x88d1Hjo)W!T{Tlzi+>iZM8>!^-h zB`=wP^g?*h&<9zO)$U;I&_p{g;fy1V3y1S@C02AvwCyz*-*~W^ekU?mUMt#0zZ09f zwQM@1U~NGgt;=?BDMfY+-{b{NF~7*$H_WnVLHumM{XQj<0*ew1)BGXWTw4V(o;OB= zw)+&TF^R+L)i;yv`ze54sfxskJavm4OuoEK&!Y5We*? z)FT|gyXWr}tJU0H!nO+xwrx5`j6r1;bN+`EY%T0p0|xSZPr+`+-I{ZS+Q&3kg0D>i zu?VTp6wjs@Ei%=v~8^#Hk42XKtM1P-oYlZK(yTIk2Rt+jAnL-VX&i9L{s{~$co z)(M~ss`iO;-%Qdx`%BU8&Bs=6m{E<+PGz*e7Um&PZSha`r;Je-BpKCPr&XEgiPpj) zz9IIf;$TMFdzo3vJ99Y?Or?+1L;`mGsLhwnIK8c9bEsgCSrO?Xjf(b{?J#?re`{h7 zgL5{7H_a2SiQt1+K4tMO#3fg!PQYx`L^GW3v zcF$0PQn%pedHCu`o1m z6a0st$&iBlBMzKk-Q9Kx6*KEe(<~9NOyf9#`qD+aW~4)@Dkuq)!2Z&@=a2HQ$B#Zp zyS+Y(Ux^2(mc9y*P!kWCo>l6<5tG=JZ_RlXq8-1zE7WWaE&-VOpk`eG<32;ITsk2H z8HY(l-{MHD@6{En65AsM%c3XBM!Gil)S|o)By!j9-EAn#6GWsoD>l>deWHPrb7_r~ zh*O6`OhAM!5QY4fEr%3rGgQlc`J>^}f=w+u84cc1~f8w7#h3 zPVMZQ+s?E1YiC#56uZPMZP{wOtDWzt+Dt<}R6}ggHUqH5Nby~O{T)|lfW1f4)DRV& z+mO?*`mToba2ql=7hqvEL=-#QkdM_6aT%G0lxG`q;sFi0*lUQ2j+S?f+!;U0G~_5o zu53Su^i)HJrtiqs`HSAv`9e;eIwNsA{}`^$o!>$$)OnSXJ1@@2cHYbj;p2Yw9!?Ic z@ef3#UdaW*FI7E{!gc^*(>JWaA8O*btCdIuK9;ILcBvA-$E;mTcw$8WLwPQ>xR)z6 zDJ}gOaBc!S-LAcXt8>?ScwJLNbH}xB7Mz+0`-Af+Qpbj-;<;TaAuK&RQ|I;BIP#zFBadEHY!TCYQ{x4JfVOa~!$62LxZvtzR$M?oa#wNZkOigNdQH zz6|`t#6S=ixGe>cb8#hBbWOB<Kd;dTLeH?GcrTt?=Kw>z2`?U&56 z7G4;De4d_#r5=?#4IC^@h9ZV^nhk0_8{QKI(NU>RGo?3Ssq0)E6(uy(0+E;3hVBQn z;cU}}OmWd_wTAjn`;ps}%mn%NR`hXO(U=R@A*@}g4;12VcTFqqrd2K^8gO-n#3I_o z@X{$27ww;EMMdXU91ko`IRF;wXZ_v^wd4Hs)!FHKCIRUyb6XI~wm|2;om+6GX+cL( z(vr+l_|rTvP?*)YGPkFFsbqf)x{AWRMmD^yNoX*LtvEZlFn_^V5ljMTB(rKt$n(XZ zQh)jA3dom>Q9HSPm!1yW$o&Zx>1xT9Mj%&W-^mtPTVvSAAKPEr`+8SK%Cxt>-dfmq znD*AN7TdIUm}2kI*0pzGq-=ZDThXYs@CX=_^bLsd3}GLA00Z=(+sEN#t7hX-%hM$2 zL8K?J11~@zfT*DduY#l&@S`>%qw?ySexGX6p4?6L{--3nhGZ~C?8RBS*^9Sm`K63D zMUGGz$nF?&M6O1z7-^qYl9el_k0C}jSf?VXE_OnHWx`2SIU3-K2g-Me+oxco#w3HdD1v5UQYi!t7+moGWt4O7hQok$hm++ zdvhK#7O}sCL_c8lPIgOd_4gRY{(T`>iN-+F(#REHhq_g_3%LQ8>6{Zol7okmXZU`I z%3(v~5faEsEKa4JNP`eWA6qw$K6w)Bd?ZSeQGA+DSt}n>Mkh=dIC>Sy^}Rx0x_iY0 zA?oOBbtS0;LA7>JjlUsZ@-9;oCvShH7OBQ9jmT~s`cFmVhesl`tRW(ag1$B0SGRoR zFY&%%@9XovTfKZ6z3)2j+w6TM0Z{%2yzc_<8#iC@$10=s=T@z0F`Bj^=e+sks zSWg|1Xv^!IHHwkwHTApWB(o9;e$5?^Om@4q>~rhRe-NBn3%YpnG^R(mYG-ts^;BP# z_m#b~{zD%Jz-(yVp)r%|m-$K=fxCSXilbf)ifN6#!FuXt-fwN$+`ZtX`WBsqsfL-C zrEa41to{gzo&jmH+3NTB7?bIx>E79bcBYTCo_gKh(6Tw4SYrgo9ec(F&j_q!!T2owWjtMS(`)2UVbG`VQ#p=+%(v%o{w z(6^$iP{^R{?>o*;#_VxXwm)@)vdZjSMi@q>lRqugFzb=GD{#;~flJ@3yzdqIN>_K_ zTJ9NMF-EKS1jN=?U3jgzpgB5&*emGiw;?v={eK6kb5I)K2ZYvVcMP87=l>pl8%SmG zdp+R$Z{fGeo`c^KE&ea?+b!-}@w*<4yI6PmPYIP-7>SD;Z0J~pnjlM}aL z0;;LTANw-(U-&!P>EKJA5&rMAb4kZUT!XD%M32(TgeL5PoUv?BgZh#v`e8n zp6v{v5?rEHzzO}B0q|D-M{>^XGs|+~<7&8%n#ArqC@wJbVD(YLih11=%d1;iB1Aop z)ABdBL0w-J-*irklOJClj~p9no|iZ8JinKa>ZX5RhdOgLHukC(2RpW*jq~zy^PCfk z&l~8UcV3<{Nk%)@0F=asgtjWFa=D2P$VOdV+`8gautZee-jsMtq)f)Z19qXVn}>Cc z1F%TpJhGkvIq_kSg);Z6>OYp0$9^GMARP2f zg% z5A?NfOpfz06^FcLHAIx_yZ{H|RV{*oHMg5Wy2q>i)A6GTx)a8%X{x^p^$L4hkTDdc zCnjE9F^Tgse2L~fn}hY+siScceEug&O+BfiJ5~0Y zSiZ}pBau9u!&X***2O;7T#0|;)kjjC)Ulcd`71s_kT*1#`YWX)a|3aQtgsq-s`a(O zs#<{BRqo*YP|tyOZO~p7c(%Hib>~U+nM1x*xgdej@07Lh6=ysvw*97b?ybgJn8=3J zyx~10B!zlcD4tdPSBg_e;l=vvBogWr8#b|qSZtta6+84U#07yFj7o3_?-S4{?%8z| z-+tD91*`=ocFH*fY*lT|0?`oPNOU-!H1^pc3xOu)f5qEUz2P5-S_!Y-6NxV8u$4Yk zImv^Xl-^Opk`TK9)TF>>qZC@4oDgyjgQt4bba#@99~R~xE_3AF_ zNsbC7`$XV4o`@KPc3M6OSifIi9DmQU-XY(GdD_UQb!r;$M+?gN~vS+@3m`h)mh3FrJFlATKiv!c(Nl zY0aIeyi`xy%hmP>e!Df^x(o5G_^bpsE7bPZisqqQIL&QyAVMow zSPR{{{jaLn;>mhS+cH zd~b;c-CoHl^a6mm+4Z*B>luFk&YhbX_K<&%b#H5TsK*V#VA^W@ry$4y(`x^7B5jEq z1;JGW4oa->XPQeVK$B^@8Pca>_3)|{i48t$;2P2Cv}kgG;o*_v5br{Q6*|BV@$F|| zJ_SWeR%y}>)?{~dnqjx5{y@WrCRzj^hI3lcak~?{+oL^2%%eRZA;0CQ6-mJfZA0i0 zBj8dre_cPMHtvk7U*1fF5g=q^J5e-ujH?C5lr!oumn3mxf|H*}@Pe3?%_WI+`Y)b0 zP&YhV1)Fq{vE71E3Wc?gFd{&sR;E5Ab%`(5 zjZdjBS_wt_2IB2@=0?>!K`cYDa}dN@t&`Sl#oMW|e1^CS6hk}BTdSrYB8ntzBV$b{ z^^{IbAi`XTbO5NQvNl8JDXe{e(!wG-b2sO zd0A)h+C_0L6|`mpR_xsD{|frHLA0$fBD%I$%cFcZHn+0Y+0Aty_HDw*hUUkSQ{63~=1zyx zvLo}v$(fn&P0JsVHZvJ~P;#|@q{3X7`|E~vhPl-^hxx1dP`@{P5;7Y8G%2(wpt8X^ z;(Fh-tCOq~{QntB%Sv?NIOmIxk=Lxarg`gno^sn|J+-POm3Pf*UXSy&qPcYw{#k?n~_LZacU4u$@5pyup>Hk4*CnLc{k}dM1T7 zPS2`KO@k{d4S!O$a{_Nv*U4anbIv4>L$Mlf+v!3f%cbZnC5KC492)*h2bq2l7~AD> z%5-kLgZ}hbAlctT_@}{o?f)mmq};F?(v8_KEH^&at+YR-%*@_SUsr#&G87#AwpXl1 zHTw1e@#?%udTeQX*^B8OBhy@Z-k0u@Sh<%;%%+K+=r(gvv}e`!=t0)pglX9szGr9O z#zoF4bagCUrJK^h4Mh*CS`#gpad!N+gGkXAE8%PWtJvT*ysBx4T5g$r6W0@h_UKS* zje@AdcAi%2Dt0u!9D67AUxXsbFM%AmuVRT0q<%_w#s3pHL-C~e+npmHmJ~l1M{?c5 zm->&*djGn;mQt(he2_Waj(*|`WBvqk%Ny~lD7@Ti(CMhI^kHuh8!RAFWInp&#Pxx4 zbxU?LQ<&fqdzIC&4LAVc62k$t`&UU`XD#eyv~pf)czf3I_O|-=IEk!=?v!hfU0OY? zs)Y{1g=XYyRV$;F*20_o+|A>N2MwF}R~u%WQq_W5*TS*^Xc|i+=+pRDDCH1%KE)3} z)g(Q%Vh7gtOzN30qj6BM-K{D1i_~xFUd1Pn5HF*vl;g#_I;E*wmF8`g(2Zm*=-|9w z@NWG+qffa#TAU-#@jBq%bs0=HIxKx?StBi8il1-4;q-@ZSbgPdrd(6N&l~bhp{F6j zl2KGLf;urPvKEewbXy!D^l5Ni=^>hs&CNli*9+|D1RP&)?gCo_*PFFYs>VatFFKOo z#8*dJgVx9QZ+>|V^@Qea4g9wH$Z37~uB+~DCGOFTTKUnut*H0e zTX%kN)5)pZ2=e4>JC;G%rr>w8O<(P$vf>j6^o#eNBNL=mpU*t@88sR+iY<|{cXw`? zjKqcwN&R_DrPRqJp$&y(fD6#%#use5(O>cM&MyfR3rs{8A`dRqUwWEgpYbDY&)vAFmBK z`c?F4?Ny1Dk)7|Az46j#{x@1a>sr5i0^13D_slKnJmyp2X_|?0+=&%0x6@(%LQR3@ z$vb!Q?p9HNu`Q-0(msEx*}s+1>6h9o28g*OJ3a+<8?_qG@U9$)lZ;&lg7x8+WgilZ zMnW3NMiV(wx%_p5Igic_?n^L9%lRwK4L{aRuBD7e21tWRm%iBqvL#TzT%^I>FQ`#d zpfVpeeiAEBeM-CM1tJCmbzQyI`Qbex@$e*8qXs9@8c3}8S}#Jh;!Ac(%!X$xPRtJb zqlYI)7T2mCJxmP?6@A4RyE!XPLQlpq?I9koF~Z2BIzL_$l5qvU%ZlB3mX3v{f4}4H z8r^Ex|LGb(8S)I*l^O#sdau_grO9^=vdwuTBK`w2=8>_BVZ2gDl9ByF8p?|#;(b1& z7B@3C_MSR5+WB&{={u6wb%eTMn=)bh)7!+yeI!2|jl~%LO?=#6^}03p%5LDn+GIh~ zwSK68q*(Ti!FbCv@!g07hZ4zR%OnXjO$Z_xjISQ(gX3!7SoJAuqKGos6|XKuT(-l- z?LaaVsn{WDpTA;t%4UD1q|fm6l1{f8ACXTxQEWP0lUMbrU24s(>r~jq^1DxZ>1bcf)c;P9?GiYoNn|&X?bJ!~d%AiG*vg&LdC9U{%Wp z0#FU}4Pk53w7jZq)HL@}cf=Y0a>jq8d<@yLE_Rq2lh6}Jt06@8)INSx@(!hi8%FWx@rsNaMNH4SI-Xff^JYg`xoonTHM|V4bn!8tiZ-jaC z#EmthoH_@O>i?SpU5o_{ACT`Gdv;u>o^g*Xw`Y%{&8VJDC3{MTp|B){AkB`B<$(J; zW*?pJ^*6JRuA?N0*w)4Oe21`Y9R-6i%PN}LffWrw;MQhueFpMwM1 z+`<<6b^p6A&V<36kg%qV*X}7pD>`Tc&b*X(o$Yj;R>bKAy4i@%ro^-&Ni$f%{d))_log>z&KO{HtuFv|<=9H05g(5XDoBouJ^_AK# zb!B|k9H~D-Sb#r7g_nTwN{of@zi_+R^B4Q9`&v^cxfwH}!E$Sk&0U z8lL11MRItsYB=Xuf0ny^e(}KrFuy!+L%i+Tczcy~=Lm|h7VcbhCme=(lDbRblO=C+ zLby3Alp)U)uAbm9e`@)&yuKUGePK6iKtyT?aK1s;2ooz=$ z^P|X@^vGnk3Zs^Llv)hr_dS`UeiEh7mDV<};?jvHu)vZh{^eSLA zJmp?a!1Q6VHo)4339g`av{h@Yx#q~wtQA34w};)eKcF(=UtMT5L`65sGmDWRpyh zcU;!1UCpA~l+LX37qIs>N6Q8X0|Lp5g2|rd5H*a1Ww15(YSO!hsF&criiRDvM=b}2e=;myVX&SyLp7p*X?~k)yX@@V8;;Gv|X*6WV z;@1T42j*wNtmI`ryAStPtRes8x}7d~oF7OI3bM~)MXG8Maq(GmzZOFDfX5g{aKH_0 z{E)z=S^g^Bu)3AgpP`I}*w=V<6`0WvpH7{3u(=tz_Mw8-~s z*GX!ZLDz;Qlv2^&`3U!R!nmjV9Y?sY1kIE=*5ybVm*b_pVde;TkXjkz4A`8lzb0SD zSy>oZSaZ!PpyPGZTdQ#raHOLdQGx03Y&tA~Ku3rFj!zwanZ<)+vt|CoD|9$Y1*u>1 zv*=ol3l3kpY|-Vo(?>6ws30L~`tU_R%(}ZTnk_dN;!BPTC8rgmD8^0q@u5@|RFIPi zO{>xE>&%Q2LD8xuuv!rnI7x6z%qr!K#tGawE1QH7YmBt0XaF6@{*W!q(i?j0EcGbjs z`2RJG{*zQLjE32-BZw7r*8d~Jm4-O+aiN0{p~yh!Jrr))d#3?M7EavGR%Od1!CfP~ zNn9hy^mSVl9K`eiLZ)vzY@EnpBP|`QbIg_5bId@xi$Ki8x1YSHs z(@L4Xeay*Q7cmAcsijPf43uV^hKj`bu|5N^E-j$V9R&(XR2>{-H4ef(;8_6Zd-`F} zk0hzfXdN2yy(>Ne)XAZSoOi4H6S3L(to7?EmI%GYai%(xP1vPw@%{<>Yc0`$He5ze znf0a_8O4nugqd0IR+LwFfa1niOfC#gmYD-itMOyJ$^21F`h_X&wixVo=0lZadUId% zAj?<>HP(;fpVt;|TNiKdJ}okDx&3;4`ETQ2A8_FRYtk{=+vl}aG!O8`JC_^sW`mGG z^TFG@b__MsqEKUFpU0%Ar7(^8PXBf@8-A!U?@yp1ny4VTc)6L7T)dQy?7zm#zmm$s zOK;9PPj_JD2ik^c&R&XK?F0KY|3A?l40`woHP^ADHjuwfL8>+-Qp_t8hl8di3~Uc`bZj-q zWDaQ3Ms^(TVDERN3C#_bjYLx=dUnd8&|xmIWma)yZ0PRvKHq-k?y*%etcD~;hT@nc zp@O%phC85~UXufLKiwZaXDdT<#cHIuA$v`)x2Bz*x))%y4++~Tb5w;OH+%)FqRYL?4#4H;UyPOtSBe@RWDV<>HNm>S@87JhlnQMa zE^sl^N7z#$wS31CHqi^a6!#UJohhAehv-`;zszzXOlDAqCufA5cFc@u`t{P#jV!*< zl?i6}(4W&86amar5j?@5hZ!g)S*^2o_rY~p%Y?p|M0!tcM1(gSdUA%5RTmI7+UES! ztH-<})5=k&{hF)xWCW$TyzdFr=^llS84R>P7lQO^q;EM%w?$fZ8_jzk7C#z5zJcpW3MjPFbdCt5L>a zfS~=QJN&wsnmZT`e<4#UUx{*Rd20Vu53`hMim)khm0Db?lUMi4+>{Ig+bPz+pw;jb zPLET6V~d$vZl~0weA9r_YMiTd6mM202^K0oK|@$(enOpBs9OZ}N*-N?HFfD$m%0aY zo1oQjpoJno8@<^)u?j|8arS|t6#e{>E?MG zqi8P___P+f93c$=RgO))MFx%@q)g;SJnlD92u_L7V~-7S9Edx&I}^0mpi92!EHkN@ z&CFd{#??D3nOQtMIX>iE`kwZ!u{*LI{C(#R#;ykEAKq#bUF>par!szUCY2G|9_8r6 z+x8iSrK2D~#WchBUF4qntYrQW;M167EV$KF%vgsW^_L9|bKb)yDdG~z0roP@Z3c$b z!OW597%Art49qy+XyuNG4XQ!g)|=lpCr&7YQai zPl_F>6ay<(qsW@RE8Eu8&&6tU5K*Pmvbp!VC5e9wS5J!0$ga`Fa%EK?(a3RCAE#fX z^?6`LGknB{H0B%mMwyEVXZS{cI?FNI+wBR#*!S!%P8|Z>9A>OqD{LGT06bt zxF4iRIcP}Py9(A@4SsLZd<&v#Tk!zE)=|vlbziYvJ{b`QrPvuP-C4BqK~<^bQ&|(NSWZ(nL@b8#NUOp3cH3Rsx?u1JnIIv6LPF%X z@3{Msl z&if+L(=G)9fOx;gyLXNLStF*EPL#LG_)}3f#C-a6^>Yy}`c8fK>8lcxBhxW8USA~|bThdA zEsb}x?NxWk@Km9;X1&oAJ(~IOUZpIS81ZQP+``tgmAlG@;BH1gHSEb@q4h=ebIOKJ zQ<`0u+nQbKvr<$uE6QAI_Z9ZfN^5mJ>=)pn5FWpYmQx$e{5a&bZh zp`|xwAglT>9*G{KZaBxg;yOG*1e8qCF#G3Q;xUOcx4K?%^g5kfX9< z;&OlZC5tw-O6SJMP@#Prs}zj}F4$ID%IuF)13@xx%n;W0x1h7Mct8Iv@xCV|-q-X} zif|l>CObW*!x`%G$~ov>NR;r?_d-rycCq`>Xy^J$wAtCeqRy_|G>Hb5+{@axvPubm z9R0AXj^8NH07wL2q=EQT0DATSiy(2Yd=xqBIUk$kW2t-;IV~TlCtdPI`6v{HTO_{c zloXd(a+HckGbP+~DSKRVipL?-(q`3ziXP_eBM83c$pnX+vmEvBgf_H>&J3&GAy2;v zof%TSCDhBB`HhrdHJEOXV!805r>uZPi7sDzCeE0QUjM1U2<@5oc~C_3xj^d~6S z{=oHdk(SG5_!|q!u4NB156Y6@7S{`k%$&b_u$HRT)GJmdz7qiry%kUV`*1R-VEhvw z05!eMh(9Qq_=Z({pF=Eg;bd(1(oJB<>_y`xj5}7uliMUaoRuLqW_40&+37g?O~&XBfy=3 z8RAz>-ynX~sMV<-87a;Hr-B1iBuHs3Fe~L*3NKHVKfsxC97!+m2-p^Q2ya;^rXRYU zQ#&{D0QfWq@l?9D#eWv%wQj3_+Oq4w@$uP$=q2BPufRW0r&GNDY)j>IO3rKToGjd2 zftkuR;D0P@Dc*{bqUsj72!CS=2HG;wM2w%1H9ggRt2#^eVv2`+9dKJ`32li!)CT)R zxu+`D(dfu{xJ5L8L1>^hM_gOe89kQy@JWT*kBxYAKj+CSHz_^fJ+>b3CV#@3Nn1fU zuU!O1^NfJf2QC{Wr^!D`m-QZXTA;HQjb%REsH%*Oc(iqH;ZDrGwKc0Qw2p(BWuxS@ z=o$9pQc(jg``R?+ltr#P?R6wH1LhRstrdN*$^NL4aPBa2d>CrXgi?n=LQz$GyUy@1 zj|I&37-mL-q=*irsP2`mST z7K7Rg;cajmiQidt@Ou?P2cxH11v!vU2Yhs(fDWWP6uW<;Xn!&n0>`8L`-A-}&vIiU zze8EL@;msSoF{|d)ie1AACcDiSdyYgk(!HV0-JuE6e*T7F?joUAmkBo`K7`Y?b5Wj8` z;eGVwFPVw+jb02-9w)o8K0{4OiK4UypJBFsBj*>K6k22h=aj3i(I>2m#)-uWRe#rrrB?p-Dv3|}0Ch_Hy%1wiL3YUDb-SU`#-|7dlwo;**} z)rmWi&?{r9FRWABY)&F)6}v4b_FKqhkVB3x;aUR^+cj2?@^7yGN*1OrtEb#N(l}Zb zyKA6(VX>o$Ow2JRdO}YzS|{;cM}?m9WxOgq4GhI0`UB2Hw)*jJ2@G$Z_*F;YmaM7R zvKo77N3G$=5J7&%b&hD^`os|&*30sUU0f(=Aq`JontsKs_9+*>6rcH($XKsL1{t1>(|tfP)i~GNV&SO3TQuOsG?q1L}q7@?B@Wp}U)DjP}R0 zXM~HDE?KsG8+g+(7QF3dT#nmFUx}=IDG(J#; zD36+xGDVZi$coE#7XU9BIk+!D8}SMbXZ-Rq}9E^8{NX}V6^s3hjh#O1o0%S zx9XO0CjO)pvMcC3tAfLWE3mcdWY|<7_w7=_8DlIBKl=tb;~T8P3}KNQiCS4fr52W} zTt*#adCMldTA;-oJVvI)`w}0iLBTT1sE68cg>hEKi_g)7(8qsUDNVeRfOjmVv@A>G z%RNXfEmPFeMB~e$G`>(x6U8*nP>-ec#jHU&GadC*Bs4QRt`2dGVi~+77AC| zJ(cS*fn}!LP2hL~rRQP_?)Af9+M4&Y~{u)n+ z#x}{a_@gy3>Ha=0lkz`8b}^*}Lsmp&Zlk3kb%~V;gVJjpu>ou#MK1RgvKDwKdq}p7yHVNXRwZcc=%R^s!d<~K zvyynTM%E(n5=I`!gy3C}^TufLhcMB(*f;pZkX8-Vs#bS1Ra|`Q&)l5uJhZmhzUDFxk;UsrrM zodi2f8oBBa%#`58>R4DGqKk6witJ7f0{P7Yu=4x2{?&m@<=^e(lYjF3oxh{pxpn@Y zL+Z=^Nxs49=f0=DrRqz)r+&}PpQ5Q#^2UdqxCT)&rw3kk_|GtJvYJK^=NM|ky*%d@ z<9^QSH$#0lYtKHzC(ddie}pf|D*44{CpfN;$P)IyZ|rBzT#H7*KcEqQ^TME4WIp3K z*W+?cH+c0{uouv$FH!Y*Z#KFn8jmZ5L#37Qp{O4ICX^gfy_eZU+wMU*#k0vg7V3}I zy~rW*q4bnYNP9-(i~k)l(mRi*P??5+;S^vqI>ji@5f~m?dUKMrk4d95jr{oEUzDeo z??uvgkw{y8jjxeBysq@WuRZfiURY%ArM!HuJCxK(o3*(C*%OK^%AmxImkRSc!|iHIZ++W zEYy^0bV99K;sPT#PD!5ccU6Bf77|ey$e%YR4#KB-;nT$Tj6}K>-KdmCj4$@52Afa& zgz*T*`oHbpEq1?BztX?dbLw|+pZ{7~YOTv}${%1)?I$l$y|KdgYx&s;geIeGdH;Dx z#|Z*;V>O8IEjPGuvI9;rSE~z?Ekb-S`H|o-b9{3pj0wv^?@LBj`9gdE#6)?{O$ztH zl3gN%I?o=SmvZsO(SyG{{V`AjmNr~7QqeJq7MdB8W5vQwl@M+<**64~(FBzqjqvYNvuspNU9k}=vUmL8U(wo`{d zuD>&YE`1cm1j&o#1{>oqy!ks{Q=%75k{ulq^I~s!`;yA=NlT%rmK`;Mlj7foqpAe07!WS^p+ z;roQdF@Uyw-v|*!7i=f!QcKO+=wY{&Q%SCbzCeO^ScR@Qd|~#1?2U%12kXCN9PeI( zaMntwEis!@RZ@L{V>ir=uI{jyXeCQgezlgn9mS2>i>>WPPDb-B{n5&1t+MlKcI4Gy z#_Z<6E0lLLmH8}+@li7;OYBn_ptI&qf1jpbd?5n>xiQI1g4KaX;C zo#PPOYj5Hb9Njok;7~9H3REPZm&|_`RDD1-KfBr3A6N|?aw5flo9>}v?oi`1b4D^? zY8^I0)ha&bSZfNdmzm#m1a>5Jqh}?&^yJAh37WowjAl-eRce)0Do3#gl)A-zQJ|eJ z7pVYq^xA3c=f(y1OmBeF6jv}0$N2lB>Ny4Z|* zh1EnZBp;jcCf@jy5bT;q8!hIY z>-63s)ra)H^1yp~Q>)&Wz35$a)jF^k6n*RO6-(yyZnW&1B{+=J-+~Lz)vj`+z#=8y z7Q)8)2Kz%rDn7^UNV<|-Mp~B6EfRWQgwayGDOI9os}*s8K3iSVmMME&0!fPZcnYdr zr-BR|7!+i{8MxGn-;gSmBYRP{D?r6-B|w}UsgwhCO2CJWc7BaO8_*T4ds?OzFw2d8^y#ilV)x{c+vx@rs1^CQ2uuzUbSyTTU&xUA%* z1WaTpDsq&CR=As^VFCPvsMPy=M6NHc&j3%AtY&^?$;%-yhhJIesinV=_dyYgmlF{S z>-^&F3TtRDcB$XNSYxMP4bE-Ww>Nud-~m~;)aN#uu}+xO#$*1Sj%aEJf<1xRHgckSQ;v8Y@4ZKTDzR}cX&b-XQx^^a<^H!o!0zV1P$v0XH z1-C8xhCu!T250d@(mHul?OD4+Y(63O^$Q1@9Ah`BGFxq$GaTR(Y}2LT!X_rqo%jX) zUn1~bKF4=2%?kKDg8maokSlQDwUrE>@V@#3d??{VDF#Q#8FO&z3Z*yde4+G;*)Lw6 zNPm!-bvm|ct7j!Sw!Te`ibjQ84JWm_S@aV(E9wNB#L1-01}wwu>R%`Ybjt}#b-m9d8;x6rbzNkPLi z30A#=^$iuI#JjReSNK**N-tyw3)!3|#0)OoZcFmzIoS(LhdITcRI1T@D@cg5XeTax zTIo%GVT*;kKLR?eZMB-M1#YZYVn*%7KDD|Q$;`)^-tVd$k&z)s9(~YwUJx zDc&>~VU=f~&FsZ*yR6!hVM6M1f?*6~mT0^%%5RBf5WB^EoRyw4?3SG2MrUBNEI3D3 zqJsUb#@lS>NDw0Typ?h|X!=N5zfGEMNNMIxTkX~O%^!D*_flE4d!&NVs}yKtv}*A2 zVJr%k+kAG+!ij;)#5_@ms^3T@HZszF{8RgllY~TWi3>Y%wZXi|LIq;VYX%T+qpiM-!(Ur{0{ng#F(xM-(0jD%L*~R*ZkDR|aIzdcpf|45doHVf z+nm^}_YAFm%bfTkp5Uur*PH9~{;Wl>#Kqmz;M&<=7XD914m+a!Ta?mMkH1OqzX}YN z!sg(A>jU`zvhg~8E^aq^!2eBh$$09(;ucxUBhVUaN|gZr6Xc{{U}|+))9(;`@>TwT z|0$^OKk-Gnvs3tAHnbyn4UrtqJ?*)}H-2i&G0n7^1*g zCs^1mG@HA8Qf67Bw&EA?)#l>N+T{CSe~xG;Rk2GxB3WCb)%HF(gNM2w@EUL9kCYVO zqTz2z%EF;)y5>*R>Mo^Re2nyi<-@jKNaOSAQ_foDAZ6d+Ei$!{ z(H7rw%hoZ9G3@CKbE>c*B|xH-{a6mu3k`1Gne{5ycFFjs0K}YfY0|$fFxD)&RM3>M zIrKqes4o<}&Yacn-z5P6XPv2kH}qj+=yWLf6$?S-28hj=Mo`!_C$0cNC34Y5bn72z ziJ=(xe{g$t7e~IJpElRrdSD3QUkNi)pxGT2fe&pADE#Ak-4_hNY ze0%l@_zi);URjCtZv%(Whm8KS?48p8a5?>fM#wo&dqzTihn{w_1cvfdo7^KXaM#}c z;Dg_os@0tkyqpGrR(~JwDIh3!H)jKZ8qNlSxRkSi;CvPJ%%q|?EtU|)1ipAcc7=2* zYtikYTQaoz_gNRA9};f3zFj?K^0bL3z0n!Mw*HB?(SDH`RsOuU57W3&cpK8^U#G7<6V|Khr zEi{2P96dF!#c$yOPSF#Xzv2^a11BA-yX~}UkCgNKQM7&VkEtk)BQrhgthWD8=aFGW6p3 z9oB-7n|_z*Nc-ho`hT*v&jDlu*A9YrikdkeI8KC78j<1e(85UuWn~WTXA^n+T!9Oh zuzaLB+rbHPv6_ZmsRF@v<*QDBL_;2bUqG0*6x>Iyd3OaU|L0;B18 z@?^;QROu2HT=s(pSlw-h-4bvl?lk&(YLzb%Ll1+@>14inmi?&3~Q! zu|z%=r%D?F$9zFL@ar(^YWHQ)JsS{pqRofvn_Yg1NQ%wTanvG`tl0RyV2J-qa6=)> zn?uQbl)f#W>6?@#XW3yM&Ba-@ z$%A%&!F_=%a4FBM;lJtW%-XI8ALK~so-r?bmsTetdCRZHzwyL@}-W!+8&H%t+Bi)pK(P3$WWHlo*FNb6I`Smlq_Tr3%4k6Ir@jobbZbQ+zwCEtY1 zR!Nxj)(qrpBBlem6sQ32(i9eDa)uh!!mZ>OcZ!q^r_(&;8sG4yJ(IKQtet?n8LEIf z^#pEOp26j)@h(;oYCS2%C-WW$?$f@at*&wC>od9VCZfxcA!P@RQ`)lMlQVHKLgN}B zZFCi%w32^LG7OL>kcal^>I)~xQfF6`bx4^-Qbx%O&>!K0mHH5=tYBAm7tZa*vQq-m zeYV<7v?tEkC2Y$FLyS`rxTPr@`EhDtkD{c~fNFS%X`da-945>w(Z~_OQ*adDSKzf zt~o2EDt1}=U1~O(RCmrxCrU-C2VG#76g)~y6p|QmIl!0<@|wbWtm1ug?DgLYFl6Bf zaY2Oh*wH(r9N}k_m^hYLC>hcsJ&Wkrk(OfajQ z<`~h*!Mbz+J3zkV9{#?pG zl$D%5;~+*mN?wsdos8eTb_v4)C~jq^manW`a{0?5o*fH80|P;}>7~e4sEDi+`5iGt zw>>8|tfctbuhaVcw|JTz`~H14@EYdxUc4Q6J_0?W<{?(a#mOL0DwqoVs@UsRX!KG` zdR%iCPMpR{03PuqVl+=AHYX3JJHx+K8{diPdi`|XGSWYxgG~S zDroJ%z?LjU;CMR&s#uj8&?7uC&1H%Ck)es(Vx#4Q475b02WA*Ujm6>$DWcVT9mz?q z#PzYEsXQJl&vjOw#V*r*CFCIM;m|$Pt6~ph%%#7DSb^zL*G91`IXMuKby^EbLOPy1 zU-~CvdnB^ke6@BWATCe2tTg#I*#+`(8g8FjPC05h$j|~;a@W+#*Wx6XyDD30Z-sT#i4g<;ZONy2A&j6W`gY@&k(*Z zah;0a$;P|PA<`u0J@m$1H6s@Kt>rmVj)$Z8s3Q1*=nQCUzLjC#ooVdGk6%WH<;QQ$ zdadp`ChAs+MMUfaviV`qZ&KOu$yR$vMGNYcXhB+?$O+7dL<~Al0tV?DoNAT{6NG_4 z^w6;E7UX1N#$Y>n6AGDUH$f~cFK^jj^zt^$h@&^_#@E|$<yAsK;$aRBaO(@1}$G zYV7Cw!pk;#DL-tWK_b61ONFfjc-4!9t(LjPI$K-zK0`E}x8vJw!UmQBDsc6}8yh=g zxiYL|Aa~G^Zj_|PU~c?B$wImeGfSme;YEzDh});=1dw2Ss}M|9ru~GIVGI6{3?)9) zYd8rdTfG-6Bu1tdPu+U*Cq@7fC%|G2+Ng!03(?_}k}hMRQ;g-r@W%tm=2qGQXw{8~ zJxmjFXi1;G%X7-uC-yw#A7_zmhZ?I@ud&O1Dp(W6I%zAmKqaQPkFBqW=VoJzk>i6{ z2s{!Qt0xOJU9=5=%G8LvuJn8`H$qyo#%X%rpc+g#ZGO&Z=^o{X89Oj=H-_lVPJR99 zU;+!y%OOgf5o%0+O?&pMRAnr9%{eJCyf~Q{YJW1uo@{dAO~-2P1hvv!x%sHmEV0_y z1pWAG#-Y#8>;8uft|Z$;`=wGg3BGTGNAMYWX{v#@C~QoT28Pl=7Rge%Cs=&4DL**z zWK((Yn@DdLb~gz_9~i-j_Z~xfRVmtqY##btD#B??p}~hATlEzpw|Em9*khJO$RZ)~7z-FK#c#``BB(9Z!eZ&j zW_24|5Uk2h*yyB$)4attH;3O4LD-J~+7D;!BRbpU6<8pJLDSTPw!f z?Hk5t4%w^{P5W6RSA=e(L^GO4?9`*q35c&tf?K%CqaVU+bCo5dGg<;)r6!-F2hI%3 z0_r;`FmU?i;5D7P5vX^Pp}?_`zfKZ8W<{x-n{t7igXnsEE1h%29V}AQyVe{>Kymq; zYr0Jte{nJmKs@)VCaDdW`^Z#cI$uK=D_RCZGA?DUG6IXgqmNGRjDeSIcpCTOIo9pe zo4D_cxSum8IVO!bx*2`7S@TgJ(M&*NoL^kWy!iJQcqdKd!YzFW@H5Tc;jJHj) zK(%+zy+N8sH#w{9>jFUOPTALujU#q3N#mHilHg`$Sm<|GT~ZCDBXA@22$AA(v z;vC0Tb7oPp;Xdl2$W^H#1K2;MuUv$R^HNq->(JeLTeln&l~R8T_~Ci z!on84De}9b7!_q;SsC6g>nl(mxj>2gUK>p^H_-dL(na5iY10bp{x2y6jufdVg#kARm6E3!a*pUjZuqPi&M zQra7zMC!(g&LWC8Pb_krRmF6x3ahy2e15Sb+$l;&imZ+tFa9(xx`D=-No}9D9j}!6 zxjS%~II>>kRBd8k>_Q>E1y@&( zxx)EpYLd^e1sEMgaysM!vMY z;K;~R(hvh;JRa(wJ*a--stNh!Q5$mQQC9L@{5x#_ev{uOU^mnLon>sb1X!vcGty8o zqAxqbn}Sz>$PjV|F2b;ek-G;x@H~KJ?gQ)7`g+hG55ZeS^6*^EnNncv&PLAt$@wIW zb48wzt2no~T{$8t(}g@x7Cf!lEn0X#Y1}2Z8XY5Av}Nz{hTsjGg*>zy_Ns5{?BleA zydhiH{~y9esGFh@oAt(|zCEeEv03jNslCxie|!zMGm9)|QuJtk-F6naN2}z+^6{4m z_ouBJpSyPa-JZJ{i>I)q`{;S0s*5V->DwqDn}9KgtC4Q zer$w&2dUo-`#zK(R?+x(-*PXX;}f};n=zu9R`~y&bWQOf zTm7LULfir$A)iyQnPv57BZ{3YTK<=K&SF3>kK|p!?|czG3-flh-Faxid37h3+-|N= zAV;b?iV5LOM#@{R^(M{nHjFn`dH%e*#wDY)b*dbK7woTX4n1+Z;@B5sTT=vYToI)oOe~zV>PhB0&=Se4DDuZ{7${E zKzsHMB*=B*_fn)Op1?TN_PH+%mt?&X78q$i+vwOz+%bcsa@Q$;D?uTv58wdLD@#f5 zgJ}CEHEgU{RU*(DpTLP`BE8In2uG4ELuK(6VbK674VkLj2B6a0dGW_UTJ z10y39IYs_(jubFwoDLj8fjOhGzom4yfMsb=@26a;^!Q|;+AR5R%5ZX;zgEkAUSg1lhwv<2Fc$PM$PXk1#G>C?)1Tuh*0wP6gJkI?mB)^8z1P+yp>jezJ?TTr&zBHh0D;R zss5Z~lPE}s|0Ff+RgA<*Dm7kNC7Wlw>Sb@Cu}U?q>A#W&Hw9*!C8la>Q@Vbe-B$I> zc**r6#))z=)AX-W<%(6()cC}FB6VBM!hzW}SN}eK8+n+&JEchh5P75vUmW!^QG1Ce zk@6aQ&*|T?hvd^|e3GWATNWwPmutSFHWhntVV2rg;xIO~2e;#;ngz<5mXC`5i|wE{ zsnrwa{!10gpVNipqYBO%d;Y9KqIt|NczsZz`RPLPaV@Q7#2%GGD}0hbg9k}c zUJb@*<6HDzHpwU%XoU*hs+j3S!NByge%Uc{=VBoje;WbzRH+WpA%R(sFg%b#TT>U+&npnI^X?P8QB(iEnuJm_%)~Xe${&q=!t=Dl@ ze@|4W`@3CEbxvzQD0PQ62^a1W?Y|JO8G&CJEliKB3?<-HQiGpS#@+(y{;3>i_iq#Z zYy3k0l*eZ2UmBiP|J19%vjr`yf&Sef{R3DwM4g!mrfL5}^e<{JRDTQ3sm4bY6b}Le zSv96pL2>{-f-Xeftk!_wI={6P%<|KL!`d>PPfB_ixJwA;;zmUU4-{V+c}4km8MGdn z9U$qZ^m^z*lDc|x^)6WrVUTMzJrVda26undhBDjJr}vErj)_0W=Yi_ytt5ykdsxl{ zRmjSxg-fLtBnF{qQN3H$#iR&2RGS67&Sn82_A*W8ct`Y*K*_7t50PR5w?x8jl{xG_ z$NFKO{f8D7&3{48OlGb+8=j?3jvJ|BJWCg(EmNfFS4vw# zce=Ik$E2iBH`Uk&iOYuKg?RivN&rzqbLJ>3N@tIW2eUY^lP-7c3*kww)a16Ouayd58sbyj> z826FRT0vzhO4)RdP>B^%@jiN=cTkX|Hz2glvHU;blyaT{yjp>SkL+LTy8y=%5#bJTqVy1>X}Vyw9LQ=$Hwr=7kHHa#_RpNgNGv?V-HH4 zc$Rbf9DTA~YWZeXCsoaF^BftovU{I?cqBH?$J&n>Z5*#2)rHlP5$hvqnS)8}LPZA$ z6)S&x&GiHQHLLrnZ1LR4(v_zpZeROHtUb5U-+nCn7`_WiR^I7vuinS%a>>WJD@B#p zX&}3>#0d?*9-$_D)W@j_{{sn$%Nt(jC$#{x(;q(}l{qYkojj7tA0{bwGaHa8ep|{O zXn2nw@@!A#87xkH8+8P9IfVY$g*nBt7{fF+4-99e-j}uLM$>soXi3r^{BCGTzdu+V zT5`s()%}93deiC9lGFacp7?U!1RsQ!UXt{iGm^ojgi7ps*}?u?B7BFO`F}>zo!LC3 zxcbu9WEm-b9!0r@&CV-}CiwRRPaslRkL_3Wr4663I%mg5rn;;*_51s32%mJxc>m^_ zK@q7|qKtQCv-6Uo@&2~p2_z=epf{bNj`qabKNrhu!)aOReY0b2AEkig6~KH#6qg4` z0#I(=mF~uWrn01AH0b{4Ay7xeZ^>VX@gwq=X~RfD{xaQ?zsMbgM+;X_zs}L3d@J}q5Lb4;E_Hy%V6?yv_nThD9u{vB!it;&vmy8-Mb8c9@42!U{$6w`l|NEN z>)b=9pmo$h8B%%T66pex!`_5jo@AU-Kwu?A7cE)cTTw#K4AxbXwr*P??G*O1Cb0Zk z7u67K?XTwXoO%vX+gls2B}FSJdL=<+DY=WJBG+A_;(K zSnPzU==D@-1e9%0r3%SMiq6mdzY=5dw`92`{62o6%1ohRTU$!oNlt5&I(^)?GwY*PXW-MbzSG-$V-Gys`1OjBY;@8uOR%KsW8N1KLSU6!MjHvZ^N}VYJcuDYxDST> zw&G1G;ekc3Mgl8*!Yr;(3nMK&P_H&K-d?>I$NS;AwDhOc(nx6bcxmq?F1&XGUzr?r zKdOM2Cmk!1LvYZFRrq58@`Be(RPNVH6e?5lg4yg!WEzZh@Z zT@Fk^j#c7N3T3(~Oqqh7}&A0U8*-JfFVPc+lsPI9CrE*+>!%@^_klCh1m5D8l8 zotjO-e@r_lALOX*pTd6tN#rfBTlnPl90fm63i1|X5Bi|xwsa_!Kk|B5&Xlv@x9e>9 zAHwrQUIe5n2>k3{He~iyco?)e6{3Q8NR;ElYo^C-~=tXI| zc-Il)@p&$&WpsZXgAK?(zXX4&5cCS|R#74HNm-)f&)u$d(`hAfReHQaI-awm>#mcI z$OplAm|%gUmw$wzj+lLAo60ne@b4wQRK5|-Lv)|XZRjP z9d8B7Qopg{6#@9f!~>B3ITX&Iz3Nr*p@QWoRD2RMLw-4*J^pRlvVWIy_qwpac=q3T zG~Za%`@8q-aKL>l4<=Pu1}ksZH9DM%6r}7L7K(LyhXUU^>prfi))QbskRU z!zJqc2@mYIny)1856%wn3tnclnX{A3u%?ffzA%?3ogVQc;Kz5)y-JCGcI>my6mj^H z1MT~+#7J#TrF){$InUqx)QGW9x@wfXpgyN`lCc@%ip@q(TIpdhYxskGHiemD2K)C4 z1wc4@#d&q8H;Xk~#hnJU!M(1AMu>wMv658L1{d$Kp!(d9FV7EK&!zJGE$g{To~K*S z^X0kHdVWcs{noRnWVn2D3y|?mPJ3|%k{kuQicWd_vw3eSeeh(_sTpV5KGbHw*QjI4Ur!@p{AE& zhQ#gX1?nQsS3wYf$ek8V-og%bYT*pIU;2h8GF}#@*TBbx7VZ(syW4TV*fwILw(O+P z<^dM?w#!ku(Ux`b?l@tT_(rt+J1{v&fFV*MGjbsb_DH;{iuJe~-DXxFl&z;#c4;qc z@kBrNkeQBF?lvdFtoIUD1YWXVd!g4AJ>u$KPfdL6Hkb5hm0PsR9`sXAXfJd)qlcZ{ zQ9e>8YEC)Ph?A{)Yjl{!K zm(gG1Xge0#bS3@Cg?Wv(A8!Ac(Tc0jF@gsoUQr$Pu{*t^;bCQ%BrhZ_fX0e%$-Kfg zt^Ohgi9zF=aMQ`P@~615{iycGlP9D3GRDeQqxGsD@a9aT3*gcfpW$;rOtx z()*@s`aN_BdfOBIz!_OPW+-f6n?jSnD&TpzKt*iB3vf;(HY1{zAp(qi+!7%yHg@w| z)O~~saP+R;@K8jag5pNUX5gA5+F4*L>~qLjN|`dF2ajFCbo7uSuK!S+QYFW9AEJct zTm*gK{1)PbsyTkAjJh!QC=Bp~bRwoOn0k0`J+`;kV`Q_V$luuh1r17VMQiR0ne|V%s5c@ELnA zpXnRJc~kGaq54|12+QysEXN_**YAM8C!!erLG);r-aE`_tNB$!$;F%`#}n$1LOU5j zYVk?!#hvXR(1h*I2V~I32hkVz8aY05szdJ|LC1?UJpolgvWE`lj}G|eTrQ?aT{2V_ zIXZCLGnjeGiuR#wIU$9{=xstxZ0pz?s)v&#{RsmB;;zk#=KIy zGKC-O_T>o*UM68djecX#Ao?H+{M{x~PJI&UW$Wee-$=aNzUrF``=~*%qiEEKgg&1J zoq2mlL%K*di5y49ye>(WI<#dgX+h9LKWLlOF{2Rx=I!@yGddX}eT)Vr&e)*QG;9X;O+EJl4DYVu9aHkO!4N4 zi-{c59Wu-A#MK6)0R&3FlwpVqr~HW12VCbc=<@DE+J9}M>Ri}@9G~`IU5;i)CwX#> z4z!O16}OD&DHOkkIlL9ohC5Fz6LQJpq#t7D?}1NmC5J1o%iqKLC;-oC%RU4&BKBC8UvHenjaDeRT#J$8!-`QBfQR;+d9Bsg(u(!YjvUPnW(}113dJ*n zlVj84@5t+uj%drSl|95{(lr5R!RQ^F`z@dnt=lJ}a^ZIKh(Zl?VU^!hcrBH#y8(=AtkkUnaEjN83g!I7Alfeh_vYc) zk>3iVG{q3mRd2%-uqRh54{oz*Z>~fZa)UA%0ZtWC&=vIK!^sfDwr??Bd0fSh{Kq^! z#Gu4}_#p~T0akOXDko$x>0-+{AMRB&vP{dD%UU;Wk!68op_b?Q1RlwVZEqLk-LNzV zL_P{ZI?t=*`7-PI5AuA0_57ARXIjti$@57|F7A~>;HdTdnWXQxp38ZDWO^*L)gB&D zDN+|)vGYkf>&8d!dul(CgAggjbMo^C%amCnP`~8S>V8MsOZnV3-H-X>DPFAT27B;2 zgr{3p8R(Gn9cfmGzZgdj#5eFfl!|ZQ=+xH4qn~Cz{HY2<@ac$0&&)0CT_@VyeoJ7D ziCU!0m$#pI2iHnmf|RPZ(LT>8DU)D1nM5`)%6!%Toa$kjj}QmiPj=F3ypKPT5s^Eb zs9d4c#apUBTcdHO_QFnY=mX7Yuiq8gQWV-aJJdG}p@X*ifHr>bB%>>PYyEvmvpgAW zYY0)au(!6iR;tj&Cx{(Pa&}c>j&Y1obFbUgOCx;U6HQQm)a%oXruyd4=AuyZ&1KY% z6lSM3zO~Y5$=*{xJ83?h47OXf$5XZcRLWbnjrY#R@mGTBOe{#pMIh8q3%73P1aCn3 z9b>)~*;eodz+wk)$X3A{vaCoy8P?Yd^;Id|+oK@hk8^OWpC{X7iFj(?lF=xQ*|i~_ zVmnaVQ|rXK50njBt~#c!9jztM#uBLh!N6IrhA- zsTqD0QZ5Qp37gYp{@}FsLZ=g!Nm{iE;;HI5k~&M;X+8-z+n%YoRc@K~sM2R(JGx-J z+Kw905(hkJI}eIi17o?3z0p%6+mCd&w|~$etejEebDZLXt8n*O{9Bwurr{%m1u zmTqz+zF*s~c$({K`_nwlI*X_2g{Qfzwm;3&th0EU-alm}N^1LUMy5Z_$gHy%nO?=n z^rsn_brvJj`=@NU7;W_)V^3jJTSJ^!20;X9&dqr!nEhDnMN%=OA5%^}7ma zb030yVBK~_cFob&#gR8pINH6hdoQ%7Pu=JmD*E`KD@0|VOxz074QSW$Ng9#=$__$j@=SXBAm}TX7n@&dosZ|)_q9WljJaCSIzGm zW?sT+RCPd*$Rin#44Z-Od`>Lm8-#>lN@Q(t@sopBLE{)lqoR(q7kd<^7{>{(>xbgGyOpH>Yn?N^`tuwFPztw2V+f#EZ;zaLFMxOwP zjp8WWixfx*Kx)j}V#Ku<+8pw1j=7M+L~wAke!Y2Hh^5MKAV!ED>_3s$rs=DBFWjGZ zw6Hs`RncY6ye4hg)k38UJ2}%g2X6v%4yrS@c+*Sxe*O=s0Rcq(O?i-!_G64|4^VlP zGuW_A7$_V?cmfHph#+>owOV&FQEr4!#YyeO<9x-hxC9>X3acn%6_~K-FS2MxUtt^U zRx{BYHsrmp=`NZCKI`*NX!>d9i4eXr>M4|ihb!zf+Vf5UqFz8$CIITCG4cLEoTpC5 zXrASr$fw*l?Wn6YuvAzXXxK{(gFai%?@yZq`Y&G`g^)cFh2oqf>A^!%RcWU}S z@~m>Qb_9q<2X8sX(Zb#EJL};qT5F2UoXe4X3fIcSX)o+{jOICS1A|dgEJf{hf8ehW z1IpzDMilvu+vxG{$?K@ORpxLusY>CJ$zFv8WIDH1OHqfS;hu@6EOrFM=OEMLfndjg5l-T>-rxZHt zJ;qdm6F!CW29;@YDpT~S9LO{T7ISJ;ZY6Rr^I0{|BiO6VFY_T&mWu(meSS)B8y0{Q zX2cTfRcD3r{| z^?i~1W$_oW1e`3D+{ieOe##Nd#t{GfcqP3QWmiGgqIh_htfFx_X4wr$cy=g;-DBkV z%Fm&1wAJ4dLf_3v{-mfFK4@HT;$Ct@kT@#JRzru#ZpD~`^2v#Nm&t&g% zLg@!b8oTgDxM)03apBAAE^YNSA1e_m6#=RCuD za;0im{3gCNvjs)CCkLm;|HKFYKayE?f8RhoHLpewx>MP%iKCN>4;XRdb7+V-@rh>d zsqGbyXgJhEA3=>E{10RrEh{=sJhtOn-FdPz03#?W;07iv2oIf;fX^Ms)B9aD zm&3j7h_};$;*)jzf*;10lL1cfJyO14Klr)%!vXujk9v%R$WOG@i!ovwilyHX9>s)E ztp1MioH8SnbTK15$?v&lgz{~$8KIQJH5=S7wJ0ORBY(qwkYRj@{opZWKX`>>2YT&d zKlm*PsFE@uY;Hk-FgfyYA#0YB~_3ghv5W0a6LO1$rf_ zylGgVPk|P&YITxNfDC}^ej}=yvQ#Pa1ps!YtuGJtaI0S>@#VDDhyM}j0PV33(gBp%U_K^k*jlD-F)5>9D2{=eQ*gtUQW<8-`(Lxa{Brnh1%B@Y z#xMW}PQ;78u%GhA4F=~1|7Pql5w;Y54p4HT19KwfMVMJu5LlVWOLeU?F|s^lVB46O z#N}cRvaX`Q1;vf>TSGvH8yc5pBDX?R!S0r;n0}*QASv$EBICTXW=LSwD!2YtLE?#& zCE`Gzuvg4elQGVleB7zB+J=iq5))YU*hfZcoRJCM>0;HHtg)&h^fgY2z8d*aZseQZ z%7NOLkGli8vt}pnu`B8P6H$kBJD4smE4x+}fS>n)g08ZEE&gII5Ln6@Sn?MK&cT>| zV^{UnuO(SZ=8qiyT{S~POY$=_`ua(* z{@_Slk7XYf+*lOx`ihf80dr}q$D%bV{uaeC8U75jyR!Q%o6evXUjX6~cZyl!=e0|; zWK{<&pUNOpXZ7VmtcllU5NGuTQqYm{rkt7t@NqPQ>+wHr`J#9Mc!FSa&f}w;bNq;x zT(=p3N)Px7NE>7O#VF#rq+>QhA@Kvjtngk|K4$`6%aqgka?&J!#loHAF$z6*73p;FHE;zr%}{Hr&6H(xT}rwRxu4yhChSxGC>qBg0S=d%W`fM5+=HP3fd zJp(OIx4p`$OhJGQ$`3~D4S2jS$fv5cT6z``ZM)zWP2#X^~l;X_n*#uf^?`y3DBU|0)HvXSY*}X*7`+6_^pm z(Ys1Vn0GjWUGeAmyx47?FQ2f#=?wn25qtCFks{w}dD*di6aj6+A1=8-Tm7D~vvAK7 z*T!i(!@T0EtH{1r3;&XOaRciJefTs=@7n5jqaV1k+Y9$-^*bcr#geaty&e4T_**2r zQO%$DeA+Z(G73DW>VGEbRmt~-QQRz}kX>KfFQl#Z>}6^c-y`n;3Oi>!BCeP5NG3I& z|6n}lf90I<3{Q<`RHDed;>D}2!E6#xeaT>!xXp_tj~dA9P_Yjt=AP&2?@Zq6>Ceol zzR!r6bswB}CVA@zLxyKm-yyFfb9f!;X2aehuMZTTN$NcpR9{N~?}PofUWsm3;41l0 zc)xro#OWe0TPDlPuth@^21ryGvDajCy(tS`Z*gD+t#^14x9J^24W}3Q+q|JQ$)GqA&Kqcg}*Exw4tmBidgjSgrh*oq;st-@7V4&_M0q| z*k<)+;rYi9plic_%DO4%(=7YnND8H%|F?dp4XQs?r=(3`_Nr-r5&wS2KY4$J-+lZO z=WWgWj^a1PAABeT55LFCybxeC!cWkNwsilXM% zV;fT_t*WY6C!fJR_)l;N63Ttx!S&*!rwiR2q+)!MltJ?KOcAH6E0*k+^0m58$)iN7 zmV*>{4Q*K|RjRbtEFUT5a)0tp_u&EmC>yjj8_p65cMSMP`Fy}X%IAntRovith7;*| zKuOOR|M~BBk79|Hk&>ITAjLh(%(AR$aY2cZ?6i#C*t#-wNQ)kG8e8hO*^>2MPU|g7 zvc3oU%;>Zw>$?)S4JtN(U(P9ibLg*?ZwS$LN-|&bZ8W%Kc4k+lR^V`fh zmqnslApBZZH==hScVHE;PcYb#`#h0_@R=tNxQu}mD~c=;H`U5Nx+tOF$%>8K=Z+Lb z%ANl8+N9le;=Z_C3%|q%IjqHb$4%3dGoWD=;YqkVzUUkC-w=oxC4&O+A>W%6qYME9 zhT_7ZEHdd6-q5;^OzQzfdA~D3shcDZMW&rraG|3)oY1+EX&sRqa}3{$H=$zUOnv~f zI)+==A}uU-Xy%z2;18X0+M|3$+mTFVRyHuZv_JbayRFpUh5I}i7!sM({#3(Q`($~n-L5Q${Toh@Q8$H8Ntkmhl%K$=t<5@oL0REUhV(9#{W0k1{uEdCr9Eo zRw2}TZ1Kg3Vro{8!xE$Du>^y?^6Ux*dal?gY&(QUs!+F44P~I>S+UiBN(qgo@Lm=B zUHZLz3UZ;3TjUs8xrK3vYKG{)zQR9IiG7!Uf@wt{DchLa&R(JPYc7zhwIQZ+!xCyt zJYsAXP8?sWS4WQy(VGs|_8s8VSiDGE{j-&MmFVN&vG^&|xg+04=3Apj-Fj08tOAwR zEYVgkTX+R@^kykZkP~DwO|^YuGP`&o#TSl};{L@;D88@&Gci6O6A^WtT}tkYc$Z)! zS1)m1?aA)beu0hD`i7UFhvpxo2eH>)P7VE4(jK`p_WN`~i)4~M#D1Ah+pW^rX|ZML zw3rmUCH8nKVGufdTc#v3+55=w`L)-eHM$V`M(|47C2H#X1@l*Y>34N~9AZRVAFq@j zD?SUj{uQ4jYikA(lOms3gMy-c7aNT^zvMa=KP2@J;LVHs(pRO1!k$}e`Kh@=0dDpz z8{x;AUV#F7OWG7GGIV$)bIhwa&w&x@pA=$l2#!vN`$}81U#xfR=O?_tO2i4%pv2i$ zVwS$aX{YNOPfPyb^YO8KQmz~~eca`3q0ZI#YX{#Fh8@1IP`VmLre&y6m zsm|m>yt(jhQvHZo-Q(|E{9TDYi7fF4=jY>?Oe?s!h@XcW9sGxU3*)VYjTN>&08W9u zn%2DUU2XPmtpKsuyN9%U-_vI9MM|}sjQj8&_SC-Y^}(Tf)aCD7v<;sb&x)O}2!G5m znqybtW+3MFrSuDW3S)Xt)}kp0c?CRsEb#0J&?i8%2^;xeL>*g8cL#_HSP5<$NFbC* zr2>hSrZ=6Ie8E2^#Cx8zd%rsGu(ud}=hV{5G(5U@3Pc)l2j^%;dG1xfhm9#)R^iL; z{amP`g86CeqU~yRG&o0tAe#}CTT8`SA6{;BM5U<+&#L+Q84+aX$`Kq)8Nd|pQ-@r9 zF4eP~ON{A7#<&vW@zRas%4jfSqcoebah$BD40LSfZ5-!zIO69+_^Qb)Zd6)0#V2iL zIUM;DHva4JGjLo3iwk@}!~+NLY%7ccQ`36`X0C~vZ>#LM;UPE6kw{cIBT94fs<#J= zCMxAd(LX%FJ-SvQv5xmU`s|X`&55rLuD(12_ndYYXr(8W?Kf;7r|O{^W^tp{>62DB zuZ_=>ZYubjGrw;4Pe8`)fYI(hUNgz=;BC^u1=7Kp7iW~tyftI-w%`>L*9uU$Yx`WT z-YbsM!()!UiFHQPyg8bc~jfb!dck5loRYg4k}3(x&SFC~XRUZG!L;8U9no zUX;+aidGa9+8r@zD&0u%pAr`n+_`w4>h(Z!*n;4v_7Y=fmYUA%{kyA6;=hr;Uzak* zVSRzW%!*qb$lJTc%em3--(zgV^-!t|o$oRB()puwo-59u&{ZQw=XV!&Fe$ncEI|a) z{fp>+R%z4XKTszl_-ds!f_D%ORmNllxGl!7Q@7Pd@YjipWqnVgZPi~pxlX1VxG$*UzTiG^85k6ind%g@n!3$-OYWD4wkhq)3r^-^z!dKer;l-aS zNz?@G#n08l;9!l%K$^g-+rJlhS%69}D5;uVEs+o8#=pdPK<@d9j0Z}L$4ZS^WgCYG z(&tjxnCLd9%I&l>0);ax$3SudvqE{-#)%fs`#`=i%V$h2NZoZb%;y*~ni3Z`Oy=R< z*hep>s9Jf4nktQLPbb|+(yUn1S?~A6{+xQpUgv16f;W*+#YPk5o`*KlimbFfv9GBI zMGyT?^y%_JyFux1H#I_)exTLATfZ~(Hp+aKuHbu0o3DLRxUqhgqD^=GP1yu$o=YCeqa`&*%sm}sqxwZ*T4n-G+dW)*>jc?+MooP=h)2D$S z5PeCjdzOUIp@X5`=L6r1KhH~elV&_8iM=bUFH>=02)m{|TPI2Dwa}@|#ZQJeJ@JG& zIaB&%kSvWJY7F&;tlG@US^juU&7hvH7xs7wr6$l!&26e^&5S`Aek&QK*1sRxFfw#z z_~PMY%?&ZB^$B*5 z@NAbAZ(oN{95_TKG zJ2Uj2xz*PYf6pxWnd$9{Cftv<&n;+OD@OxVV#;;$Jm{TK5FFWSNAaO-SdB}xMROd9 z3sX7Pew7a@o2?NkG1(NyHLD7ZUXgsps{TzjZRrEw9K`Wh^rYCV;an5;F*rF?LFUf6B14^|dj(vEXJ;+)?qsG!&qVu-}!yHwVotSOEvsss8Z zeE=@CIHr_J5jo{>^s3wo;C#w_vtu0?S^`ATRjYeJ00Msj=)`912jj&}-q9UVAo3$GyM9^u~bJ+SgNWl0OE_C%_!n&%Ri3;@UOpBOm^GA)guSc89` z{$^@*)SX1T8PMiyt1z@7$gHb9INaa8=>E{s8#C5DHDlJjRTk@xEc;q+ed~V4`sMqb z>bv$6U6%8$cC{0!w>iU+c!?0MnIgRQDei$d2GDNEQ+}gxYTW3P07MVtumd(1Bum2V zS+V<5@3JuEZch1au*s3y-Vim^oL}$uDXJ%~l$=GlB0`rd5Rpi%5yCNV3WYW|*5~-@ zr}!KyvTfoKTLLo%@d_9?wD};Pi3Le~XG)Qucy60R^)rchGsTzLzy``l+!Q@}VQ6!Q z%BYH^vV2*&Ov+_7$Ow%OrlXu(&IOMCmizue%NhIFTxL+D0N%B)vK}E^21S!G4iY>D z2?BpP?D(7GtBS>y_b0Dai%dVqnOprUib*U(niy!I>i?zgUErgtuEqbEWPkw%&jbdI z8YSweNsTsBq6Li-NJxSr1i^rc=>mX{9g&s0e{cAScHtwp#7;)?00DOK*Mj@<@H; zfeGM?M+KCsfLhNuDgl-7kj($P_Bm%V;o)un_xJex;FCG~?6aS1ueJ7Cd#}AV2?W)A zhRXt#4Y&U{Aa;t?ofL@S@0=dVqCvKT*S~cC&YzWQs}tP6Q&N482S*jpyTciE(>!gZ zz1$pHv6lpm-um|X%3cRtp2!bE8)~*R?#RQ|A#o*pkR_iO6-};AKuWtMOCz7?Ngmn$ zA{-V&8H>m2t+8M6O~^R;&*JC6->cxyjyN3`kQZpB+%zh09m?Zb`$G|b5pDz zwAwpZ6%avO+^St6VWtj5jn5hi{g^#7N!Iu0-awWNxOTA_Nkw8==ZP`Nl=cmyc4>ACHjBGmlgs>X>sS`#^rJW;>IvT)?b8?;a78 z{e20uRB+fTV*ZOPhQ~AX!=Z$ed2Xv1BeqJL8;Uz$mIY0*)X2e7!(7AxDNj&rH8|Oo zm5`lSWv{V-R8D)NN2W%+dR8!Y8g(J?THO$mHe6}jgK#Ie#(Vv_SZpB))qHr*HtXAPmW675OuZPCkg@q= zFQ2tl>U!<;!eH*9d;S`Gi*h;ou&a-Z5yK`nqOE;jmF{J@wAxZQMrM|`5w!v!N7 zuC$Fr4u>yI>DhZ$yy}_A5hv~0%VMD~IE%9&dIo>+LNKnEMUDWWj?$7l%p0% z8iWdvW?=+w?@Ogkd(E zCB`R6ChYBo`DVo|nT`bm^ONeSvO|ggCw#)I-p`jW(e>%{&ATQ7DB?dtq|FBG_LW5^ zvPDURN8m?a05=9kl^vTZv)?f#iichA8nI1L1}MPByJWYjY=b90AoW#NpRLBk#LsCe zITl$)HP$VRj-{TuKM_kk5HiJ5?{gX;7iWv{zFa`=$$iEBF3X{{hnXZ9CuPAnx1TV` z>cae&7t2bD@48CU*e2W;={9sgVsiJZqt27KdE&YW&b=HmD$3BTNQudOgALEa_LK1_ zkH?vA^4Q{$T_(Yip0}IEFR|7qEK{0>N94_%*JwuyComVNNXw!oYo&adv0@?66$(F{ zk(R%o*-z*Ff5kK71Z7Ix*D$HCso%}>VhQs%g1@`@dy2n_{H^0p=BuRqAHB!x4)>1U z<9A0!8p6kEynQ?1fI5%0PZ9emae9lozi;kENcBNc1$>SsP!e=wxdjSFj0sunu3@Nq zonZV8tyik8*>Ckw3|fMs7m&GIEhq`5tr4t@7j&xyEj`tO<8q~87m=>^#q>QD=8M*e z;BEmo>CYzmX%&aVjr)DjzaK%*moFS7pMN|(@&t{Q1CiQ<@k2jH2|$HHSjVvNMB`?B z8?VL0Q0B)1xiRK|GoKCL7ak^-^iKhIIc`?-Gy%L!Z0Y>Mldo@Yl*3hZB?a6lSK7G; ze=_m(+C*eyd>(F`<}`SIKD>R-ow$LjXqb?AhJA{c^Qj}1fY^EVYRhL*rnYJ-*EFwc zs(Zhyz52*-Wueoi6~A9cGzZ~u$%W5d5B`{5=Q$WMDZm*;w8@Px2s$Ebjse^<;9dkO z8Ma3H5Lu!6KP@V&L$wrUgViASi&>ty;!~H$UBwg5tpwJ zV3brR)k=NDs=9iXW$yyZs<0}HN3slw!>SkixJt9%-<5dgoF89XL7isgX(7|KRfHP_ z7Bl;r10PoDh+RM|5pE}fy=h5fu2>7lodV#%zzldF|#yL-5A7 zF=KydeQ0C%NoZ~9{WR>a^j?`@IrL4ZJjpZhtT}uQzTLULgQCCTOgu-t?PKxcs{*+7 zI1-OJUsf+pL}&GBxasRTzhVcGL(z+U@u8~nfBJxQR-b6A9FQ(g9+1xRUK0m&)@^I7 z1*#OGEwu;iCBdw|0=f6P7X(NASRiLjiZ)7%eWj0SSX`rI8f95C2UKl_91`>GlM=|A zFkBC$>4k~*vaA_)H?Aj5)h>Q2W_rwnd!<+({v~?3>PZ|9)igchj$CMXf~cUPUl(N= zMZQR1G|2bh2=P8M-Br5?Oh{}ZpOnu7GaA|?l7Ld8ZeR$##z3w?Pxn3g%rZGdB06ZV zs@J4>NxK(`^Hp^m7w4_|`nb5hRh~%rhZ4?%cF5c z3d-6`+|H|ef}L+`W7j)Z=lzaM>Z`gsubUmPzo_g(Q|`|@&OUTUw|(fl-S(mHrrw{& z@%pI+>CXLm^YAh1mF?nquXjW6+A^2eEvuFvnAqwAgtUE{0sLB7AD;f zB;iwt{{j1g!JhE3(grN^RPjZS+lAA(Plj|8+O~&I0v_=XE(C`mq9QsZ)4o-M1uI27 z6@@~_RN@~(60-fTNUmYAr(tT)+jus~^nF!NgRc{3_BWS)s;EwqVfdZP$EpH;CNh)V zVSV}^6C?~)wbu{2XVd1OF|2w7TGLX1onq)tSjD$q`d>U&eC5c_nr^mmAdo)UmTq5zZDaE?P^KL-s6)}mab4g1T zdR9E|c~3lNNy|*aNRt_o+AU^@lHg7vtM{o)A`9uS3ikx?Q~*Q;4J>`;4T{Us*&{(j&LI1zmKiK^Fkl6cHGcrpU7MdfD0bDZ( z;7wQUrO|!ax{8VVRNdu%NlI8NF)xoMq&?Q8F0;`dZ_&!%(8{~KE!ACV+NeX?s{L## z&MSgWs*pVcpj-JwGy6{p)yNV6X=|y99%pK+Ii?*wI8a-v3oM!~M>|h06IqIuWR{(z zX))POSItnn^zqYFQ>;Ep<5Vo&lrl?~rka+{TUcYGEZaC#5`!4~4VyP9%s zAB@B<)Gg17=D)FAla#{$Cg;KT{z6INpGx=x6&vW=o z>T^pzt%ju-LZ2l{K)8k4#i`_bEC!{J=O)OL&U2&QmIex}W|v`;MV_0Zd;VMUEc`L# z8MevOXOXA8%T^aftv(R>){-`%#!x~mT2kmVo&$LXm$WJJOjPf8#|OAKENN4Ox!-Nw zmn>t%-5esWa$c17kEJ)|z`ZAVa@><1;0ueb0h=@#4$)67f>boR6X3Ug@m9^U+q{rh$Mv}qL7w~7vkImaT=pBOVeuZrIjbcnvx{e zs4c))f)SFmCm`pw(%H}fRYPn$>8cZI;i&E?-SR8KUL&n)6xxxY)E;Y(B5`PsH*4i> zTKP8bq3Wa1_9kuBK4@E8_E*Z2^`bRj0{*q&mdNeE$uonE?3X*W^7Y!E_o3TF+Xmys z1zgdV>r`vtrXGO*mEl9U=-k0b5)vk%joN`&yKrJ<1xE86SlrA(spz_Z%`R3;b#zU! z3*f~{!VC<~9%>?9cFw=^4PfG^l1*F|n8c`Ez?8~b;^(WLE3RQdzIGW)wUX=v+(SV# zwt{j5M%LJ+Fr7_y2_=*ee?f>)n9RgVvjHlLuJd-c|G^@lccrWpY0-HUCnLU)Cv0aS zZ0CN0itTJ!6w%u#WMS?$a5Pg}W^t~-LLmO%u%F>w}zgjZacf^1Kr!LjpK#ELK%u-3?`@o9OC2n z$!+0gQ8=8#+E@&<2TZFOV~s+-%~-{#MsZDeBWUWBrb?G0K_R)6d=~AR4d7={Y?y{E zfbvSrY2;0^z_Cm$=BJMd3uM+23^gyQRt!-w$1Up1TE!gOtT4H6=TEleALVZXO)2EB z8MN-?PXrl8$j~peyZgyi$R*+>VKK|Tn5Z>>#67(SdV4Y6YvqHt zz7(^PV4ui9etXAn$2?2czGL(GF-kL8#zt0UevtIAeBFbY8zp5qh6}jRA|*C@NI{{d z-1h-=w$L=sAni@P85v2ow_6)^Ftk&e@iCC}iv^*x5G9f08azeB;dEe0Jj2n)jUunR zb@;|`6=zJExpZO}8!lHw6Yj`AwABmJEYGxaFIBR`47oLA3%}D9zefy{oRPM8Ubl*| zg3~oB_L=yp+Uj<-9H3mbJE&`#K9_)%e-`jJo~elDY&4W#6t zF5kWNlY)KlzEW42A0MS3Dcc<1ytlZ!!fRNYJO2J=F4HJg_d0QXGmBoP%z)OKwSz4J z{%KidYV?xEVCawdJAhgF)t}>~AkOa69GR1vVsgRQibV`cC4VxE@=O(YE&a@AjPl?c z>5~A(C;YYL@L1L9ZJc&)1$eY^gvNVvx<19gIt2Ma`;5CX??ya66 zptz{vdnkISw-yai04ZwaR;tj3*xnv(SYh1li5?v}=i(&(pam3FO;6DR*c{Mm+okwd znxaRG=D!>FioM>=K+eMX#v=K6v?#1qzbF~m1Ntp7`X|?^a*}2{_}3y&Y$4yY)sxef z95#_==jJLFHv=_$&bRrUZrQz@qhjqYER_?!@mXAPZ!H+8$qeUwTokoJTW#L?+3WPa z`LjU{Q!jQkWc@sMhfj>Z5?AXc_tgM?U_1dX>6s9F3|{q&n~PAq7_4ha`>T`?&*H20e?7b(2uHTDqza%PyYMv&8-6s2%mwgZ`SGb<;J`We$F8SvX@o8J9M_0gItf&@%BC_NaJnKbQBm|q3a}+2bplK# zYNr>mR~RH3W9d`bOKFSfQ|}ThGs_1&ZGGxPf+_lxF!^qMDqxpM$yxTaueKQ^I#cOW zIZW|+wm#*zB@=X3OERD}V5$-(GT{?Alw(};Br_++y7j3*iaymd3xf(YYNt!JR=i;iH)sk*{ z&FVp~XZ6JpQqk&EXmtvtsQf(l5;Bb!LY3lInMuA$-zO9fWxgFbqnD6iXeWxIqD_&I zJp%c7ruO7}Zuib!LWDw>>I>bJ^^LJK<9Lchv0{3cwWo#B%z7Kv3q{vr+smd)VB+WR zHpRK?*q!F@4v1A-byyqqX3d81{pbSqH$$5nxPMQp6}1)W1D|s_p&P&~KNvkFp z&TrY3$F3%6^${*uWUpSxS&{o+Z4$Q>tyds!NZk8+_5EHb{5?hCUjZ49woGO`hJ39k zTWa#qUOuSf?X`Tf_UFURdp*&1@#+r-Y0JM)i;e4jFS)7#{pQZMIcG}ZE61Zya8qFB3SnpJ-go*{~spLH3T$Ke|R;TxG~Ycn{L^pGrn7zIIA2k$%?Y{Zb^ zeM?pk*bGL&BVHyjNGeBwxb~N#7G>AkgOL2hNZ5l=d!Jp9&1fPO zMfnP7%ap8nzpr7e(!VkVCukJE**3dU9_|&YC|;E3XkYmf$9C)RuDN%je_bQ{;f{uN zB8=;NkDfU=2NBo>v7qD>bZ~CA(y-28c)FFWVe+{E)nO}uC7; zJtyPwi53YaS)rAhrqz3@9nlll+=81APusXFz= z;)DxTc*cs$DE@5z9spT?!=EDr!3$0*|7=p`nqEu(8PusJx?|;^|KWb{cYAoY{-^hY z=fU@nKTEwyX^l?Ltfy=@be}(1?Yh$02Ig2d8`F0-sf}QB(48G8+X(LJ-UvS2V;@%( zamMq4#`74tcwwV#o6TT5Q}%&X>1lU1shwamNf_r3^eCJyktkVsiz}4|Vu>O?& z%s_&BO4UAE17{zOJKpfac`_pG1E-D&gsRTR_o~_;GJkTP(1D5&GOQ_i2;97j)w~p$ zSo9+WeB0dI z1&2fGt}r_Zf!a~ocgakrv96(`lqMVAN^Du&F1N^i=oQ~YGh{4(YMDhGCx0xeK0Hg(h-xe`7S@I z%kL22w1e_8DH9?G=?}~L6C@X1=ViWeN2aS&-@s)tiXZbruW%osKF)1d57#0y3)AMb zV72F`6t6MblZdzy7!!F2Mi+Qo;YW;XUC{;JzAz=9wp7$z^H!;o*TfIMj?E-O+5aKd zGald8cjT_OZc1>!!6pAs{cDO*;CYJ>eZ5^D)?VZ}Q_5;> zFY-#jd^(xv87ondo=GC_{t{PPkvBtI?Srt&`_^-6qOQC@ZN{6cFIYb*m^MSd)?Igf zx<1;YT;}NSn15$WAHFAeX`KZzZdVafQKPU_^IjF<;D3tzm+xh4?)Qldh;{I-$Px{s z{Kgy>JQ`jI<}tN1M%fU!7k2D}i}MI@Kb%(kd-x}|MQI3*A}r`zxh6r<%fFeP$rY7} z3E9zgerC1obglMA5f7{c#x))a$uiQvF+;8tf7r0vV5F0&NAl~ADPJU85LDdydOEic z@6u}J@H9)nei2UmbW8DgySR~_O0{+pqH}o@5*5-=zGrh-POBX)HFJ+gl?XO7U4Ws0 zz-05@e(EF;3theZE$YPXrMFtoD`#8Ji>rCAaedv>9I^z4sNKDuzfJt%uHf!nGqgGT zhVZkcH$Puw@$==G{Op#v59H@Ves&JXR>kf-tHOG6CU@^ftC%_a&nDF#Ni{fMecij6 z2q|+6%_d%lRS{ za;`bKpe5&-&lr{8+H4|C9~oNmLiU)*XPujdBRH^&B>A*jx#A9HEUJMA3KAsKXZzyW z*7-*nJH7_xt9W$rs)1ZDI05E@&3p`SroFU7Zl=?g&Zo31?)PcS?~!8hinP(apOa&} zAhs%unM*kRW-c9~NN+<)e}84gb><>g5A=6fWO2_GhmP4su`jnHH_Q}K?9-1RtXb%# z)&3n6h|75ePD0tOsS#!syHuKlC~yOA zfRMDlNUD`e&z7NTr&TPtSNceU+!1E8dS$)f> z5FmQZ0m()VR%M0fsh$jRdLjYSJm7S>gAh!9!ZE#gK(RyBkq3g8fW@(Ig94m`K5XVa zDC`+^39obcO7t*KS5Y`f6Z|vJRFNqRz3~>s&}HZ>hW>jiLV#*TJZ?ou+pLJ?DnhY* zYrR*_i0Aj1&-2uLem3og9eMYf2xWrgXnOrQgAn{xVa#@<(qRKczq1J*9I$^XpBmo&rcDo#w1Bi=;_G`oj7Ln^pqK0 zcIKGT`#o^XjJ}qoX{PvY1bA9SSTnl4p3iUuT{>QF)CpD=Ik*)Kf5m-PcA*P+Pu~5GN6`8%olBm7IfJ$|@b4 zk22gHS4t^*u{ZKN5W+)iXOS3g=P67_Lc`g(pb1=cl&3unL~+Ia2DUmF8|dX8S#uZM zvAtF{o7skR%t8Efm7IcGfW9gk_8rt?rmu(e(qsK9hq-`@No8!)gkeg9wj2G7>%?3t zv*9nnEGQ3oBXg!_;)Ke?b(u2N*Qi+hQ`f#g`;5t6qmMD()42sXN79LGaZI{LB;76E zB}d#cJw#8Xs)jNVhP;lLfEr$5R?=Vk#)NvlEhAiP%Ltd+GQyQ7kP%jpejR_W@%K0W zWXkPecAm3Y3 zM?QGKlL^Rs$_I!CSrrY|WL{xjhI4G7RJ#+gAWO~V%u5Ihc2HL3!dJ@7tpo}E?Ns?- z=g^v8$dHbSeA2loe!B61k}*i^(Gf(`;`7_w>G3%@Ww6Qv3H*j;O!hETenA0R64cu& zY(xMr3e&N@#NF(U#4eGbjcK?j7erQ`8lLdpieKWU z@ZbvbKnLJFm^NofbeKDGMzqNjKXG zMxY?;*@g8*?3_iiyM;Hk-)CO&!!9{XRH&_z@8P`??nrner7(y>^WAlPm99mue3_w> zB`cpiW5UU)hNOKXeO1!^WzZRQNoI-3F?UIfWDaw8y*oS$NLX%Ik-m)k{O!f6-R;GG z%A$Apr@Sv<6lb;mKQ~LcSR3*BDaf-82z}nv_ZDRc&a_2Xu|WdyoaZ# zb~OIm*NOPGp$%$JS;4@mPSs=AD!_b%Ow{3%f(W`|M<_-j1mm32rBW^+UIW`;Lz89J zX6Z|R`VzScjP%E6(j;XCLOZmY^M$=I=b1xkMr9_n?4`}64QvM#L zLbWaSx#*q@v4XQ`(fPm{3M*~FV0jS zi&P#Xzg^zc1uY}UTeBgOAH5H!BH!W)2IHFS_F{EmIc-F~;OZ(tf`e(0O19+EYR8dB z!IyKZd^6AXSOfNF=l~dNHTlE}oMUo+*nFtN;(D8?9IjWf53bj0j)^;5Zvr79)KO&b z$@QiKi+^bZE_wJwO-h{=o+qHLtEINwjf5Ut#Bhc-SoPAX zTOEdYtNG?Am+N`C4J%vd(R}7UicoU6cxv@=KsS2O6FK8VD91Umv*H(@=u2XJMa|Ce zKt7FiDjI9fpd!UB6{gly9%WGpk0Lp=WrQZU*R{J`U z7Wl{cV_SG>FD{gX78cbsO3T?z;CRsfuW9H3wkX3v@3ZXjcWBRy^F>4PDPD|)%h#SEV0gg-)>r|!CGworE%MA*VP5l%^?&x)F7~QpH?RsM5brJ| z!yNdH8UI2?_#hY$Yrjx7xek0@;%c16t7$$h0wsf1!Or3&5o1Z|RTthu_TY+$GJeU) zbJCY1P-Ky;NMFc%(K8wN7Q}d@(Q`Q;YtMhH&+& z06EOduV-wOydhOsi_8~{mlnzYlzDf(%)34(HO=&{{TijZakvz9MnpG{Yk64Lj6V~@n zHZPs5cI$ey?{P^t%gIL1Cjn0JJt7b}88~xJ3eJN9XW$)MDWlabiyag&^m3|6fo3*v zH9wtbHyc~NQ|QdIkU|DS_yhh#WpMO`jwPS&;tW@BOg8p))P@e!23Bp1 z`5vRx+fa#wtksG%&oFyaw1+hxQrC&JhdWH+ML)GZqdkQk&4z|YOAjfacq;#kyypwi5yB7rC{Zti@#TUn6UyMG`8`mJmPwVp%CG zlG2NjZ!?t7t@PMiqJB~-(PEB0%t4(tYU zK&owIULURIQ7Pzc^K1|@rW5Y&N)<_GpQI~(rz-mV%m~G?dH2pOp5>su7*HA^||3p5GfDP^rzEnGH#M9Np6KK*O{mX6~JL z(hX`ou1zv8pHkn_$AAR>_X{EUo4-3;ZL+CZn7>$0TWMBxGgL*2pAn zjZD&(J9ZDcQFM{$dzZjmjM8p>54lgP=`BE;mS-$N-zzPUW%~idh&y9kQ{c9_5`C|a zq$v$H1Qv50wdVKu>lga-wA`9t6MzE;{5Z<+=k=*h^r>4I9B(Z2=g7xr_$ccJw6?@A zjf9`nPxXJhZfX#YQ{ul^s1BC1z)R_BK|wf9C?N~(!VP9CE~D~QNm9SfYX%yn0oHbG zWwKI~$@c~_v3o51SPgU$cn5r-roP_qI#b^%gk&>?+&QmmpJE_gm9I8MPGzV2L4O>a6GFkfIOcFMu1-33J z`?CBOH-lPb_jZ;#*izq5wKIMHo04QpJS?#mdNHA7W@ZL+Mr z(-PQcDbIKfv%kjVS{t=3de|L4RpzYP5khh@kumwi_8vmI$NJd5f*+rN`f=DS9(1;Wuc- zVqBQiipzOHY@ydSVbpwV^;Vo_{9P2jooL0_x!PLsHI`N!5Uu$BX`&VPS6Xqv9RD3! zogguYVkaJ-lDI-8*6hURl32^Jcnc`SoDE({gzyu25rG1+knR=15ymS9F-)Wq-sC`1 zneYv3N^cXX#O9cYE)JtqWn`2~L7X^~SokGn3jZwUhuG}cNVp|O8$Kt6hIdj z_PJCpNm3Mbo&=z%9G*f^-)96Yin@t`b#(E7Ad{?82h7VuLP!#1zWwD=dnRE{WOfb0 zi2^dU(0-cFM9ZW(TQ$s*H5aI4Ogq4%3Nn2h*zoc|uv!J^fK1De*wZrc!djGWkIUGa z6_|um>~tEV)keiW9F}ALK3@$qvvAG5#8E>{@DZ{l;TNVzCC=3Zh1tkkwn|lFzX|9# z87UtufX*UVE;Ci~G@CgH7zzg4D+Pb!m67zAuWom6d@CVIkz6Tg?}6#Elt~ z``9Z5rCBg_0FT%5Y{kvD0dp=UKGh7^OMTrd1u~DLw}Hc%aq0%p^<}bBaCWMK;WB?d zMd=sZ`Qs{ud;j9;kV1@J6!}Jd!;~GNAsQ~?c(XTRoe=%MpWQQ_DaDNXQjYLtDY(a}Xsuc)m}w&I%ixayX`nbhB)5 z&Th0<3S>(tERiQ%G1yw{0Iz%fMXeY#Iv-XH1oRt`Uh+IH*E{^F^#WypEM#nCnEc{= z6rC#F^Qd<-2M=~($SQ37vOn^jc*Cuz>U;(<_C7zx4?WMg)kLwZ6wxuDA7sO8oc~J7 zsn%-tg7aLDUGp(d+}%!9_LZeR1E(EY&GV$u$N8!k@b&+qFsn2IALhrq+ma7^_UQ-k0vVHOtSk`%Oov4Xf_m} zj$nJShU_PK#!7Uygy4(>{rYHOOru?hqllN+52(9Vt8P8Sk@2||F;U7>*+G%Z80UT7 zi>L2LnsQnthn@8N7!xu+98dJUOtzesHS(RN6`J>64BRXzgf}N4@Ch|(t85S)ke7cF z1lp>T!C=YHkA;Ewiu_lApjy7XRP0I)s!{G9-SA*Ww)PU1uHyY|B*_4!x{*X(Ii;3Q zHqmqVcA}2ZChc(l%hD66LNp6c@Z3~jAOCyn7hA4i3~F+8$LykvBA5?Jjya*S$r4G z%+?RekW|y9hm%F)RF}>UKNxu__8kINYa^vSTRH~8#Qu`k^UM3poc5Q2J-@s{p6<@J zuB{o#Vq`A$S3N_>JhjLn-lpV-PvyhW5%vexdt3{l44~v1%F{Lvcx|o8a$(~DVzI;W znt%G8;zr#T?U?U-9m>6 z_{uc9{DDx0$IQ=>&U&Y{)^1qvT@^@Kfq8&_nx9|gz$srAna`l~s-P?~zm@#Z&HX-= z4=*?$piL|jluxcAp2B_vhRQ!tW=CQS63|lOu&o&5Gyk!hxqSD>mW1*i(T1zOQY|Mm z$#TLLt@a~H%K;>&mO%BQB3IwTWuD!u{g|CCb^3 z@|oK%pdPjF`~(!C_B$R2{4#LNR={B zYgmIfM?#-c1^T((geMErvbp{``}%OfZc=|WtlUXOeW zZ3u0Vc>?C*Lj^K^;IsFf+DrYC+E|pyW+5bo3Ld_YRRI~fTWJN&3Yo8cWVIfPZq=+I zZKYl}#zf-^+Dp-hC6nbEv(4>hapFxw0O&VG|CUqY3#EelUB=Cx_R-Q9S35Ef|Imu2 z=>Gsmb#BjWde+V6;&@+pU`Ij=pN0GyjF&q8fi1#3e}as(7Wn{20*B}%Dp=6C!YKB% z7hA-E(B7?SbP}fE(0aikH!JcAha6rf z&mQ3P z=LkLjKXGUefn072GjZ31^mhky%Az&)igGiT}QC5ni+1R}+ zL^@9)(pg4j5|OZ<_z^|7adC+lu{MQYH8gz|$W%qQWl^h|uf|2jea8&?XW?njyLC+d zWj@sNz$dWjW?vY!D=Qgeb3#r*#vj4a>(~E4W#$lv{wB4z%ESE?#QE z+nC6`lzTVK(5CyaY>Z<%x!9NXoLgT{s_?lD<(l3yGTNePqu$_{YVjMd+5?8oe z6yKf{oSv~=dvfal?a7t_WS%0x3LPfL)S*n9?he!ehA`tzZRHz&?aB3i;liOVzWavq z#SP}@%^98Allum1D?9q@?}ZKyWv+HJSF;sCj%^v*%B>p5h-k-9B&(s)0_x!1A3Cz6 zGeN)H@WYIEq&@n6ZRLA|a7{5lKSFAs{wC=??pM(=yxNoPer;v5KlDB|c-^!>KgcSM zhgMPdo7gW8rCeI&b8pR{CfY>Z`?b*9l;L$l`uZERiS*kBXe&1l(p#jZQVYHCW*pI; zJWTlq{gPULKePiJ6`$xnH+l5!8LisNmj1M1Ft#PchSaeXsnPuftq|By+Z$XEW=SfP z>!*xXcQbAA;k1G}J4C?nhF(=|r2qP%jBVP=?d07ox5D{DouSRzlZOVo-^pmxR_@S3 z>nSZS)WO9Rn{cWKtc?t&e~TZzf6jK0$}_xS>Q(+|8%}(-H*ropjD_$EoZW14x1Y1U zx^TEl({&)MZ=&YFc`{mG28SSxSy91ftLH?^OtRT?9iara#WvFaN~Ru}qF ziGN91@lT{;j-@q>>NqdG&6AO6EAjeetp*b}uQZ0!URGnsA89huqX)fnv?9H&`E!`j zSM-HDeJ?8Zb9N|paWCi#RjB$q%59RIHz%G&8^X zgS3Y7jE0g-f9K9~T4i?1ebxOcw?dFY4oUr*XEd=-i#|r6q0CP)esh1T;`z#)_#k1K z{Gxov{cTHhx0buH^KHGvtL&*777p@9TZCo{ptt z$dMxhM-9RFFz&M_+|3?mtQfvYi%t=iNr}-|H3dpJGq`Ol{2`^03(lGYny}O*wR4o& zsIjV;6ddNT)Bn}1bk&9Qs03EJFgS}A&j!J61v4i#?^0Xo{l(J&V-RX5QI#Uk3ioCi zH+8-8bQsK5#a^D=C^t2T%Px;%6jMWQ;Ga>HI1qY@yN$ki^)`48{6>4S3r-=tQTU+V znbEARY_m8GMTFikti@)B&GR6+igPk=x?~! zXB?){Fx^A_$>oDtwuLtHUD&=bGO-8=WVC22TQwMFhUAyrA@R8A4{hhJSJo0Us8d_{ zK5dyA3=9Cs-jMV}(stNvmA2ZGj^x`$ZVxQA+1;X8D$|WjI{?%#bqiCa6+--!<8IYk zGP+>t!0DhS3@`LfsDoO396uzrz72-{WE)JmWf1AJLhmpD9`~ENJ=L_TsfI7!(2-Cx z@EYvy%-E!+lMQM_vqLRvn#|{HI_0gA^a8)G=q^9P3$1(?6bEmH$C8hkdJJaD@sp z+(hIdv-WdVk32YPPYVwbd;NT5elcW{)vw4HWb8*+(1|LiX{+7Xg?$J9{=Enc2Q1x?Lcja!^KgUA?;7J{Zzm>SxPM ztC88{%0xP4JrrkpUPG4Z<)!{)s%(m@-OQJ`ChNcE_LJtQEpt6_W* z!(IX@DM*T3P@cJbiZ_Zk-ROrT;07i3q%A9kuxw_Rm@npiorvzO7J3s0w*b|{IV#wO z`I~FinAhG+@yVr2tu`#Fpg~!_thkCDOQt&GdX_3q!PEr(#5@z`M?||!@zhCK0n&Rz z37Anp`H---ancKFcflR#wcJGIN4N|~59k${!a1V<=q)lqv| z6F&m;ZdhxzzmN|GKdSo&zQqx)l*<4A^~Ks__@V4E%)Kl26z~z&`m;L}oM3*etNzjg zn(U}+wYz!2Xfv1H45knnGuc#&MHzRCD=rbTy^_D`@Qv`!$hF3^LcR>~5_t;N$p|ts zB|Uk1iB!Dr3Tt_Dh{DuXE!m978Lgz(8BF- z9o52cVeBI+cD|j*w~P8a-?G)6*Uq;-eAALWtNl;1HS`)ibhO}GiR`uu-UN9UR1y2b zO!x#6o*;c2LXped_gzY+Yn2ntVZej+{Bl?L6!T}R>;>7!2!xt!`KHD1I(C!k+4IS? zP7eMZv&r;$@>>q6OXS?qieHcm%UHUI=;Ss3zH1!!`G`4s?+%4%F5@M@X$mzl}oJvxb?tU#F+{q6Nifef}N3H_Uu*)d-Gv&)<&kGN~ zJfL@Ia0(-4txm4HN>$#(r^X_F%;(RR2zBJ(8EF8+@2YB&dVU&o;L_cFwcAvk{LsDI zG`5HwcbwpZ+J+jJ{BX=R)TPdcH>oy6e?~E`7kIJ70hOBgTh8D4tUjv!s62+b(7jQ| zt)rL)2}{@`C_#FDm5c*Q_+93EmjVtLkj|YzZL*1$t?vQ*Jts{3EQ!V6LJ@SI-QcMn z;0JOQ6A=W=&;Lu|6D|PSz^HQOJ>_d^Gy%{oQ_yTEVI?!<6Brlm>Nnq8zfADg@*bPV zCa&x{TI=&!&X!|zV;ale5pQ&zT%K`rD?7ZRcCr&Wb)U5p=~af^jIL~)JPc%H5~`W4 z0?25K38Wy#CK)jETzkNbA9}yR{6J_~%nu5AA}%0c4JmT5-DAk<=*ZbfQfgy)nq#gY zdp>Oaz8mXLKt!thMWlL?7fYmi-U=NjQq3dY46vc79A9J*D06BF|17@B7^BXI6@LuV zrRyTP3g>$c1c-ggPf912Jwh{$$_jlGyVA;#Q!%^9g|P)B)MP#1K>gU{?8SE{(Q3p| zGm8^7oDQLcn}1$n;{j(ei?9WU59EJV_(j9HUOvIBgZJJDt{@?zGOI zx;{foeRfNwmDR~s-iBR(`GaTeR^CM*{*LUosb0m{97|YCMR60Gw`es#lL1MNT6ly^ z2SdP~30$bI=B)E5mdVA&@7Rly-u~q6`DtLU?oXeg`ljUiuFNNPt}Q)3{hd!K{JH{y zGtD73{#&f>?cs{m9b;0^noM*IxBr9lVZ}K#RvbUx!c&g_h#qOtZ@DqtaRhIS_p$>D z_ybz)8Q z^gVv8ShCynJzvqcB(msxyrS=YW-i8sW&r|=+V%|*NTu)3*pkeK#)F_pj-v0NxjGyA zw%cgacaCc0RVQhrP2bWuZ56Gv=-Y1H@$_xA)S_>vl^C8R%m@Eux6&YB(YH!_Qu@9` z8YJ{B;_yh^PN#(@3XSJN<9Bm^q@wXt6(MJuyC6*q;> zq1AjuT&zQK*(JSZCz8YIPNF7B^lD0?-`RF8s$MS-|pJ~$ulYb^+WEMi1 zC`;M4(Pj`N7NH@Bhmt3EF@rKx!$?1j_(I#tu&D8C`GD9-WQlFGnJ*Fr??PEFbHZ85 zXtRhjnda@6o`~m+cN&w@N@d1$ne$=AcuEr4r-7$vh)UimFt~TZNU8MSJODGQ#VBUE@vd8961L03|iL{pie?Tz0 zu0SLfIw*d5z4|V?nPtN)+lCo3n}V4)A5$z~CJL$2$5sqdM`8nwUt?kf%sgbyl*st_ zf385=)H7M2JqUqD-xb{j+Jlfsk#ZPLTo<^^*Upqd5Ke9V6Miksx?#N6EV>C8-NKQl zFz$Km`PaC}yyp+LI5&>~JNWU)C&n$oCuZG>yDLz=NG%PnePA!gg-??z);@PM5!!$@ z^hoo_+NR|LBq3e_&ZOMHMDv#vVqV}Bc^&~{anKyhQ%Q#dC8B#)IQn~=AP*BzQ-afQ z`)QB=aHEV34EiYi-abt^RDDf3-!@gs@zu^|2*bB`NLK`2D<>Vy< zql*hs)_+F`(mmA-+PP#Ru*`?bu=nn7=DoInM zbRq^zL>ZTZakDP1@Ec{>vfk@$7@uuURBg<0g);?8>-Lb4rUvHJvIV+>AVnqwvBJ1PRQBs92?*A8h2o51Jo6M+4$zy zcauaJK$+7{7i?o-QY|mCdRSf@!7r+63W6;O%j6hV8M-SKkMzjHa9hp_0m%85z>*VE z%p;El_{MLMqH2mP#SaAelzOUr#M6K>7-8aftu<+5V@T3vNxDx?wbLmKssvN|TC!8P zp9RS9z-g^A1D_+6Td4Rs3}DXhY|!3KV47ngX_Jpp=4U!Rqm7~$bJ#J%xW#XdB%K=P zs|XmkWStyomjC&ikmfG3n_vFcE^HqG3Nt@&B6djxD6xg7BB3`WqML*oc~vN}nt<@E z9u(xP_wQQrX|?qCa^O)`Kws{R4nr#Vh&V=5yybA1hJcoXjfUp;YyK&Iabd`j45M7_ zld?7?hdMA>kQGfi(IM6gdYW;g7s@}^xY{@T?fP4W%{_~ASAF!WeQjk}-?ez+f%e`~ zdi*>3y`FeqVmLB&iGI0S>cX;`#Y=I7m8oT%s%1>0=!{Y+dR&fPn(yqzXt`*lTJEG^ zzR^z~Szz=LmNckgJO~x;W8SctJ@a1XC@L}k^pp*xKM>Gz$f4zsH~w(SjH6`ab%9hY z=?2;4%IbUadTTYcloq|m1EUH1jjPP-opP@uz>2t8;zW!j5M88jVv*mx*opp@q$|y` z$a`FtSzpiO`umT(qX`WUqx3pK^H>{8TX4u<+SE5T$Ta4mDz1enAb)M137RbMAE|vOZ zt$ZV zAHXK<`{mr}zW@T;#Qy{^_|;t}fPq-~{|i7+&0jteOwvtfVZk14jQmZlHW&Rq-rvTO zyuZ;qW)ao_a*UB;Td&o8Lf4t|v>MqxL2jt+;%SU5Qo{30B|I0Iq9|L~sntv)9J^B@ zCMHqMG5F6n=2Yk%U|fp9|AWIj!u5=CJ_i34+#fSm4F3Bod^0aXC@y7>;T?0I?RiC* zhqCt%?=jDMov+H?KVR=Sk-fj1^B>-Uz5j(mN_Lx9DG9vD)WC74&3_OH{J;2d5S|+x6lZ)V6Ws4U|3rfO4gICZ>??t%j^KVf*V!B^xQCo{4lj`> z+UrPcvsjjHn9!&5?Q=G!pL(4oL0PapkBbhCt85YK&p&4*5utv^GcjM8^!x|GR1u2u zSWA$l-0&b{f!ACpSwsrDhd|1BP3KjO*T3~FV9nUBMUORpVf=ohC1+PM?Rb?a=Qr}r zOPpL6NiIpjXAir%UZcXR4q)ZstQ}w^g>?ISxp;~7Ch`*#vQUVJP~VpM@J1y zdlCE>7Oqq`u=`r{HXaeT~?aa9I`-cw5#Jg&PHu?>1b#sI7UCFM$ z8`{ae-cPk|-F2WjTN}MY8{O9b#)AH%^2w=>%GYl!nAb1*N}3*z$zrT=b)GRZ$C#5X zOSHzlK~@w)Z--u?McKyHe)m2Ce&gzZzCYs-hG|$_cMf2=ESu=e(3^%YDE52Cm`rz! zm@M9nFFc}tHc|!L zo2Vy?+Y-0JyO()lgTtheS&CzG( z>2yz)YUc!Wx(G%p$c@U59`Pu!Wz9KF;P3d8vXF3LUT@rR6YZd7s40}d=!Tf+2KVr{ z=MHc1@iojfZD!%n2uumjPmp1xcZFG#fywUY(efRc#TmNGCjye6} z!z60>j=A|Xg=<6HZOyy5C2dwgZ*DhhRwX>mO{wg4+eMgt-x$vo>ZVK11wT|hu?^U-Ra5R!^`a=WzXXEfYA{1Z%;)Xgwyq>&U2Qb^l3-wabK zHw>g+&+xnyqfE^HN=S+k7pCfVfitN_e+5e~37GZCgg>$qb_u5EU;^gc5Caj3Q+Z6? zl~eiNIF)ZN^^ln}PF_lNu^Xb)Cb{Z}5Dn2QGp%bAfCBm>s-i5qsXG>}&MqA!h{lp) z!rkB-7U^B@s!NX#np`naxPrMz)MWzEbw2%CmmcxB-v^66o3WxHkgj*-Zo@=m-Zk2) zfq2Z_!U;?F>+Iu2P-N0^Kg43+qb=^YxH#`NiAhV1nIJLgb_{MeBw6H-@ylhr)ctF@ zF^X^NR#L@Axp@;M=xk)7__lpJh zvuJd&dGyE9Sm>iSja6Vf8#m{w>T^|16zSE|^=mxw?&=YoKe z|MkOMUVVcdchA0POIr1jU32>ne^V>j&gInqh+kQK@7<)^qUf)^otkJdeLw<2O=_;)j1! z#e`>f->lIFFU+D)b5SzUGAq$FiecJ((2w0{VUSTT3HF_#m-WTyw0~V$f3U2S)XJKp zn1H}Y5hn}UiaFlnjcubRDW*=9hlQw8uGko@A|RnP|Jkeg+{Rzue(PRqj#{&5->A;U z@41&fXTLx7)8LZE%K5%Q_WPmS+c!2IdE~N-t#>)T&y1$~g1VRi?QUEMG%7IJnfR2T z5f)btrCLwqUy>X7n0mAW0RVg;oNdlq0kFIx1}`Ec`eoy<1*-Y_0@S)z)w{+O#PFg{ z|5&_Y@geC}j|vnphSOGWw(x(4{%+^)=1&IP*`h8Od_`ORO0$`A zGvGn47p!r;cgkp2?$ISj61%?YrEk?%AJtaBFhU|{=p_YTb8B)zSHrxo=RX@geA}X2 zZFNhJBGymO-NDkM`+v4~Qo`T%Y$zW8KjH)@cmrPgwCF`n5pqMK+WJ=h4PAPx? z?f7maZOZuS@2aXg-_^#(mmIZ*c?83(V#WT(RAa4wo;t{F+UmArMkqPRZ!9^g2Kg;* zH7buYUL}PL^4P+zhQ(jcU-?fDa$y%tEOn6oi^f;WAQvXa$3*TlQU_W1-~XNQz4@5& zys{O<{c7jO-Spn7 zt#0js3T8LG$Cn&ZsIXaEjqdS_GaUp!IzyjY0G0ep^qvrU$2T0re*Zwhfk45y`01EB z9lmYxOYx6V09+tR75+Aq6u8yMq*BlsX#yjz6;*0UH#@Ac&e1)fe5oaA-(dPlJ%6pP zJ_X5ygTM$*z(hDLTQ^PdfUP}vz*#+U#Qc%_M0dP?dQQ(VR_l4?`Wxs;Q?4@~JgrM6 z6%JW@WUp9M-jkW0-o|PUq8{gms;U{snduxD;(P{L(L{4!J+c`JF0(q5=^@<~SPu}0 zCK4>pFX9e1GPz=60wNWelfI|2WV$1#gDY8#M7Cb)!415nb;QI?0)k1I|kVNfLu&rH3$3kgG8?Frh#MH<3| z8LxAu;x7m>6<=-JV=nN}Vf3$H0iEkjcLjubmfMXS^DiV;a__SQEc3e76anO|eM$iF zlFOR9*Qp5Gzs*=+CI#xdW_l`SdM22^vfA1wbRZ`F3IRyIx#d<>W4=2g%R6%Lc34cB zA&|txKx|w*J1oF^r7+%=0d_awWsxFB27pg_HsICvgQ^?dfqIG*;IqsU+6OSp72u1= zC~77(n6EB(AitH6K>h(~c^ip+Y7>uvlA{y7%_ov6f3H%8XB;EkiC~A0s|35=0{goq zhZ2M4TRBE|!@lih0X!hj7LZRxXB|lzYyY2s+{_SNHx{Z+1^cv)W59l`ib!Fg7JW@H zT~>tx@v|(5=b5+OVvVr{@q8d&5R+8}K$x%a+;iDC;ki1aOj>2paRNNgPU3l{`PSYO zXEK~`(m{zW6?3SdD#q)H@pkUqK%5WlBXIZeO zeYG~Mw-B&kEf%Dyu-^aqF|gjPB2r*2!RV(-O9fkUkeLN%XKx#ci9@DQk)@2hym=N- zl@&eT{q$Ejgg6LPR~ZPhR+yeq!o`EFYsQegF@rcq9{=ykpZZUg|0El(s{DKY)$$+s zr^+vJ%K!bb<%=$yodk#{_<~hl4`wQG5pj@bK;Tnhe#!M7(REp^Yc@%F@O~Q}3cvlJ zt}G{JWBfETqe?)Qn4g)bV7<-9Mb3r6It#XHiKz{3ODuwABhy#)^l*gE`8P=6;%&i$ z4#r7<@c8H5tj!doSw=3v2WnsZ))=1P0hcFono*v`$vW}mu$iU z3%h90pg~r-!aZoXM3N9NB$(`Ssi=WXG!M(Ryl>Ugx3<-4TVJ)U zZ54r9O$;X7R79%?)`Hh(U8)hR1V#7%J@Y(IvWZ~p@9q2hfBygE^UTc7^~{+wXJ*dK zoKf$m_bL-Y`TG0mG9S!m%O|wfiAXs`+si%l#ROU5G5)<4@Ja))X@~ z=4hF|&ImKHjCKnpgk4u~J^y;=oVoe>Ijq@@_U0YW zb&^yTzI7^9V2>sFdhkPGC;DT`>R=)QAKOvaIP2llc1f8xoUjcg$vIMt>@yK^gAU?YW)Kh6nIbjM9mKM z-$Yccw<=3&ZL~*~+>oySzKto}1)MF))$^I<;OJr{J~9*e_i87i$@<54n8;|up>iE1uW38x=nI)%3A4CD zTjbDI(_KyU{j^4=s}}Sh>k9fdWm$5>L+Y2+f(n1~ph>N)bjp@QX`{+HX?(X2M! ztTh;wSs`QnDJE7GsQw4IV2(^#n&(@Y)d`)Tm$P*FG?(U~n zI|&Rd;0Xy-?r>^rpTzn+yhc=trKsqmv}E5#k9+HJ1n=67B+B}j$F_(T%Jzi|x@iMZ zd~6RM85?|mV9n=$bKk}F9$Vy+j?De%TBVk@$Xl1{jW4r2|0M0J__D5{JGYnhF&Rl& zKRat#cm7Grl9S?p?AAQV)2(xj>-vDW7Q0B~%#)@q9BC2+212JWP$K~F7Vep-?jYpDt9IW}g)g6@AR3g`ZEw41m>m2ds zdLG$jbxF5DrQ<@st?~V&9?k2K6w(rRoo8gkd!lG@+b^={v|Zb&K`hvi;GVE+SObc9 zN`rTx%HZyXaJk*CMeR}dhJ~a;tj#u`yM88a{jqgs7kUzhkhwe$&BT`(4BB_8ilNAa z?3Fk@l*6OgcQ^_4HtHVH`Q3}A>kv0>=Iok(bg4{xx%zDbXhv&BeXk%ATg~vbmaLD^ zgn$p+Jvnll5( zMEYo4+g*LOwp%qsF!e9DTjSBB==Eo7x2mD4&FZEA)35`vuj^yecfBn4Zb}# zx~Nl}Wa5;ww-TOi*O1}5QBe_H*!aGyM>B0_a)moT`~pCm6`-x_-&a8DJ=eb|K=u{@ zOBoEc=14Qqz{UIBfuQmIb9%J)*w2dC%4YSSBfpRcyW=D5ijQz#1krd*fA*-1pA4Lk zluds?{nAIRjh6_?c(eYPp9mbPANJYkaV~f5McoBcOxI;e6&(i=IE8bHhp}G1Kzg3u zcMVf5TSbAc3iT&Tk&XA;lQk2Ywk@Nq!yd4Sim6 zj)XH2oL2Bbql3wTL!=Hlxg4659GadIO5wl|3IydC(rhK=C@;%aD<8RoEZoJ9Wh4DM z-05owBhL)nndS<~dH?wnJ!y=3i2on8*lawhbm z(88HiA!FtYW5EP-7>p!Mv}x<7sUG$Ip7wm1?8`5=&DDqAsb)%LvR-3~H%Gq)Obee_ ziN_dGSndvn6Tu2yn{3PT^;2)F)e21|iec^`hICYEL4DyWYmr`xOLDn|q*}8!QY&yo zK4&%X^41St*lsI+ZHlV&aNiJ8;z)$`S36Q>1(%T;P86l%}s z>jmIJj-u6FVuDC=hi-ypX0Ij__-D7pfyHkFBoQ;x!K`8dA(`J&Jp~@W<3Tn+jq6Qa zL7St8t5u8S8zR&x`Yrrci=qk~!#;~^nK3ZO$V?0h%)mdJLLK*;z?+n9%!EwJE+&#d zRu)Iu#Za~!xSk>qn`Dh#8KGvjKKD&U*68a&dO3xvSklhFa=zM-GrxyR$hv`~imbax zJO9`o^G{~XdnINkA)F#>B%TIYCka`vlVpmlYt3XoAX#U!&Jhgp*10~NC~C1h1qYn+ zPa+bH!&5&_Tt_a$n4@P9gTsgG=-d*)e;yf3(fe2#^ui(jRwhLBa@_aTQ)Cdq(BHiU zxXzP#&M{n4@%N!Y@RRr!c*pL&->~}~6k=%xkvV-Z@4&3FXnwfU;{Pi9*>7BgtYDUCl7X_8PnEdNRp~T!^9G?LD-9 zr;M6vt`H}f&pxDv+{PWkul3vCmS5WiGGjeHKn2Hbxx18ywVJiguat8>ocp@k>$+a`Uo;M^ur@0v7)JY;^%e9kt3=d!d# z9;GwMk9K4Ll#4(H7`Z;*FrFgnJ69l>CjRt56)Ih6V!HSOZr{0Re~@h>?V8Agvp8gJKi&hgw9nLcLp47PrEy+w5*cY9pN*t_8 z_hP~>hBZjhKn0+p1Z=JWn~-TcR0PSzx48h^cbcm`LwDV3s3*9y+#s5nTqc&sT5M%o zeFs%lQjK9*~Tf=5@qW>aM_)ka4-*1^ICdnS+ley>^!gO=zC84kaHCkT0`0 zZq;)Cf0oA`yax}oXmsa>l01mcr3$suhIy$IfE}duIT1qxRZ;HR8IX=y+)u@Mw&J8c zI~CWB*m1=LTO2IB(PjT7L&ixWNB$xy7CE9GAYs|4!~$A>qJVt|voG}VGLvT-#Z}EQ zis*9C`($hnwqN7d8&I4XA&%hWrl-5UjpA~&NuFU1fWRx> zQpiN7(cse@T2jzFSl5++|pTd4;)b>x(0jN4ruP$$Egw znk*+eqXVcm2OGy*RrkMxR)jzwvtO#hqlt(u1OSqmWuX*wz^|frb-fb#`@<$dZSO*9TdV+69vD29vT@vO?KO3}v$g?+DhIXW zLGx5tXnwBt(&+h<1AS2ruT7d9T9nIrxAr`t1~m6g$_#&ImmV%bA{4|`~)A1f>DYi9Y*$qAtsH{Jr?&+^PAFrCmb@dt)E)Xc%rl<+HW?7 zx_^+)DALf9XsVkL%+)qaUK>#Jvg1->l|3v9UrxSZ=0)$6UT#A(ztZn>Lu3=bv`R-b zQ*|4^Tc|C>fxa|YxidP*pwWn4vK2a62_WiJ+X@^KZbdeG7VIL~%sFs1VJ?H#-L z(hm>Q-+B}J`-orLJ2YY`#aDAI2)T6}xU4JXU2TQNDFge?D>4*Xh*ww-BuY)jS}3pf z#G#v>6a9|rKCBQG@kjK{Pg1F$EHf*$1xK`-cE$FGg^yk$$lE6kvEyJoA2s-Aip=0S z$NeJZYOhdlPu44ei{yL{+XG&b>VBP0HqViDNSnv&ezGg8?N2-C-tZZLA-DaF{26nY zEOMN4^h`$BogNMn+5=t!1rknNR3ph6M`X`z`8g7dM|SibOX)stnJGSpOOPwPhI|tbqlpB& z_p8`i3mN8g$8hTPl0r=mH=8M5Ay0KY)GdxCCWqqC7qv%RYDRoS!c*clw&k2W?~18& z@_jfb-<;Gr<*tv)9i}V6MQfr6W6Gb>Hl6ft#YlNiaNCeGHvB;ghkejV7LC zG;w-pth&*ZtpBx?8Fy6XS>yolNzqI6-T0Zen|9)qEc7QOp5WjQIJDNF5=zDIj=%bn znpsMJUG^~}=-eYh;c`rTftO_Vdc3H1|uZJZ$ZcYy!v z*%ACY#(gHnUHZ*rIxosW=jaf95pEOHH{c|tK1G5B(bwX5+|F}4!f&U8Jv^V~#Ct&Fhev!|whw$DzQ zZt~EFEqYbshv(GnX;l$bGAqiN(sd(U!giT2Yj4k(nXfm%=pl;v#>oexTFecojTgq2 zy5r5Sb#(0rEzcYc6P|~e?911;dnKDxBNr0OK|z=LGV}#T5gjGu3$7H-cv4JIW#aAs z8yNdO(w)v23my}_?s7fBtMC=-L0|988XcO8Z%Nxrc)M+drUYIZl!&JN-w zs*7>arDGIXUEUaR)f{!#>^>sFTBC0)X^0Lv?ykWrkrYYW6jfc>7&)hAcdHRkC9~pu zJy{aTx~mIi(2TmNoj)UX)lB_|B2(Pyfzvw^0$iwwmTlywrzw~;`|{M#Dkt|py9|)t z&{gJr(4QAEx^W-$N7$xHjsL_M%5#QRI`#Du3WB6J--?^P=-VCILZ_v5L=p7=Z}55I zyZ>{1PG4-`a}u_R&+#}-d=8UP6Q7skJ|jNk`NOCG8h`k4Y8-!vYY&f^_m+QrYe5fNcqBxo{`4?At^;=YDkH5?dMaB1bssFd??>|7A)TO`2S)~`hP2Yj=kV(`0Rv_ z0D9j#sO$H>e+M>tNtL0l1Z)!^_&6Lods?;iSEJbXph{yX5iS%3h( zCD3k4inD_??y`lpJ=S>RLqgQ6K-+sldXZh8szRPPx4#*W|fO!YI%1`{m#Y+$|1 za41rBMyZT+yz}SiStr5(ta(zEue0ofPG*IrGGn|>rw}Xj}pHQ%2r z)4e{rOY&4}uVgdNJwg{U&A-@&L#FxS(BGMFMU3JS96TTqM|N3zWteNP;gQEkHAmk@ zWc}BY)+>Pj&P;n3X$7b`2Be7#47=Y{Y_)kXS;3sAy!+#`(xKZ*_0537~>Mw8z zz+MYrap=R_BaSj7wo3TOE&!vUN-Y-8kxSL)>S2PjC4o%Q!X+I?t*aSFg!JUOs}#An z>eR+Npba6w7Lk?O{Nuwb9l>kRyx6gw4gK(BTCk;+$0V<@`A>uvp5}deQ~0+9ha@K# zBU0cnRc!@6$Ny@AK`#D&+wmvNwtT;9^pn#Mg~^84CPO1 zG9HYZSAlRFz#>6Vp_5f8!x`nI{LlHJ|b=Mb#m|Avl&QbvM8e-g-90ms(FggUwPCl zA}}pFC%#JUb@{f)QLrfu={b6U+}H0EHmU}UuKYZy;Vk_8@6TERU53P0+XK4r@ISQ& zbm98HumU=mJ1&vtv!@t~G31Fpbi02J{IBlkKnhxnD^!kS3=YiDJ6!|Z@u_&4hiHwH zFb<~DqFLCh4#=6OV)UMkUor-56O7+A&Kz+k$ZI~MLbtFTd)GL5p!{m~M;x8s@Nvjq z-;h^judh!)-a2vUv0n=|d<)ULv*se@h})M^FSY#n84F(>53)GMF|<8o1$3&ttlu*^ z_^22d^KbT=0H;A*rKpEjF5}Un;Lgndsq*kl-~dDFgp()_kDww&ko+&GGd!#Q@LckY zPWT^YGCK}1Q%PiJCFGNyl_pe}GxpQ6L*sd+m||0y*s*lMC9g=!sq~TI@pAk;lLxOt z-LySv&jmjp~NqUdaG;`^;3*Pcq{EJV>yG8D0bp5tYUg{Rz&TE!AV8Z&$v&V*}iTn zRM@K8eFCG1^@nDM{ez6GjBKTZbYc%B-ZWW$C9xybw|?%q^*k-OGh1<%c6rD8WBUa? zw>f$7Rt7cqR^H{URa2tGJE*LT_d!|zg=jAhStH=eUt?&hSY`7Z4|PW4G+n$b~O= z-|0Mu{m`$V6%@bUNWAa_AaS@itYs%Fbe&yh?b3=Gt6p^w-+S_JT3hgl9Gm1-fH%3l zseKWA=PP&pqd3(~i86QXcnCwtP`~|pnN6d9=q?=eUMR_3TTe{ZJY_7F(w|{^YD;@D z_*J5NgO5~M?1s5Fd_;w^zM#z6h$krK7%9Tz6X(7BaXzxf)LHuPSlfzV!*Of=EIq;& zERqXU^T_(FpN%0cfQG*(?3g*eE=DSkmb#wI(`g$n^sJYH{Mgcl zi~W7|b=R@rXWv)aYZY!J?4knBD+tKq%7Tad?8nnikf*%e${SjX8A~Hyf)*N3X@QT! zQBa+95S(ep&GX}-tJ#&8s&e$~cXITMqs&(2AhlYFYfOE4%T)+3Wd1V3HWvCWWyf)z zL)16>n2l9{4Ph9flRT5JkoYohCupuB{)~<5d=-G}lxZ7hc#-e8pW-+-^gqd2f5*9` zDX3rP`(CNGx^Mj?mg9ckn#lMh$c&pFcG@`mOLy&`Xa?%%7|8WgY!}N5gg5TGbE#Wo z8V0$f=wp$%8LHbR;Sy5!3c-C_)opE)EfIsw%w{XaD-pwmf*yG#(}P?@e&~DKBfo-6 z%G4xsN{5)Cud)4!WJGO$4rlxG45FX&S$G(VGu^>2m}2WyWH&F;hLh`K?z*WsXs1Ht zNiL&%)%qR>0C(*=OhR1RC-&Bj{lhav8P)j~|I=R1YVJ&ho{-In%%iCiash7f7;QJmA6O8k1QUP zYXSR&5eW=5o_0L^gs%pmv`?Umb@}?Xdlg?&M0Z^O{5>?pLNCF#MBa8KU9jP+U|WJa zSTF2klaX?huYnBop+6VhwB+J&*UFt69y(qr#cHkg{TnX|-!4^kYhPtGqjJmmNfn#T zDz>0VE33If<(Bc=f5k)|WHnW8^&`)$7VQ&v?n_*OqE@+|7%I0^ee*sc`LBW1vHj6U z9(iO~49Y8@nS=rhvBX|1HUO3rP1J9!3_I$?E1a35wVpgG3_{yK>_DTQkgso^q$W4? zxB_A?uKSF)x}TQhcl%`NLAQGtiyK7J)QV^1gdH2mJk|c9%&(#=aI1bM-N}B4;zlAa z6`yPqaa=@@Gvdg3XJspvM?t9}7jw+)3!ZiVAQ_)Xke^v^ ztxCeH;kJ9AvijAGQ~m+kEBf3#Q$n@~hjvI5IR<)0a!H`hz|EaGOMiN{s=sz$r!t@L z)dNA~eRw8~=lFc2!A=I@DePpY1j_gYeo~OeO#*aJ}yTwUTXa8Czm3cUBQ-5 z{TH>%_x^;Zx(~LkJv8uk@M+aoZR(ESvrlBAeyjGc6r+cU1iSYLyT1!}L{>KXYVkGn zKXu_BLL zbXxC4mI_`c4kMIzc*sv3ZW1NBkqKt$@8i%9V;HBcc}83DyLwuM_Lkv~mw=xwr*`UK zQs;pK5DPf`aVZp3$W&sk`>9+XidMKyL19jL+%`o?-iC*+cjU+V1{s1U7^iQ%p$pCZ z<3*G>i@lI}*xbGqq|L;sGB9RIk`J63HEGS`JYj3+ST-itF*0T71BhN`b5I4+UcwJy z*!ffdKr#SWIw0NUAuMp5DKW7}@>9t6F|nTZ$y!L#U7tv6IC8jZHeIq!DX}i`RwQi;DR#)d(1ol=}=fHA=IJRL2 zDBp|27D-Ex?mEGac0lc|;E}N%1+4nHKp-uewbwt-y>-L{W>(3;_tkaVR&Hxn&4v#r zXYJh~8Ce%RcdoB|qp8f%x^A%i2<_?vYC(7oK5(^nkx9gz?xHkTQwdUlAiC%`ocf@ zYt3}3wQA&O6JY=C?ybF~ZMfDL;LP%CMh>f=;kssYfY}sZ7)^1iwR)GTx-`WHt{yEG zjK+Pvpe=3QkfH<_&-9-YqS`={PdfdyJ*U)jsMKxGX4X@;a2V$0DE7Nu&kfyBXo^ zbHexeY5-HxH`glXSLjwg#46zBr`7Pz6?&OnA3FIK97CeAS-RB-qS_;=mm}<&koCqY z(fpVxnv>Js$U0SBs2#F@?%r?*rHS&0J?`-@*Bx-zSMr+~5CrU>Onh0PJM?+is8K^{ zFc(I)n%|6oIgwRDqlc<*)_5wjmZEL8>!t-xM{iUqKVkiGC~!q|s(!wiUeXRwY2CFV z_?Ld7CT$rMm?_cyUi(4SMXdaqb3HNJ_^i*XK2t9Hp{zHEJJP-3A<#<4puyc69>g8w zBBm>WRn$D*KfXdP+wGLSP_NBht8*hs{~@ie#M z)@X@k%$=^nsb7wvusawB%*63pT+Z=X?D~u>5+sYs51IR@)W@b@rhe&7qm^b8^DcHj z<+*(g5sckdhw^}C*Dxb5hgZmvhz#?+mrNR?eI9{-xsnGOOP#P`alKYLtPuPUtB&H^i~Z~oRjgS91Vd74u7TK0#;*3t?wEpSbg)(8H^nTJ>Y4?c5(pEz zj0)~+Q)9_kzf~0t>7!|0f9nyWrFc!KX}{Vkm0{T2|Ne#YU`=3p6e$mF4+rD#Rgv|d ztK@Oow68Iun96rD)UU9?<-yi$aO|T+6n6wvd6P3keuKMQ>sB&fMXm~`F zhbgx<*s)R4CcbtZBTuk$V*#L%ETYlCqJ3C&Yd?a7I5g7 zW+_H9h;kh<_TG2~QeHYN zM*OXg`IPx_?i*@#0>U{PTY?&P_^> ztsZP%Fi2O+tcyc;@cx{7cJ5YE$a$}7Y?F^wNG4b5MOccHEyO|P)iL93b)$NX+%fT% z?e7?;j<-E|I=yJey~R`8jNi~xr}s|w{YJ@R+K(u!@OFK%zwHt#@4e(Rs(a{b8&bcF zVLj?Wd~?m&ANaZans0j1$PMWFmMhJ3Yxm&bF~552cb)v6=G4zG1xpjtzqULc5|4>KW(d9IQsULIRfF|=m0voQ^`9S_m?4!Oh>k1mlb|ToiadJq zbSykAT~7!L4kXxrRD~E#D2L0B<35L8eY7QqY}{HJ34y8u!dIq!c0_=Wzd4h=P`yC=nt968Prd$-0W zW^%!EXO2)eSvd9HfYIp&Q}EbeO&zfifw@Cf(Ni{FNpa*(wZNVtu$9uT-Cbamr<30f*gvK*m{>JA5nLw>_gFATos3(&?UapdRqo~hYV}%DK+*GY*awyf_o$qgLnegrJZ~f&Xwaam) z`&*w6gPW`STiqyLxcNW3zqLzJsA=PVT$17}_qTrD9`V;^#7Ag}_%XmE%>IAz{?-7> z?RtN!2Yx1}b>O5IIrV>Jm|gfdjx*igO8zf3jv(qc$B_i(vCp^!I zk)l5{lrq$B;}W~65>K;(kX;HPH!f(BQnraaf7k(4lK z3nju6X!7;h=+O*{zFwW^YW8N3+&|C1?O)3OQ#59({F8ILW)jP-jrM{D8Zg8huVNBL8=N3PraDxx2>9V?CYV_#Ap>lL| z?B)rtjsdQ8GqgHW2Jg^qHjU%Wd5+-oazV!ts&a%bXz8XD5RF%TR~5{AQT8wNe9ELi z8OJ?RHtFrBf(>mvWN-n`Aq5^GFqI?A1|Sfe0gKR^)t?I$OBo!xne(^Ycl}82yS^CC zR`*>8=j$JhQnli~>tJm(wQ>hVo(wZe)vvqUTExu6C8JNHAoANTViF`9HHh_6+4xtS zVFB~jWmcs3ae=GJ@q!3@D&+ccv^ywDWpyU&7y}t` z=d`!~u*(wVVdWv%I+H$RPnmR~e^tM*K8eFrPjMiWPEB+Dzo5U_Qzl*VTfy7?|1!Lb z)kVv@>_SYl;a763?h-k0Q_I3Sr@tkryhU~cSu2rGC8dJ!&S*(~p>@o0 z?h-C=lvzn?zW%EpswPrOAJ)M-Wy8g(%j-7AR%Qw=Y3x5r8quXkCvAy;+96u4zs*ML z^4=ov{SX%gt${(prya6J!FFO%;Eto$vH#v%Z+gg*TO%al^$8gQqi%S+C=|p;h6NF% z(8h2_TpTR(sCWGOQZ}1ba{WXwAz0!~AE~YW(T@~skP;2)MfeBGL&`R!Uh9;H!7Iev zR{W#KSMGS@Zckrh1kv_udxq`iXsg4tsE2>Cjj;h z8xne;-sIa)k@#Kfga$Yx+_%Drs>N&$t zsP|Q(S?2q0`mKXZ0$hVb@-_?A59A<#-D+ecDJ8S7x-$qEryGD}wr>sQ6yHkBT3-!? zXD1={6fv6nsp(wg1~v~r6#Q}+R;2-W(v+zxq~Iw}yH0U$o!(1D;{w0LzuVVFcARmT z=B^DGg-W(0wX*bVQs-+`(UJ|a%OfO7XZD8kU7UD|Q^%4&C{vzp6$<)P)~Z%DIA={Y zU=>mgqg))De3D+yR!mcn){ujWC4h5utlmIO{q$Zk1WhT`ruTrIl#}bj#KgH0r|e(j zT!Zs*oTPaI3z}RE5~caHTD8X!HY|XB8c#LuI{i)T`}vg#Cg=pdP_6G(ewMYpfDC~(!_53y>ZMQPYB?8zM7{%3Vwt{Kv3%we zPN>z1c9EkJU|zYRyQQ*p0ePL~nfy*MbtH;}&o)aYQyKZO89DF`vKdS^^Ah9pm*;)W z{6*)l5SYRVGdePJs^;rb2n;<3z-5k>E00z1yM09#ay?)6Q7&LUUycPO4W`QJAww(H ztQpXA0ct}{X!3z(_t|QD0_^@9YP*cNS_d|hJ8CQX#?1#dghad45kLp;@PT2#&!N?i zfJ~{cG#d6~K`u@I5Eh|g5wU&dnlm1(Ajk&!`OVZnfgkNCnxz-KrKTUhPpEAGLj?xg zr4iD>M>AmQt1pJtDiOpTxP&o_ig0>CXB9FmLm_@siOd8^qvmhdn`tg34L3!JMJZm* z&Js)3ye;DlWiscqC%C{&@DH|W=pJ66^=fk2%X%$Ex)jG3Cv&_3Q8d%K$GZ`yKu$WR zlc12;&4Nke=f8&*1#zuErxy_twKbnza29(cG=q z8M#P3YH$hy^;>YLnpKF8iDu#aVvakA>UZvr>f@wx9|mPCQlh0}$(GHV(` zUG5`1w8?ir79knXhuE1|VviJ?cFiGWZdo>yYI=G4%(+6=i{T-z;Lc>IG(RyQdDRfP zT{ZBYgxS7zMiOR3Gs4ETml-o*U}h?3VjzXCkdqiqgO2GJP%iu>a$K^(LH%6WiBhsa z;I2D>zlt~#)41Zp43Ns@Xopl%24uzv#%8#`Q-8kTv>-eu8wv@MlQhy*SRA#WrKqk5QkYc&(gzvZTse!`R?C^1t@w~q)f>d)x8`iwwh$x*2)_kFsNDzX-`OuU1iphyihC8kCx$uNq)BeKii1 z`UJ`wKx+dLbv4A4e5w|a!0+7t5mT-m%olBCsqnIV{rn@sV2~SuJM}Oc6E4BF{{3UJ ziMw6cfH8lXdZ(H{b?gsi8y=nalqdw9SB-x&bL}cWE8E&3Ka=(B`eU0YAk`3TZbuH%J6X1u%YbZ%w+Z)6n5c!*o1h+UIx61{;nmZ?^hi>PEfL8bK zr+LPRkGu9`7)4f_ak-I;7=`M5&_tv?a_U}9U8lK>8=Y>Lgmqsp6}NF;54MKGTA2t& zkph=548)SketT*(%d__V=+i*oe*!7vx0yb~MpuJ(L%VP2y0{ zA$?pm@X*Y%bJa(SaNy`|eF67wCPk0X*EtC$O;SUZ{-ZsAjulbathT^2k>N5VC};!e z0_h*WM^!H|eJ&868Ef(Jm_F?LIrOo&l4zAjukKHUCZ@zzB^#sC#1wPabXBssYnn$4 zS!9mEHW!&AajxGfpeRPs^~&C?dd0%v1`V=*oJPDdbp?Br6|lJveybs!A=o3ZWj$rA zpYrv)=d0vRhWyIKnlhaZ?G^Fy>qJ+au-xa1UadcpVy>EhjYHz-TW~17j`xTUvEuM8 z8Qe<-^Jba)3Pq7-u#3Jz|2hZ(;_sxZFt8Log$-oq4COgu0doLHfG0`{L!kio?dAEJ za!{(DN5P;eQo@gp!c~8SU9*9Ah1Qm~%e_H5p?xnmh0yT1oVaMpi}qCAT<$t0iRj*V z(OchnKGUxYW&GZUOQvkwNQ)HiMmRDl`b{zH-ZDMscj9bpZIWEBia$zln`EPAadj#i zf3cFnT_|}qSywI!+9NGCB8`og!u6FqS*8fCn*m9&Z|bP1#A|C#b*rjm znhBHkbe?MZCx&`SYillF^jhOPxeq9Fv6th%FFw6z};fg8lOFNP+D9pJI-QcijX)s7UyX+D<~L-L%G z_F~q-s-bd2eY&NdPkWm!ry2R6=jT9=P-ZBbtkh?b$Hb}V&pcE$Caoy}?YBHox{wD- z1-axdf|X&1^-QV;HvGE{%sdB3CU8azMP(m1pr!>-fVDruZ5wLr(F-3{e4u@Q#Gnrm z&u6O1@6pg|=REx?BbI0{-JixwHx~$boDY+b{dJf9IQ-3>sj3AydZo2b1XN2`^nO;2nv)O#gv zGwgm3E4%OY%ppC!@8<`K=)L4PL8g|oB=27O-_N!B<3DhL-*VN}E+KEFvt1neuJ%a# zjYyN?b+)^tnq9YbyJ}j|sLsKlrNi_S{U653Ea?`8Ts^p9`&#XtsIuXN*4K}59c+(u1Q*yC7teqDNL!=p zQ)$&nuoy628)y3x;yCbFst%{@_1|4M@Q&{(kJR>-{%_@B@?ZEt@R$s@UNywZ9C|wZ z#%X^et8vwNCind{X{GaICj@2?Mo08z9bDC)D>2%sS$f(Jj4r#-6thO>^H`ZZ)SZeH zSQp}tvVl8mCU06^VkM*Yu`iVt5>8@0bsW7w{{+5maWadsC6TE*IUob1Ddzs$ zkELp6O$^K67oJd+3t@YO_WH2H%)}fpZc`p=f#$9)6`nEArM;Z?hI>Pa`r%+Xr-lmq zAzqf@k&g_$j{)ycslGr!rLs{xe4=WrQU%G`pt`rgPDI3?$|oXMEcGj-2G2`^VGR=J z8Hw{Qh8|_HWGJ0FflCO>O#)#V4^M%yJb(W-EPf_FZrJ_qS9ag2imhznM}3}fl|11p zbA)WC+Vp!RQ#H*0%*^zsl%=@F#o}mYs27L6qCH|jMMUT>r;$y;OdsueIq==1RLc{^ zvc2l_da0coj^bR-<8x_mRo!3?13b3K8jhjE-ZXbszW(S%ia_LwnzmYWDrt6YnS*JT zF;!H162rGhW5N5E{i+LvrmRsO+qjFWyHu?00<6K8zF6I@% z$&nA7P2cjMy=r(k(|Miin5G)SvYEJ~f&STfofJu-uuQMAbyuhjFNjw?-#^X5Cd7a`_s?DTYMmxP+bM;mp=ME#l1PS8AP?3oXq`KusEof zfyDvXCKgk0eghUq2zVA2J6Lv?`mNx!pVTk$BdMRyte;Qncl-sjesZM6k3jfLB=Y4y zR26^q_Lrh!Xkx0VZCzwC6Ggo+dxGL*wdI*6*K-+rFgXP~8-Yydc8)3f{$(6o+|$58 ze{2&6$vDr1gWhub)GNf4PAv?l(a6Slm5MevIr|O;+7^iP=?Uo{h)~0>7usZ8e;sz# z$Zd+FD{s)62*?OKTJq=V6}-U{-0AF?@oZ)|YYd*^yjDViqiSeEfvYMlp&+@+mr#%z z&hb_siFQ(_m&0XoCzp=TBX;$t+YfTpbjOtxtv?BWboY{*fQP%msSdM4p6t)ihxRbn zFIVH>8r2(t?^w^!&Z?3W+oTf>J1}f_w-er$v|oW+b@k%6@{x@2I?(QhNcJ2U}d>^uG&sI;vl~ zIn+I^iS+>CVOJ7JK+pT^g2PBw7ngx9U`h(3p z8r^}Rzp~uxgrThw;n501kBQ?9*cSPQ9FCT7LD%)}t+slzh%NX{j4xna*8-l8&Xb0v z1l~O%cb95Q9!qlhsutwS@^`NGyq;$!qgksa**}sT+2=P}Ko;TxGrNI)xmV`Y^k8FK z;Avnn1O;-oayF*`l0=Cy2M~9r(ghbZZTDQ6XVZV7cJ}qr9J+M(+B^`Hg`paGeaVM? zGq!LkOFlvMq=!;adN{jLbNJ@X&|8yK?;Ez89^^6cpWu`p^<3bjh)`Jyjh=`kWArp< z^>{UxKCa)|3ZoGKW#fg_DF9~5OhB%=GMc#S>I9pl)KFEkz|oSYwuK|F5Zp3Rb)1%o zN~|F~u+isB7KC}E06`QKsqr-c0; zZ}2%UOQk->O&F>gWhiAcbL-zSQm%r5ZUh$@A}w90`;h@RWb z0A70~u!pX92Aj|k(?$t${&T<9#QD!ckDUK3^mq`vSaWaL!#0EvSLqiZTVTfBLlCCr zIijihYs}9L!9ov&4DPz;DZC|5P1+Gt($XY9UNrNEYZH;(qE9JEDoVB1`W=%M(rN~KCR0=BOj+&y&+N4;^BsT)=Sz8 z?(rW($$gxi(uuibbCS z-DLE9@(!a~?4^q6M1Pv=k7VMKjjx>ms49`;%xbD$$PHA7WO^#0Bhwxo`H7(Jke3K^BjN7`bQu_guy(s(ZbOW7Dlp-AqDXokUb>hio<6- z)Eu5FCy~*JtXq2=yhDrzt&~-{q1gjaUlORmmIKM<*m59wIW|XQ2Y7=`av*uX{S9vG zQW%|A9$iHZX^ZR++tj-gX@9f7fqbi@^*OJJytsz&&8nIhEm(5cc$ zV<$7vJs9hzwMIQ6q^=p(+M_KnlBc~md414U)zgS4SjUy&{@p*+DFT=KcVuqgWpBop z_oc0xYkRemjb9Ap&8=MnAe^c}$m{Kic8DkPO_LMD`w$+aaj8en|v7 zHuV_EpTuP~;>o}Ee=hBmdX2AtQ`SrU;n&r^nRCjBQiDh}0oFu*Qo51nd6MUa817zi zGKttAS0mGwLG=w{I+f{Crbn5{%1lvasxrOG^eJ<&GSiirq0CHWj#Os0GINxftIWyD zoTAKpWzJS+fieq~xmcOS$}Cf6xiVKO)33}m%3P<+8fDfh)2ZsRNx3&G^KNBsQRaQh zykD6QDf3}vKBmmamHC7+w<+^!Wi}{tr!sdbbDuKzEAv%l9#rO=$~>aXca^CtbFhLc zN15r$%ur^gGDj*iTbZfK^eWS*Oq`9Mlho^8bL zaibgEwO0^F< z-;yYaVQ#i);>I^9Ef#oFF9&Dy^+bRSwT_5oUE{xSuD;WNi`!dQ&0F4WUg*VGzgNj7 z_L}|<-73^dtaIn;KQm)FV^`_FlLGV~VTMNP8^vnX7h&bkBk=W1SyZ|367+z*n`;jT z67@>L(XDUSlLUnMCj6o1=#`F@YhZ)eix%FvTUui@(9YE(WDpA+(Lcc6r!Sr z7fv_gz{yWS2XVQuU*S3NT}%blJXQQ&j=X&MbyA+y&Z_RCiMz@^ZN!04^THdS^QgJ16evgH9GCC9u;JwX@9YZg9K^Ze*yvry zt9peR=ig0@83LMy@MNj2&KCWE__HKy6FfOM>r&t`Rsq~|BMwCK6?h(*3K8n;0^Tmb zOa2cGj|rO#*!lpQbCvUQ>I!E}#&%-6P98dW5I!9btdu`*gv>WQy&7&y=5i6y4xT*3 zsG$ZMqfoGS+qncKcLa%MFoF6)#wWQxWgyi+DNs*eJ1sg397`bhB7*DX=*w>?ydDOx zpM(VP6ahRr4ygjTO97q?z$pOk!uCvG+uekHQ5WEWA8j0}0zhL_z|#R`GEhq4sa9A@ zM_4Lh7FnbaC%K(0JSJHP_$g9tLOor;7qUoIWRcQN7Re@AcucaG9Tdn^%H|%*#o!f9~f(cOY1%hTvFyEmi{1oQW&qhEJJ?YZT$349NrMU z{(*wUoIeYEIxl!+;Ik5Yxp)5MyMnu7uk0F;C}CROr&?Z{mUsG>zx?I1lHTwjiQ%`X zIZ;4C{rp0@exjZOsQZ>X%N7f}mD_j1S+`BSfde^NR58aESnxnL)_SHyIktQ%5ty>Q z7hJY9t3E}7uc0-zOW5U&`7`u|Fbu_JzZ+cRv#q<>WIHIk9~jCz7J^N$A4#?iD2od< z3a>IF3~%VlmcY2am#DOoyGBsoV?@JtX{Wmktk#T?hOqgQYHoAc0_Vg6PF;2&#Fm-y z{P`yK6~;nfN3eyOEF!$JOY{_X*C#>*(Ow49GjY#9d2qhsIC)OhaFW*!h6=;`;AFEk zlY=Fn+QNCC220v(`LTZK485Vewh@B()3JUs_74+>jgbIHIPVyd9Q+97wT7pj9+7u! zMBeEUjk}vdy`{nC&U<#+`#FDNX9W)TlHXDHV&GDp>%pKrMJ@v1@4DQ`*WA6UP-@rxp|5+_q0D*u|c)fY>m zS}|#=^~ZdiC!4kWd^Mq@%@RXXoiC&xo5 z7>iZ7KXbd$vz&p;6a!nIrFztWZAOn8ml8N9xYplil`FViCkvZDfd(Aj&{TFkvooVS z!L}%_v#lSwqf8m&m#Y!G?iCDeI*m8bs_a}{LSn!;~ zrZ1+p`+|cCXlh&2thvu*(Chys#^@8({pW?QK_<{M^pZJ?c^xs~=o3{DW(g8^q{J2D zpT%W3*;jV`Z*y(MFP+r%gT}IL>P= zeo)dKZ;Iy$KoNRx!HnZl|5zZ|eD5jXEbIF?vp4BU`f+HC!vaP(9aJcl3?B2%8gY0+ zj{*5aSl&}Ffl5V8RZbfROIn$I2760Tw-LMN&eH}+n(%FJ&T{`EbmB&>ySCcFVtd4H zZ615~Z-#C=0yABIa#Be}Ae5(HxvZk(THp=ky?bSazoZP|!({x+w7nphtHq!GK_2)Xi(X>(eIflqA>qP?#zDKPW_L0fQ_ z(?|$fZ4ZjiXH8!JIl*0C!<%kyc#mkHHwgbIB#!%@hNjVqg&hxcJKl6WGMH#It8^6U zQt(})N0s$(*cxK}*5F4Ulhu=ITZ7raYkov43a?q-ZT<^s50>4;XxF<~%zlf-98f6c zl?7ssnT=Vxsb7twvgiL^1JNusnE5^&2~4%2F;eW#h`p;PElroGAAqZX=QFx=1OHgtjznBS+C4m zWj>_L$CUYmGIuF+lQL_R*`Uld%3P<+GG#7S=00UUuFTEKyjz)DlzE>rTWPNLzm+!# zDWG?5PNJ=Vub8i#Zw=ojzWewd;oHHthwoj!&-h$(6K$9Ajpr-oTgP`V-*5Sz<~zW5 zgzp%ijVnCo@D1gg$hVMh4c{id`}v;WyM{bp!+x9ZIA70#L|ZD~WqgzQZs1$aw~lWk z-xj{d_;&E^;XB0F%GYgvqRq=Uly5xWLcW!J8~EN`Ksd{%UD!|X{fw`kuYzwUWu^mz z{QakilgqG2@y+GCkMukF4)C?|CE<4--yd+x-^4qd&_>XW1g$kUz_|>SEcFZ~ULt zmJ(ib$9P+7N{+0qZBD-X`Rz&0QEtJZs2jPWDp2iTa>Z4{ugtu1SjmX1ue#}`;U!lN zA336QN#@m=!SmzMawB^9)@x1wl8Nk9=zWo3Ew^pz#JmwHQ=m6v$SiYkiBOUUm<@?!=``touL zDJk{}fmtOkE2;JpGd@kV&3245myu>gQPs_oW04VFT3O{SE-5b&!Wu^=aRpU-B`%rA z$FYrmKG)_WpC#p$)p7Y4uvs}&8+n!#+ibTHpCe(mTvdoF*aB2gW7|SF+mf~wm8(h? z1y&Xp`K5+zh2t->qu3Z@0PBpal|t@*@5&;7nYXgkYaooYb5sUETwYvK zt4h3+=3MJty{w|RaIipssS z{DIdI38YKT#K+!d5v6{sj$ zP4tyjl}k#ht4pefdh^RmimFLR=dLPYEHIjAZDpW}jF*%#xd%J+G4k;HOIEB@El4Q_ z5ZtP>~_a7;T0a8C4A# zN+MhL-MNbIU5M=fA4VO$tBa^hV2Qw78YlFzVn4M*Y~=!z%%kJ z@vlEie3_>SzmV_#q+HvYv!uV}Ea@LUOZ?vxU-Ilqe+T2@6QvzrPo5>d%qwO5mb`Kf z=h#;A-Oty+*UBe<7N1)A!Z_8ZRouLBwwm$G`zDNQAHSZs%;0A*>m@g$Q`#}zZLV32}=RaO-aUBUobSy)xFRJ_)zS?SVc{<6SL zLzh&p7&5G6$&#yvXJr-NlvT21dpOmh}{S@cwumRGJWDYkHJ*%lpIw%}j>yvjT~{YX5C^G&p2(cw46 zIU5~XG*TTJ`9qKb(nH%%?78n?1)YSG&30u|Q<%Etwk&MH|seTjcs z<*MA0C9e`!=75K>1*h*|OaIeN+k)Zm{1&?W#I*l`Eq(9{Y{8-9FGfDSuqB^!O&b^j zMOABoqe^UmSyBc#%gTYK1aQ^@4^k39V*PMaNfm%qVga1`353eF%_cu-*LkLWgJ~}? z?Zu|O#I#FIdunCH>_Ex9lH%EAfr(YiW)=Bo1w;(>5a9yuATwPKT_!;>uL zK5A4oOJ&%9=fU8c+Q8zi66fF121zC!zNt)U2dgb`+Pr*SX~Sy2Z^}pbfaD{8e?4sU zRfjq`Z1{EZ?`Gv>gjwz7NIHvumwc=~?+|5raex2Rzi&r;!L>EV6MD4%;{6@n<(Ki- z$-hrWJ`(zWTCStLM;c}PpXQSoUjeeR@Y%(?-9NtE|A)ORfvc+c{__@AQNY|ct_q3^ z_y8Bg?XfCKNP=RD@>m{9vc=+(CeJLjvLt_{m6r7TSy`!3*{=D_$}&qT`?Xn8*ecbnW4^Y(X_xTT;H*?OMIdf+2?005vfJX+FsjwzhSisk~jM)(aW(lQu ztB@s(7j#8JllD>czbwi z+IR3)wexE4>fzb$V);SbC6!M)L)}ZJznmu&i|oFb`JHef$0j<4W_$fdcgFA=>^jprVorCi~!RY zrXNgy7=M@mm;o>YVFF5O0y7jQ2qqY27z|e8bs>@og$aWh4l@E~B+Mw7aG23B z5inz5#=?w)84oi7Mh_DS69p3u69W?q69+R9W)e)iWG2H*fk}Y58YU5DDohg0H89g) zl3`L{ro+sDNrjmSb1lp)nAtFCFmqt$!lc6(U@~Bs&oQyS8c2N$Q$Df6` zdje#90o*+RrZyYO?h7|26FsI2GLq(#Cb#9!WSX3C;eVt;Vp3cFOs1r17yd`_r_5-} zpUE_1W?TMDrkS%Y{Ezfco7!wj%z0B8xGvt9VJU> zSGG+(4Ik{O0g;^PSj>OumqneN>HLb{(qQcygLV975SD3XR0H_~f)w8BZx_GWPTv~v>yduCqKeXMKz!IrSz7U16^D?nk+XO?!_h|40`KUtNSUdp*{=LDMaWWK{rt9@fMGN%^n= zNd>S0NrkWhNeEMoFuLmy4p31X$qXoH#)9l*V{tB)p>8l18-%P3+QvbfClHTrS!0}L z=%C!|RT&+{^l?$l04Q>eVJ4p_zW?i95m}h-65LcF$7ngw@gh-3>okh}+C|3DkV}4d) z?^@ILtEkwxFgUj)y#UoJaL_hgEH5)Vka5(WR{j{nM#HXwodElB&}pAqUSZy%GGw;Q z|0QVDp2+xzaMRpEcT(I__YfWi?MJeg_YCCG9ulRI_PEeC8Z;eQw5Jj2o^Qn4O4^n| z+qS4_5@^%bLNo_h$;=T@lnNyw7q}m=q%=E?9(r1SQArkep`9d=7bvgE{z5r#ERZ<> z(DYf%!`gjzaAsLfa0%*0;2?A*jijuMqKvHE(j|d|5LT9T7H(>jWt<8;$!<-(QI?Hr zlnvV3NKgT&0Z@5y##5=_G5r+7<{{2+0lduEl{wiz47y$9KAN{=>F5hG^03w#7Cb`n zTHNNH9JOavn;YvwHQdU&QiOJaK$%`j|1`W9m)_J#&1QTIf2SnvH%5|J&BKvwYFu1u z2#JH&}It4AtogvBCD*JHc6tO zN&6s+3QJ0IGxM;|EC;X9c%>702bNHei#>37Pmm$Z$5yaRqp<*cII;9rxWt&9kw<;X z5+T2=G$S)_30`YrcNX4RD*KeAtZ18OQUp9Q>-sWmgH4{6igCh%*u`0SWhHophmHv? zTo~RUSD_C;9`d#u?!>Y@o*HGo&)L*rr*?cPIvXvNVLDea7-WyBz9=Xp18apT#XDG=yYwS_LVs z)21hY2`sP~cm#m5TooaV&wB_9Naed> zu_3aQc7&o(p>SdEDheBI4yC=Rd{a1*`VnuaY5m{*kSJ~idX@5 zRN6k@Tcerzw79P~9s2w8R5boLDJNVNDl0wDi0@YW!}dn7P}myS@-uS(HHJ+Ejyi!| z&3IN~cWSVGCgVa3*l&(4tc3-%Ur1P(fgu|;4X7m9(r%&*Arsr5u%Ri-h_c{`c&HA{ zhy0mV`N@SS2smYcLXS=7*o9h{pNmbb*+ZSjOvS;#_mpP{*!_@Mh^9*sQF=OU_)pKo z&Z&a*lKIHrbgQrV_ZT)AaW6wT>kC`P*8r!nxDqG-7r~EVAp02mxyV)l$O!zm@qHDc z}pvA}n9 z(MwC4kQSUaJuy110=#{|69O0vknt&SQ+uH_3OSgZTH8HICSq5ZAfb)pvC`r+2&VlZ z&{y2OXDvJto>J2{aG=!Oq4h)h2M!#HXxYOk-&7a-;&N2V$GfHS{wv(nejBdB*%a9H zj4I%+>?EFDA)KJ7Gukk(Xy(%e?U$nMF@Ubf15`SwrtFdE;D>{XXn;)l`L(YVpZ}-v z;`?oJOi)-NHo?|i(_-IOT!vjB+0-T(`M8erP_fLUl`R!Rm*8>ZjV~V$p`(jTil<4s zatM_;J)y+OFhM-kKoaD*JCod-D|aLX1z^>nG`h11i`NgaIRl zoKz5n3>twN7qj1xHaZs*4WRZ$AxGK9aAstdb$rrQ(yQq+SYTWt^c^Q;MMR_|B&ScE zo{~N_Ek!7Zr+`iQx&WfILdiBy>>J2PEeijYZLN$Qjbu0K?v<((I~zV;S(0^4caRF#jeI zPz9-POrSuE9`m4fV=c~GVv`v>A7~_2RzSg^qn!4Qh=+7e%~)V;qB7|6*wjbT$EIz@ z`9kGfn$8H|; zSaZ5{TXt+=PGVtc9JOdk)+R58w|GdL)ND>O@-|UPK%?1+M$!o0m<>S^&6pjDHafmw zdWn%7@Q9SBDN(!~PeL;uDYoyibkeFMm74!3s&w&UuMtljh2+Lg)(l$n&7N9Tno9l5 zEc6`lH187oo~g8ITX{|#BhVN}xdvoY9va63*e)+_=#!klWhZGT+_JSh!yfby9X&2L-KnScv9paVor8T)U&cotM1lbV53{&Yin?dFNOg=p|G13_Jp1`OEqiGGh(c?&7& zP-`kC7^oMhALO8^J1zO;7M7LJJe_9o@}fH8$ZLpUxF44lq99Yd*|hx<>)8MyIVCbB zHvQ_z*vtsYxv?c`CIFHY)d;;DRYRi${I3!@yQ39~Rv_0hV=OiheMzaGoS zc{Fwz2odgzYMD;y! z7I9%LKZ|O8y(OY@F2op1vWjzgx{}nfJl}P&1<0QOX!`uE^AqtwK(EF$^LHu8AkiyA zIJI|AcILeK#=N57?7Tddyd;03v2-ertb{N;3k4QmfNq$-6-gz}xZ=Y6_<}qf{zMy% zF-<9_LO=pY4m?>;O)T%{f?(4aKo6VGwO~_zy^Xp?&qyj)e0`cmlxY~)&&PEDND3As zuzrzVR+FCrNnDsPEq5fSPB{>e%H z{!vN(djDy0{)7D!Qv3(_PfYP2>z|P1Ki+>DJfr>n%SIXT6RPuHj^9!Kf`3_9w*Nr? zvJsj7VVcurVoF8SudH+SUlT%aK%bHf7%VUSJPo{7`@7=QAW zqf%iEt#^zaFJvz%5ODqj2ePBf3Q96^Xtj}Mt3tniLQX-T5Hwz}Xk%F}@_^p=P&*;x z*TYTawWzFM2|dQ8aFe-sZ?X7A3qjd<4O1{LPu$%cA}+Zv)S>hQ=jAQT4`vpZSerE% z8JE{!lz3n07aNQ;NMWim2BUQvB~Cmt{yF^ZapF&(l{hOg9lz<*rlqG(1EtZl>HUq( zdI8S$xyJH3$eZ=!Q~O4F9~=H!=3Gc3lA#r7DdIo#vheP<8Vll+5k+<%~JebEy~&mQ6U z)T6s!se5Ws!Nn-EoeOtt+qC;a7df(7KZxUwQxZkifKSK8UOP zjpNV0^~jEO+pm8hqpptQZ{PlN|3&>a|FE=9%g+<$Cok6D6@O^whB_~fr@s5#oFyH{ z-t<&mCytMrarWwwcl*5hc3m%yPrY|ic;OElD!#4r=lFq$n*!dxrSv0qZYalp+qie* zJBL?Q_B=P7V9e*Q-*PU6;~U-zc=_Ee3;tDkE{)?iKb(1^f8O@bUOJb}@iU*Mx1X8w#D6|K zm&fq|zwH0wU$tNTdg@#$$6qitJicwmv(I|gFXQ;_lb7YWq-U-UsK1%x$+~^R4Gp{B znoz%%77snTL_TF1-alh?Y{cesw7ZPHe9#HkppY^YCe0%xQ z>Nmcca9^i}LmYPJn~^Y1-_lcbI1SHJn)22^s%_&j{% z`|lgPBrJ3L>pw2uq2VnAV>f%;UAuVngcW`G8*9d%>FoB_(swtS!=)ATqO>2Dz8kuH zT{0WW!_POJcw%e#`yb}B;T(_ccYoIb1E+3T!^U!a;Mv!Xg#0_}r+;Jhhs?GeZ>|kD zeo?iDzxl@5E#nhC?sPwZn^aS{|NXtMkNUIsoYzkC6;;|7)ANy`xmT}mugd2BKipB& zBl~C7rvp{gQscgBzxG%m` zZRL2t+R>j4e|6Ktb*k+gPup_ue~Rya<4hOzE{?zZ%88WZy+@x9QSavXSCRcrcm1_) zO@jJ0jz7FO?SoD43Wsvkhd6#Lx$n|nXLY%Eh587`BXoWnk3L)Z)h6{(j&FG8>$K$e zKH2u1`Z&kO#yq<9lVzLER;y2P+$U!1qX`KMU;a`38^?QW)<1XZ&L?hn)zoo(=*_8* z_?+^q7BpJ4n2Zeyx$DF?TYWZ-(RgwE0k6#uo!#W~-E>VS(f_wGnV$%O+lw^4IDX6F zM{k%rCB}5S#-HOspKsUbkN4gCux2R7*EPh<9kzMioo3B&jz_+*cJl*W!;XBa8O!m< zdValY{b$`D{9O~n@lO^Vd#PaWh9AAP2^^=5?0=`>nbf8q+J^7k&<1^_q0RbQMSPSA z^zI`Y@IB_DJ_8x6T%}_AC~s!ka4%zD{*H^u?jKXsA(nLqj|Ktw_>=7`JiV$vDEQj# zsqMGSj?54GSs_^EcirCXpTY}%+W6?Fzx_Gkgk~!3acKF1)k%u;Zou zPyT-R1NWoa*FLR!XLtAVutzil{7xj&%aaz2YFY5TvsZucO7WIYK3+YnbH_K5zF1IH zF!`|e$M<|#aQ)K*s&d}g;Xkr-?^z#2jqQ-qkYz5JeyHoIKaHmYcTfN0z){oDp9+3^ z_teq!Kaz3Bnv~8tNat9@E905Kdn@!%j<<1FP+Dg0JXjbnfoD5p2(S;qrZp<%dMLfa zrR^?@Xsi^v1$3y|lLu#YIL?=(K_^R2QZjt{b5nsT-vW*NqOL0}P=dVIjjq zMudzE85I&9GCEWj8bYTTLWhTr2pt(ZDl|NFbeJwIB#aI?3=bO-HZp8fSa{gz;kw}= z!$XJDk%tk(N8&=Q@ZqCJ=thK$2ptiI3%76vV#KHs;Uh+m)Qt=o89Fj-$Z$G3F?uvq9F6ElL-c3_ z8x0a;Z+ge_cU14frnUEK+%rQZqbmv_jk&}m%b9~|>^y8;#6*?f=|$`N$fJ4KCv>8t zxTmQ*YDNf~Dm#7}O%neNppR7WCrk8b&_^lgDH2^S4{Lx^J&~$w5Dqt1%=|;hJ83? zxvzs>B;P*mavpUX>jCCL;7?YyX;H>#Z+B1<}QkEH*9gO=v%1ZbOPYK?F2ReAO10H3tjO=U#E5at2 z7D5pVoxO9Y2*v8u6VZ_$^1{AedpQ9!pG$Q6dhvxsr)Ihn;7vd^ z4u#{z8`HPfFw@N_sX-ws_Ue!A*xe%*_3tFETiBNoxjxV{r!p(!)XNVC&Jd2)OS`}( zf4SZ0EwvkB`yjR+SY#^3)2El*w5Wj>gB)p^t>Oz+o^eT#OJ!*>fXbkKIhX4P=J{fM zoL7wd!^HMp&htk)i!wGLyfV*a`eunP=ebOOK%&cSkxYM3qRV+M)3-?UpAa9_x5Kb| z!JZ7DwnfGhBzy_{gW#6KKLj`FX8@h*lbrTCxM?j(#s?$sNgf%+{!QATiTyB{OZa={ zrnxE>f2?ALzLbfUBoqDnf|myUkiF)_{;QXB)Wb6{0h1{E_o(5Gn!TP1Wm5 z+duKHm)|Gkyva~z739czx#2uFwf8jkqI3iRr*>YZ)5x0Wy5L~@e3OfZI=6rE9nDJ$m-)-N#R8 zoV4_9bdsxIfB%31>VfJ&xCad$q8=I)JWQunhX4&Fe==ce^>ESE>faISk?K)0cer}A z?EHWGe<=qd#*C%pj8m(}PtZq3MaRU(0iF22l*G%OmPv{T^68*BW?qQFV3crtYrk;nqvtTjke9 z&QL3A>c`ZNYoBocOMTYmoVH%m;IU)zlH2e2w=Q+&?Q1J~_5Qqr z_mqUQb-}|Xq|Hfx_N$xkxbv>{k3IF$%dfxj*1<21f78IUz8wdJ3?CISW?cN_IXB-4 z&s{IQ{Kmm|41UJf-Sf^H?;eg%oSJ&= z-1J-TT=&#-&+py$#(|G~yL6qMcIJ=z22=a|>%TaLuVxk$_UfH}1u=D}J!ybL|`Mn1Ye{}4A{l-^07 z-fc*nI%~F@ySLB4VLzWLC>%9zLR4(UUG)vg^UB_QtNOiKcD*Lls|F2h{LxT!mI^DtHEO1(_~?cwEO zYH%?<=i=|R=?%~Kbv`%Wp&8||BCV6@1$WZ{-3YCxYq)!yyO(QeyFQv(+G{;bE4%gb z?BX%W-E^Dl6I;EyYC|50#d$`96yS2fHR{O?PNbuV{K|yxTKZl?rK8 zqqwR)UD~OARKD7dE?4=YPgZwTch~lE>Fw^Xx=yn|y<7dB`iR$u9{*K;r2bS@=UH9OFTU^~dMvfalzxl; ziyxJ~#HrcFS!vHb-?P`Y$3FhVV^qam+uS_IjL*qkx4tm_=ToyX@82{qaQXw45B+EB zquX}8wEH#Jc3z!(M@)#l=8;Day;JGdy+^-*@e^KuLo4(T7!Vj19x-WhLQ?Yd8C0?i zS;m|NC5vw?zisQ|Pga?$y^8;{_3c9ig>(BYb#q%TAKp%7s#r0~ql>4z>E6+rEO!rG7ni=8o-QhVxOR%mFs-MXhnrp) zsP*y~sflpu;imO+ONt*A);`QF*xhr*06)`;K=;9>Rb4$2wSBy!J9KyRbe-ri(4(x~ zgvi0JV_ZC4uW?nm_-I^Aw;O~>?w+Pc=Jtzi=jq!1s?lzqBZq2zOy;rK$zCc`Wo*w$ z?#aDJuW*a=?5&v?KT6ZV-P09JD@JxV9SCi|a#K!OJJV~o?Y?=~y7z9H_|S_tjdmNX zRT~C)#(4(1Ty;~`Y~vK|Xg6QIw%5j5_nUrwxcv&h5RI?aeZ|^awF_L@YdqY1{$((o z@hovK=o)9bzmr$0M|ace6%#eLM0t03Ug;Z? zFwXSqSXY&Hx=YXD>J=S^YO}p&c(&Kf(Tp42yZunD2MV#P>Hd}f1+AS+sn@k`s3h8O zC?DwFXWAl7h{p7YS0}B;MbqB(mg{I-i1DHT3(L%W?kVFm&L+By)0!U5O=X*zeiJ8xy8qc|D%Azo}{Jv9Zc-yJIZ#_R(N~2zw zq&|X)a6QdWV0>1MCZGQ7mA;s-;Cgk5uey(5ww^}?gI%9eXv2gy&3}i{MtX64}cP42`KwtiiU+or=tD&6Eq~L8h zZMCI&0i$${9YY8*<3Ca=EwtMCN5i?kKKL{;H)r{Tk#iBQ;x1;A_z@Wq$cKB-0tI8z zqkzlw2jzwtAQ=sd!JN?mjMl;$8Z;(Y%nUA5gD6vc&TobhU7#N_%X64JOrp`@^yCzdb=2Khl#Uv8|5LkV{ePsZm(h|?D@39jnY8B;jY9dRw-ipi&zCGv04fZkF}oF5xN9~28n_d+1GYSOma0@k zx#%aA_{FYNK24|mq!8{>(K46w1t5vaOdsfptrpBuO_`}eRWbX?;aEeOR9?j(e?ClW zrdDGbTLoQpR-Dy7+Ne9IfqTiTX17?Wsq&!cTD*v-o)l!YOH6FJ*pAkfODYh(9075I zbX`6nFw1vwN!EMw6IKD zZw<7PB%K---`VkHB>vF}`T|81KOD>VA&Snc%St)cc%DZ-eSdrltGGUz zRg^?CLuoV{3jLJ(rz$}+11id*nE-=1<|TSHuW6NBtxK!eoHFr>A&pn)S@Q~qF^ICR z37``$)A%~uN)V(PAuJVyrJll#HwFfJQVSZ3wNv6P$uD{J*^+`1xx6^K^OJ;d9qep5 zKDhyqd5A8xOV)P-6+z;@)A?ZP4}T?2V;dP?0e`txgKV>2N=MO9Lg~1G&GR z@caZEzWI?}T4kz~b9pMu}H(>R=1RGWP=?#Z|rGchGxkmPgl=&t1ASr3_-YB4^ufsm#a$fY8wo4#V`v7p5) zMS;P=)c?zOWKjD@9a7UgZoF(mx_<-j`-El7gurYZVWged^kPPQl}ooh^<9J$j#O0m zZ3*d%uyYg5zx584{-`AM91J0`{JUZgp$(&Wt8vE)4JLd*Pk>GDkm#L)tlvc7G{aG>Z3a|5Nv+*x$t==g;-XpMFTXjNb*E%D;?n22T0z?D_K39>Ljk_Pz`+ z+LGDQzCG&BE6`ie@ ztEF`t@x|M_jZOOVaU^$9f#UNCsPNJoGG&`7ycf+JeDMk`KpA~B3`HDo{#?~6H?0SH zc6W^-Ox&Nd4QZpc&vCiMr8?dh)j zW32bp6fKBhdf+~b@o82Ck50j30#8i|?lD_r%Tv>8)`&yLZau zDt`Bg^f9m0TknrxK6+LJJn0jFLLZYNE(_w)0k7ZP8NaFXf@zxc?4tyqyK8P0_EZo@m@wlwQ0(7=Ge2sG~0#1~KjD$>O ze&}#-O9g;vWKeCGqcgxSK)*ili?d$Rl7(~Tc%!TM5+RL!YrseCLL(o2ov`s6X!1u4 ziPvkSxF4dCmriyx5y^&wkH)si{8%+kmeXpHe6NW}#J3YblltOpiJ$J(!`UM`q6?`; z8c0M45|IyAB>ubY_{Br{w*346rNsXl_-TAR&6r7FjN^==n=>>fM~s-~5DrNTrAvyO z`r&{{G49gBkxi#8zyL#23P`c8neCwpnguCL(T%7bfkQdK4gh}P<}2k zB0{1wlR_q@CRUlBz>NV!Q<*$lamkSQ;ag-MzqU)fnuOn;gnga3qlxMl>7*YM!^~sR zmyEN$2dtWKfO)(v-4Y4jDD;^CWf{{)V~hY`F)@m7ph|s>lo+9;AfpI(4&mIq^25A2 zxyAUTlgvZ45_)})@6ys)YWcfjZvvO|kMdU8@A3QT;7{}7b+G%w&W25G#C5Rg87ziP z@?u~skAPY#_0+D+_V zogmhM&tcPZk?)4t23*!fnXmVPPD_)^VAFG{fKB7sG&}yWc6ifV!@aloQmmM_{ByLy z#>KdyP5z)PWXkdTLl)_#wUa65-RtmE>L@>Zn(td59!+co-1U`PYOTBbNTwnlIh-u_ zWhedpcAa{)z52$aXf z5W&*)Vw+zJx8w0GhQ`wg5ERGVg8RrS{ZuKY^Wwm?~2HNPU5H zd&{`-g80oyS;hd!2!xEL?Y`KXIO;Rxuylfnbd_;Bu@nZpQ>55u%Jli5;}w#XuK+le z#mo#ewq^8XFj}gn%T{pzBJO-N=9CKXHp$^X0zaiw#y_^hKap_xDk$+JfbBhybnj!+ zGzJc)E8?0=0ufgo(m><-3;^|Uj>6LSXcS?^H5x_OOew6x=R+61TIZ%s+vRG^9m5fx z%6m~h`UfY*{(jM8QR0~%6YO+^*@8y6FYJpqgyNS5W9(!zdLm*(L>yi26NAIV1vK4Z z?0WGoQc8mv?v|h$JceS-MKNaY45g=D>gI zS;aX$UTWj+XUX59jbxSXk+}OTk_kSzXYnfFU+bCWn4VR3#l5W2;ySgmPftQ0Y|tZ4 z^v75>v*|0%&`E|P2utO65*FxCc5S9xB26*dim~CfnQDo=jWexm@Y49A2sXukgM_bw z-46I&68->e>YJaC=+D8X`XS02D&+DGC!?rH;Szhbp>(w&T~|gu5~?1}s_-fGq0;4K z{7aF*a`H0ffvj6RRKRK~IU2h|x@}Efq;)WZ5i?`Hm^1M)jp1xONVjG^NnIylr4%^v zl@sN}TfBsg(&>bOC*6skbV*6J6K`Y{{~S0j*g$799b*t2^uX8%SD<5S_aJ$SW6c}! zami0ad3C2TJ9=8Q-6D2#qJ@#egV0eb*EtMjSmyyyozpFZd$d@W8g&g38M=xIzu94s@j$DiXRpz5t8$2>m4S%*1}wV_KJ&@f~ne`|Yp~!D}R%7C4*? z28#VRO$)>spY58nEPobc)3`*&X-$FlHI)_3E6&KKflkIewC7g;YWOMjqb)Dgx6@eo z`zhi%p3Zn@OzoI_UP6`~t`hrk1N?RqV&RbQ+@CWCvRbniyl8SP(<^k%15W(}pM&sKI>BbRYQ1P11Hv4< zVCQ##$YWURK;Cu;TMd~s{;^LR?#QuS3YG4T6_bKjLNswROyh6=BO=NQ78Pd{1rEZO zg>k!PfndPGp#fL_Vd)*Rm3eF`kFw4qZ0=(Aj8WY4glSVAwm;C_$6^&`MJRi5ko6{j z%JT)@M?&uaalaXTv0S|O&Av>__pnO!k)IUfXZxgg8coNEhCn``#eHSPx%1|i4l;NO ze25z%7z{%_MIyN)q_>sSnuu+)GJ!Kur-mS1@_vjPP?u=zE$6g&rIUS53kG`CEakLP zpWMCv+;%{JU?koK{-aUV2tE50qYo8&ya4A!4QZSHk);gs=L7>0p45D z6id1rFGIjxmg2LQFR#N?O1%4BoR3*Act`q_WrOY;H$$cm=rk6zz}=`nE)82G--2aZ zf9U>1wjqX(*(jV2?iv8idkFX0hL`DykTV)Hw73&jbUN9fH%jOH9RD^ zC_9tqd0)sTAS3W!{Gc$H@6xhhx~vSS`5`SE1sccw^9wkeS<8+h60T_sx6I&Wv@!<;^|1@VYRk2&gX7JOW}N8wlvP?1KPH=$UA)Wnid#e zK$)kxn27tQkRH{bQ9Y7qC5xqYgX+gjbnX)Uh8u3c#dP2sI!)#;&GL_r(*{VeY68r74ZH>{%|X7s?W)Q#Ln)#=w`S;CmdjPT;Fl(9VE13AAbj?O>V zA@jemzXF^Fc+Nzg0tN#n0cHWN11tmF2Dlfn9qPv(_8aNxO6qo$YQxqBwa(! zZgk-{M6)tg9Cqn(F4o@#)A2Ygqhs>`O}%gpB+DTA2^l5w-n|4aV;Zg+CMls5Lg9Oc zxKprdnuPBSq~i2G;f{ge?NF9Fbj;*obkfmV%mxfXR4QF967>_$# zi}U$4t!RBz;v6NKJ{5wYWU_bxKC5&|$tyvi8GMBPkxMETn0UCAd}{N#{Sq*zY{O}v&CpI*^UE6t0}C@RH8o6+Lcr|f;=OD@fp ziW;jEpD+LB3LYxTVn^3hx@elRn)!-u1g3AYq%vPcEHUyF5IOOv3OR`fAYaOlJ5pIR z-&;arQrScbM^43)idrJ;&>K%|A@)Yc7m}96g?Vf(FYSpK{)pjC9FL=ygCc>=RpIt* zxkBLSR4|YKm^R z4GT?{UW=kP)=F$)p*-QKEVz+ES%Z8pK}s{SDNUFm$4*O(O$ZC+H{`PC)JcUU(gnqh zPvu1xgNtzs=iwVcSkBGJPi3n$$@2>riC^Ji>^5NHz21ELDTL!Ak+|8HzDVb2Y%SzVZgpWJS!B!%d{#l`@L`DCwr!#U!IF}}6daR~fc>Mm*}24sVRan2vWk$d zSnkS4n>>+RRCL$~hFhtr6-%Gb8|C8R(tXuzMl|l|PKm!dHe|R?%l7DJTMbgZ_eW50_L-@!;H0$wFhEy03LF|9~JVnI&sJk-wgf(-i1S32ev3mL_o zYrVo)_ELPgguVomJ`eIGE=Mfkq6{dMk3F)SlicY>d{Kzr5#mM@N+BF6qOLi#gNXJK zq^B3*Bj?a0i+0vnG3eD58jE4Oz$J#Bz|xCxj03OKiqlIKUy-A1NJmje4CyqVr*FgH z&AFUrkriE228u4EQEt&^IJgojF;;#*IO#OfCO^>LlTg0TldJm*D=ZvULRRTQ7&e1G?@!Rh#;&V(f;|MypW&}?DC{5r|mfC zDJs3~{juhfTc~8P3ooWz$zU%53${fz{#R?SDKi!?!M6%{XNPUGc)w0P3hSn5t)w;s z%~h77FG^0p6T)yKo0V(gOJaR%w#&c z4rX#dr?Pdg1G)zS(jiUR$a08oc0#XqLa%W`w>Y8m#Xu=yWxTYuA{!-La6;EPq3c0U z!n({JEZ80w1u-8yslcd4Jp5J6YXchbn(r{T?a_!&QoFKkK8?7gqbpm3m-Mo{#l2kF ze8`sZ8UarZ>9yj0;g7_~_@sWWOr_wzH7Rjod(R&9s;Yhbq?l=9OQK@#Q~=V7x8=a{ zD4KLFI`0nq2~-CPw`GI5Fg_+SW%1^pK94N!d7$&^U-l+{kvyuRK>woW(y)O(H>x8C zy6<`5j{Dj_myw7&H6BUyDVi|7Z=wDRefWxJ<|l+}2l;49|5*C@xpR-FJoT@8H*Y&V zzHC%T*aVOH*M3yKao63Y55InL-q8AUK<^)Ha*w7t10rS)vL5D|Msg)PyM??dk^+$mkDfTKknKP%rqZy-zk2k zkVV|}c2CoaO+4%;TEn5=sw-G!{ux!bv6Ej)`IeLa^e`KOPQ<-$yi-KmnLpm~>KVg* zKlJoryWUyET=zfpW$2m5O$cYy8ixMBH9FYNEF2VF?aejYc*uMFOi#VV<9uQWTe-)Z zbel1cy|J)QkB)5D4qV)!?bbne-?OkKV9yZw9L`5b6p zw(X0bzw}$0viRZOpT6%Wl}i8N8Nd3cwiiAc63dcy>|a$r`}5B!s5Ff~)dB-t+2hhTI$bj`3xk-uce5ZpZJxefe*B7nwUpV_+ZhrgC|F1+uPTfST! zovW@|`u+0{OrG`FkHd~mi25rDjJI_)HEl4@#O_G zx_*;Ud(E2gEt*MJsp9`y{ZjqTZHK*db%B$1d#fM5T|auZdX?WTx1NnR`>Yst&EA}v z@+oG^fAqgh@a(mG!$iME-M#*&u3B+AMtEm~xxw^sJ{MrZT)JncgXxT!93Qt;=$*% zr#jSo)~{|@w4pBi?$4tme~qn4d4K=68T~(~?NdK7e((H{U(fzB|Al#HXIhr|hTrv@ zU)i~DzG%4l)RzqdPV}F$yw}_Hd)S}-g!uApKc*HIcr5d7I5q3gyVsuX?|PO^da=Ld ziG}$dbsZ*5SswFUe>UxB_ua1qSjN;1{qwGvFS@SWZ48Tc67CdsQ_CQWRQSgbC z%Q`fis(Wl*O5Jwmx+GQoepP^F6tQpK%O-V!0#AN9@2z!1m$~YnUSsOI`E>uDdsP*) zZf8@LXMZ<_z3;Q)Sf`&$pXfYg`MnlD7C-AyL8k}jrDkbop5C9(T~)E`&kue{_&vrH zFyYWWSFy()aj!bQx}DKQ|9D?@L-t$V!w$AHrCg`|@A~?kub+JXuP9UGeX5Gdx0`ot z^`3QT#(%r2*WS~UJ$AQyUGnXpbf2<(amqsGf7sXXmiHeAy-mkM)I{s(B9W# z3H$w7|3siSsH=Z3i7%g-zUtLEw=CMU`gXSSLtm4w?!`X+o?iFI`uZn!?yY*o$FT9V zrlzp=K>foz_m2Kyk5(ULbTj{9@g9F`kZSYbQOxMoUipo_ z<-eXh_Ipp&bJ|I-PGqM$l+QdpEXVuF`bU@dH*a9?ec~n@vrI@oed?=G>W;J3G1)y$ z%l0??wZ6RTF<-+JQ{YK;MPcotVSg_Ar8h)`-+whb?bT2}rGCz`iTcbbrvAsh^$&iz z<(1>dUN47AHNp~2#k^W?k~cw}=b^jy6}Hu{{@Ja=CXxt06|!-_n^&2B+h0EHM8fT# zgns#l`@uCx^T~i4+56rN&%SCo7Essc@IAgO9t~1iG`X6Jg|({#8jc>+uFOn4(c7e)qLyL2?29@ zq`URH)z4JAzwl+wI_do<|J#*K_{vrI+;Vp2=~JgWt(g7w5Y?G3!`O*c$39wLzVY>w zFL!w+?3M+tN6(Hvm>M5ew;;ajPJDjjuGjN+?%a5K+}AAp&0mI?hVMUB{#L_=*YkpB zsEdN%=wb*sG5h8x!vg2M)zGCM`)>JdXYP5mec*SS(zkS|_53FI&tvQVxNDyA+CyKR zE4TQ}Y1nw;k5L=G9aVmV*Utg(JW-q6Fma9fM|aa>zwQ0A@IcM1FQ+a~pYYk#74Ez7 zb<}Upy;I(O<*@0&e=h2)KJ3eqpWFNAj(+N??xsO!58U+pnk^m79%{oa?q-$RaI3qy zo2n{KYgoe;>$L`S8j)Iqi7k%OR&-ZcR=ErP)iu7p`T<(=kbWjFchkHWcB?NtwT5-< z#{%4aYcp@`zRg<|82dv0{qDkGbyCNErZ?U7xj)>-hFud9$0nyN*X|5B_w??PV8#no-^}F)E`g7ea0t*<@U;X_0oxAS+d}g})+!hL%{Q0Fs$cz1ur zucN@8jrUtIF@EFvf|=iLT*r#R!X_g`rGbD2Ya1+|K$CK zJ3m_a{3Aae4j4B-D0AH`M7WlwR(87!ngWj`X|)6tKKw^bp7m&@7mY7KU1a^!qP*!eKx*u=B<7i|6RwrofcUiE&pcs zL(8=0TZ=QRewusuYoGf2e_a*o!&V=>W8ZVLf4M97n7gTDYRC%}zkP8g^WWXy?OFTg zt`X{_ik%JHss@LrjtlvCKiUNB`Zsr)ryiQ%JY3yZjXGYdYvd zv_0)q+q#7;Zuk8Bt4wh|D+qdeOFG~eZ#gzaMVjw`c1Rr~E_T>9Vv{o~&!6+YgeayjCeyJYS7aLmV8d~9OO&M3o8Ns%#uK=l9< zK*a?7!eD;+zhDmCz>)x!0E+|_u!aAHv^h%y(x*&w18_%RCO&5}{%Q19rrA+G)F7-0 zfEAK|mT5zp9pwYjsGjJrX0vkpLIjLMo#d{-KNvC@xp$!Vs(=TfD)8nVp*6QBs72ec`!wxl0% zUy3wS{!tn$0F+Kjqu@+W_+8fYBfg7~W((v{8Y=;m#w38wSsI(8BitoVKj{Xj0Mwjk ze3Zs20Hx6Y&;u@N{|kASB>j-v+B8>#m(odTECNs(otD?;p5=x3A+C#-e#ml`<{J1> z8Y=*lPD7kN1M`5=>Sl={BrhZx7u*J1NStj61AXba%W1dQ zy9$2#^O65gN`DJ!SLQ_xcn!qgQeOO1(tjRlSLTD|e9dFisxt~AMTnVrMWWC6p)RG=bfAC+Fw37}>xsKclJ!O5* z%eI#ZdDQPXl2KvL>j+0!9iZBY3`cUCr8$a2No#97N?EcSGM(iCrAv_c>}~i_+AV-) z(XW9zf}8DJ|9D5oEb! zw<64CZ~v6~$!_S`TpqNPZt{27cK%b+FFmUZ$pf46F6XCg|C7>x0eR4*yvym9?SESO zr93dTLT|I2#^&r+$hjiwznli>s{>G(ZcUvx$>E&Yt&!s_tW0l>jOKV`IW5_caXx96 z^T&*EKF(w}rWq<;ab& z&83~vR?(b%g`de@zQRw=t0uO67<;@mGMeMDm#4%LuDP^V!(SkN*sbjwZR$gFddYrD zeH^)Ez6-S-$s`)&HJA1#;~DU`HV-V|)k|?SdEWNvAim~|J^%UQj$}iIv$T`$*73W2 zSopOz4=CLxz!jH%=;SQz)$kMS(`=7}=X~)U}=p$_B<`cZ_j_ecuVpxmOu2OHs!qYpr!cFH@)`!Ey=%_ z{^ywoRp56z){ynGPtW<{vYg9hw~z-^J}Ll0YxOzb^xE^cHlB;g2OV?(N~_#=)xb^t zrPH~xv-lMCl_TM|segVc}&3Q89236jk%;zvA0hh6I@ z+7>s_uA$vfpqnMzB-tPmowPY~zuzGG=G@@Oj5^dRE=4bdc6Un2i5n(hz0rKE!uVEqAdo+uasX(o98m<;sb4vvbll8kdep@ehqX_gbrW;$oE8; zaPQ!iXsB)js6D4L-==bZxzcB+v$HYk71eIFQfEhLsXuqER{1 z%knRUeF=1Sl$L75W4KuQUnZTKq@ykR|6MvGUTZqeSO1HoGu1~kpaMYkQV$SF7uZ(a zTH|hw{*a>sP+XSQ$dq`9mvpQIm;gxt>XMo@;JGOJQ(S-wKurrWNyjPx>1Y7x0TzkY3f+}uxdwEq`^~mZf4BZlbXTUs z0-j1mmfJZ0PW@Y^*2YiAfx-;5^q@fvEZPwqJ?B?j_n+9jH z9OZFyG-q-ygnmA0a3;SwT^;#3lXIc;R;0lKo(gC39qHH{&6%9G(4C}#+A^x^&9({6 z>FUU@EqXQ=R??N~ViiE&9Iw*Pk&eyLlwq#~cXPTr^1BjrR_fqL$L46tuvdb+IbH4i zsGl`l2|6ovu+z~|Useeoy)w*|YM3{-8GUTl;XW`3rhQ=aFtNLdc0%!eU}V!iFtTY!64~XF4U6O0 z1~!4{kn1Me7L91vNVb{VXB$l1u4!PRy2qN7d<0$0*9ME2&kesI-)Wx~K@vdT zr=`dDVE;}-WgbB743(wxDo>Y6Z#$hFwTnc%to5~(Iyus{24PJApNpMeZP3Y)opm>^- zMLJXgNCyg|mvv~)248bBt$s=w2%`g304#RltAUdqq=NyV2ehect5n2EZhdoUQt&qWoST!; zT0cA8l<`r$GB}cRx%6vBH>;k1mwv6$jq>SY=?7T?fZ7&oJMTy~(ZHiDZ`Qm5y@}hA z3`cy9XmVKi85I5&xRYc*dmDbO){SJ^hbLSSSCjN8{gh!H#9N{Cm*hIrjnYKWBtCl? zlAI=dtqJQu$7;}o7IY&X9l#7|67R*-&xszCFIA4>295HQ_rs&<}C=IM9urX9Ym1o9re(K`IZI zw0rR|K@o~{f-Zusi~KK68b96ZhCqmAzNVF|a_!x`=mm}WR#sPh(FRcIw&4t11qndIsz-E5juBF#gz|HuDP4^R!ZINsf^CDLr zbEEqW=)DxT5rEs}lHJho9mg9Q_DQyB8Sx_;(XJQmuj@p6U#)1@SVY?*h;}U#IDZ|h z;dZ^s)|TlOiLXWqXO`s1a(|WLL3(WUXfR2*tmmmZQBN^F$QLUv=1W7Jm`@FLlyCHo zNdV{p@_Qyzvn?waFM`2y^#K?FRRF3Zt$N;Vi5hVTfFeLOKv^&C-50GsARZl{0#MUJ zoc1~pPGL-d^LirSPXbf|EC5Gx&zsgHrmhn)8gq41O6*aLb^FTZWdNiA52oxg~k_`PCAxknK>9mcqBy|9>@pq{|0T4WQ>o z&)s2N2Hj!4%k&G$Uy2JraVuqWJ?!P#@hJJZ+n&EA+)3P4x%T1DCw}k>_TiN{{B?ku z=42}Q$=w_;`N{ln(=((zGy|GEOVB88^0%hdkz1B0+m3jYGzDL!f===16@Jd*CY^2c zk;BNgy}vy!^N|fdr4A&Quha5*bSU@+~hj$dGl4j4}T3n$6kC$*qVU=+?aytrh zF=>wCRMIYHT#jTZ<5IY(44VKB^URT)3#BRIqp~n$PGRLK;@@NcqP9h zf1)XQoVmg01F(V`bZw+euul+{q@hVhw-XB0g!6M4Fsao)a3Tt0h%q@i@eBY*NFYv6tB> zZqH!3tb~=Z43>xJl36L-*`O5yi^gv@GlI{ZRj3%d8vevHAGAEqAA{d{T#o#sPHM+I z*~18dc_++GY&x#m$%gz=NG$-jz*-Y$Frz=Eac3sT?g`l)nD0Qw@}YMYq~^g+M;yh_ zb{>9>z)M&d3$+GTF*oj}R(4N&$`QR@Y;yyn7*jJHa*+JC;r4zF3&aGOu=zM6s%3&8 z`5}j0ST{_Z$!`tj%dX4^G|q`u+l`IQC@C@KXXY&t7U$;`l#J_FR$LHKk~QC$pHUK& zpPN-&SW=i%8kAL-ACXa#AG|Q6pOBwXkeg#HDV<>~F3Bw{7}qZ(Sl4fSdruFmtoZ+H z@7u$&s`9oUIT#u$7AY1PDjF8aUTd#?T6?X%@sNi^BSj-M1p&iEK@N(Bh2{ZEjm*@F zJe!!7c#I}ZOe!78@KBjrgN>(>N=?&ACck?>I8ERCe(!g^e}32Xy?H zUk3c^mEDF8?wOsQ(XHQv3E4w((o^#@ayv%lPszd8OddNyr5zm+_ph`6>wW%1q-W%% z<&MqC$I+ajgQL8ML>2fS5S5vcm6MSx;{N<4-nr8=axy01%xP1+C;a>O`Q2{?$N$Iw zhx`5cJpbtekB^;@o;^9QThHwA_d|F|NiU$@LCb~ z=ktlUKW^!Lqe#ukL4;Giqx?5-t=_sd>d;H@;EeqIu@j!kYy56LIgiSYnfduSJTC55 zBX#?uk-DLg;sy`s7e^JM$K9%se?6e_vCRaYz|(WacAuP@n=t_qa1t|e2V_qeo1dLK zl*UFCOi1di5LFCpr1nzx>bd|KE>? zrzn!a4{MZ-N*UQt&XMMH9o=GY~`{YG=UHY65C)0^_nJe60?kX1#1alPPqm|+)3zWsmGUYABM<$YYNHA?d@1pn8 z$@DypR_kztv;3HJw%EQVx${FQHr73AiQb;u!M>o-0 z`W?MOyQ)3ZD{6xp#O`IC*<|(|JE(tSoH2eh8jQi_V)JXO3BQxK=L7jPIZMu$XXU-_ z9M{{BC*s+WB$;d@Rm6u|#8FP)qi1PT^&z#5)rkAzQPhz1ZF@u82M| zTTYkrj^r6_e3I(Gt`CZ9yNd|Y#3X}HnJVY-;LvDhE=?xpo=OV*#|vtQXJ?LBR`c0}u}zol{a$DK_r~qL;8>zWF6T`J|U-wMK`fS>@;hpwbpX< zxAh%*jegi1VU4%uSv#yxtS_xJ{tREuD|vxE-^Rl#5D$Eer&rjU_}Xd4Y_kI@b(zE; zRyF?Y1i5-%I>9RsGRj+kFY_A|8VVDZLYRX3o^PH`Np%x z0^?od7^1cj89!=%Yx=AhD;;s$XMJad@D}_5t|Ir3@-2K9|AwFCzwsbD+U{mw6d{P; zbXg(y$(BwR=V|8!M|Gv^t82uLDay;rS#)n-bnh~;q8<{8w(;iS`2fE&H6^N<1QRL_3E#vz@n` z^N!DT+@bCgceneS7klXFEc_a!>_=7TbSPa)E9g(als;;<`nFoDPSIZ0&T38dzIuwj z40Uo%zt0$E6dQ*1sI|tbwweN~M(}*TgMZ8Kw&U$<=%;i!Q+^`9m5~l}COONT<9I7x z64u0z4cmYW9Y}ZbJb8nBO)e3Y4yQ}#E;^aLgo+H(dTS%KGHsjotJYp0rWfm7&F;X( z9p-g2%o=EovDR6iTg|z`Uy@aFmb=3}>^(cGiEkr5Rw##*b4mb7B&j49b@(ayocu~U z(FbV{I+#95vw(23=u31ptx%7vKd75oEeq5LvN%oqMEepqJ*NMp2N@AYjM2|XGF~^{ z0{?VJK6|1k$6M2^xz=medTXauW1Y0>t@(T{-_AegU+}^9N_#W1{0q7@N<4_D4-?nL ze7RO`mwSM{hSSG++zIr~sx( zZH-RGV@9em-k4@=2SOY&I$N6cu$61g0J?o^-L%^B7~orPK7^0q6Ycly1NK$>H#=B3 zB3HaBmW#dOGx3$!BzMctrH5Mol=nM^)6*H^WH>lWd=t!w9%mg=PJyp}Q<{^fNIscK zHj-WBGjaiS9}3KBU>)?a`ZM}kV8wR*xPDnrHs%_i8mEj4MyUA?kh{M%(b{W$ZT$#T z_(j|l&17%+tn-eu&G98R@iDw(yRut3KrWMikP&LBx`;3_+>UDI0Ysm3^*W~H&& z_>1w0aT@*bfT^4D=14Qs+>A~3bfO)Wx?f(E#(kGCdUt?dr>XgkY(7g;`JpRj+huh@a2g@_a<#a+$^ z&M7aR#f|4~qTH@Lrv%fMv;dVgOIxJ2TZ#`y>8YeBPb5CZ^Eo^awpc!`0?YXLH&2te^I(_Nn%R z)=Ym)e@dUE&(&W+{eGzbsz(@ojDfi6L#BaS4K}v}oj$?M>dkBBT5FT_q1BQ{a1-eK z3@_#j`Dxz7?g;#N0sP!rtP`W1Y-h2v!l`zB6-_+)@i8SsnWAh_K2t)`-|wKa+tazw zRR^h1PoX;QW$CN{7_t~zt^yU(Nqb031zRlDwrKBbAAxDV)gIG_>r3@jdNnfPGeV3u z#(jnYEfR0!A}1e%fm@?yrkc;20jTIgs|~*oNMrMOaL8!>9ACuu^IHBj|D6-tw!NGv zqOWM+W@ZRZaXFpsn(V@|ZGA=|={W7sw)X(`6DwJJ4KON;gwm9i--| z*Hj;C%I;>fSUKCw_OMUc308-={>++ag}{O}`a60h;(1sTDGIwQ~g+-#E!6mTBKg4&jyO_G?L9Cv&1}L zUN8ynGYe|=M?Mm``H8qH66I96T<(x{GTiCt40f`dHO@gN$h`xq`C<2}pKAhq)i_T} zbcaRz(*imbobob#gT|=6)q3@++LX1%M6r@pvA?q8$mKuSo!Y&ctqs=3X?fZl?G3F$ ztJDJYP`!ixpuSq)sPEGE>0ju7(=Y13>314kjP6E%V;f@eopIgxr{S1MW-iXW3HW%$ z>}K_`Ua`KnezIEgHoPAn#LMk%_Fnt2eagOQ-?UpoEp`=}=q?6`Cq#yrD5i}+s8b9_pG-_UI)JITI&9tiO3fM=B$(jOCmi3#j5W|VMt54)fBVq?)+)7gCX z8fJmbY!}{RH}g>pk>G^g(*Leo{ZHhZr+3>{Z2Ln2h( zA-|F*<7zWVJg%%)j$q;%gh{Ig3i2uqRHM~yYJ!%azpHw{VFu+IDJulsZNeF-Fd^=>g;uD zoMX;zFZVf(?@edVVUB5vsjHXP4=S)L`m2ZT0`FELXZM`K#+;m=Wx4CuRdy5-m z7NJn(4zWRO!~9z-T3~XSfyrf=TrYb#{c+|r)ax`Ty_cL1Jr_%Wl)qBo)+go&Zk&2^lQLlsm!v2P*0~&KD#WiYjqb1WPV6WszJU z_sUB$*lFt|I8&V$ohs+D)7*`8-*ESPbJL2(=eNT2`=oMSxd$llG&prTxk$QVR?Vl& z=>V3-#jHir8&FSEmV5_^8W|cstJ!7}?aH%T5KkItu z%2zg!J>-7ciN|q==kk@vykn=?3+*yYhTH9G`-uIWAJ>CLxacHiqi@!Tt>Uj@G?bhd z;gQJBBt#d_t!;d6IH6=XwCw%R%q8l6^*8k?_A;BG?a}H`7e(mohoIkHF?K;K#hdHE zgB`44&=cSDJMH0ekvuFXLfL||lQ5YPIY-NrziWHI8FonDT58)~% zuohZ^_Ko(tb`PHXh&hMjEEgO5S*JJI-@V_%Pxr2V3R6THNulZLG~*p(jdjktWVOQG zdq6K{LKDs7WqdPlZP(fN0W&NS>BrkZKM#CNmV&1a0Hc4WacU;+_Nw}(S_Qx4qAH*) zW*XO^{kof3=6rKKbk?)hY^#iSwtZ27{yeqeeR&dp8tP>MU(Pr1_xN7^Iscw3_H&qm zmcYlU!aRFK%#lar8F^Lul*aEHq7X9;csIjbfSKkkbBp<*`B(D2#lF)X8?)Y%2=5K zZt3O>at65L-B;XC-81k_0{y)iuBggDsGN(Kox{LkdGtBDm~NpT(sT3%4OOF5rVdl5 zs=>hIC(uc|aMQEwCw8CSMJGmky9*RlPtjkbiAw*}aavxHE1g{E+(5t1r6dW=d6HzY zGVM-1LLaKn*3am-K`G8QUNjCuRSfXECnv1VP&@_vdA^Px;#YZ~-QMPQgB=dc=_*e+ zzT!Y%IbvQz>PS8LowUTn{s^5x7tl4dySiJgQCmQ(4}_a`ll9axv=VKr_LX*03)9=_ zy@B>)psE)@hZ$h}>8Q-Z#^b1?mF8#WB{LezYmk+RX=|nRwpC|^LL-iZMhvsR2PXZ~ z4iIex6|U$d`iU(-!BarbUqvcr&JZUYm^a5QbzgUvyMOWK>e4`8G0xdUiBRrUI%39Y zK_Ur*Co>!;j{qwD1q!4yys1m-r);*qTR*5zG?J_*!CvF6V(Se|n;YSX1oKXua2<2j zW`2}s*b_15`eZZNQa&Ju%6vF=FUXf^Ydi^!BH#fffd4jG@4>@5f^1CVv-o`A z)dl{tculMn>%|Rm#c6;t33VTLN4eA7FTD3v1p0Zr9qu@Y^i&6^Bh)c!f%=@fQ~e2Q zb1YEv7rjBhVFp>;9%kp-Gwc_ExLfUAP!AXE-|Z007~L>qJR*`%McHDycoFZ~0|q`0 z-|4bwB5#+8GFO&LUsa%gcAN%;TCA*4Hos{+x{u38=Z+nP63Z7%3{SxN+BRFxr{j04a79+)YF&TVN zikW&n6!u4Anfw}D*vi2V1^fRC&B3G08sY`Y%A9P+d_2^x2q zRu0#1k2YSPrN0V448qHR#= zE~eWy@H2O#_RgU@Tlp1S4=o8jx(Mgn2_NJH|2yjJ7e2tg;Qr#?@aifo$X9}oK-6(- z=RFPjUj_btlD z@qh9dd%69U-9rpQb*(}VpArF3ciqAGQ{~HWs_SHgL!ES|)Y<2J=Y+fQZlSvn{fq-d z1^KxtpO=EU)__wE@D=vQ_5jfZieZo(DJRHh>+DT-3sEL({8~B4 z&#gPjP9Sn9n*w?HgM15Fv$!@l=IbMbrk%tWnjj4%}{HG z{jP|XPs;$um(o}ZFKJ7(rPr9eUB|(1w%2e8t4n(5g zpF|~WA`%rhNF9y6$};rhWw_=9j>Kqaq3x_16WDj`61=un=!gfkzrhW8MSlac&s9Ai z9_BIQvJq`2Vk%o@o;H6n3IB`-*kSPHkI1{72cWrTIG;N|!>MTICc8QAR=39en^zCT zL4JG)Rz@jL!5LUc_tOUYqPkiwfI|Ni=z0e8S3B)>bB(#x+-0`r?RW>?6`q3>3*{Sd zf;QlOw>vMpuR&$5Z>;swAYUvV9Rc_2GWiXYY%BP_AJYr8lR8gbq@GvDo3~p-?B8W` z$G0NLXEyQpr8zY3M?m+3$+>=pVO^{GwOQ1uQq zLT!&p=K)nwbyZ-q)K?v-CP5*j0QFa4hNJ9BmWwS@5qp!Zf_MBqTaLN6iFH5JNk40d zm0?YSfcMLw$bSF^`0O_DlAo~0+j-b|t+w}L&OB!C5MN@R z^T~L)d<*0fStd7OHrNM;@e=&>;Z6!BnCaMxtaEH^{bb|aI zNi*e6r7LC{sq|9P;W_0flawN5hB8+vRhD3Lw-&p>t;z@3VjO@cUWc991?4Kd@mAzM zOcy3_kroy;Ng$tzII%Tbpb$YwYMyWkP*hfDAUe1cPO3VwuF z;HwJq6(M&=p@+^RTi3}7b)#AVrmTW~iC{5|F_Q@v53SXgjlkwAi{)T*Q^*#vGWa#8 zS%j9Nm136Pr`2jPx`}=p0li-ehp9$CtzUr$mV_-u5hnRMBf^ZrZlbT12nFjoC`Ir& z>#?H<jP!R#vRfH)7{HkP;0`ASiHlhT4 zwp5gfaxhvIy58F_ofjA3TsL4t5+S2x4D_lg`-1b6;p=D0ELkW^!2U~-^K$e~6|!C< zkID1?ZEO&>v7t^FbXcSl?I>`TOh-7qoDohfCg@n#bkBP#8?#f8?>s)jpv$6^7)4P` zY(Dxb3DBn_Zsp@5yk{Q`Mejt?C>o94VNjU@y^}x_X%e_C9equ}RT zSQv|7QOKTx?8PH<`KW$xi|J);4R%P|uvM;RH7pX&MXbg&ff+sl({Mhvr!%pqT7>Px zG0bkB2Yg-g=^@xbc%DR%84A3eX_Z;q;QpVs8mw?03vKFcKjwjpc0w7}W4{!Meo3)? zZZUMIuP(^5zkM~>vK8SuGf^FjFi8Z#b&NOqVt=y;oKt3$!ws&4CwB!7N{|@>H#owK zHe*a?nwVAk0;`kFbU2gwW+6Pk5_6Hc6o^)iU1uexjeXdC9RqHjhdUI387anMmT3tq z9xAdgbYvowWU@8FO2KX{6V;c4`YXge%Asv5vCF8!9%mo!R139z+Pa9F`B0Y;@GBat zF4B&*8ES0=-0vdjxk79rkBZZ%lPms8@yQ?=BEwNHk*JvHTQwtq4!ux0383&1(R|hXVl;SQ0ym?Nq21u6dPXYU!vLQ;$d2 zC+q2YrkEXS^=T41H61>E5&CqISRpow67*XwT(BU2k2S_H*57CGh+;mXScEvvLmU^u zJ1=)CoJeC4(0k#og{b5b=(}pn!zpkOlkrY(3tsM&yA{aTMX$@lf_*i3TZj_o z?{Tlg6P08oQz=CDN-;51;3otc;O0kS-!zYuVdu0H89NCq4pGA}>&C!`jK{V=8SX<4 zG(`oFxmK+M17B3*{ax+#wAayIKc565UttX_)Sn-(uM^;Hh3nDKqTZ>KfX-RSke8Wy zpmPGyd4!SfN9dWxJapn3bm2Dm!_`I&_V5CEE5r;~;_aiNg8g$`xmt;+9K#7b_37nq zANBz!(eS1sD?}+UpOL^h^SPm)i_fPB6AccJBhQ^ zBR*Gvh7G{OP~c%W5HS*%7!6GPGp8l7Wbj%F_9h;;6(XX=K*|zeWhvsi0%%!|=vE-U zRfzCD#JCnc5Qd4N2-Ctma9^3W0^9Ej;AIe^JOUN5Q!g|cD?SSjXgRR568I7XmWu|b z)gV^&_{ok?pkx$KMcBQ-Uiql}Qm|JwSnKF5-l~U}eFffe5Zq&ry&};UndpVWTivh} z{ZK9{{Jd5DA2_R*Op+tOOUDr9zCf5{U`+a-FvjbRHO^_L-nrsj#{?Y?4^u#;B%xQb z+E8VKbJj4h4@g_=1K*iQ5CsDCi@beUm^zvg(G4>DjaGYcDGYbNFN%v>w3h*OH z4S_-nQ^TRrB9WQ|* z>~2)Iq3Rnmd|i!ZvB;pfg-0V;x}Kxw-@+Y_J)%qnGxrL3jJ4o{dhkI5w&tGay#i=o zfm~E$Z|x}$1zY2IuvcH60PT?k7E4DpSD~Igb>ZQCJXoyKu0j>Z1B-V0)j{nasBikQ zJqf5@B#ZI$MWxUKE96GZ3)^IpKjM|nP9S+T_P@dYT|*M$lTQn&FD2L)j+P2iLjT}? N{PutT`Tr~e{|o8s+tUC5 literal 443904 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°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%0A9)8TdoI|6;GG3~5i)v%cQ8QBLt|FyQov;x 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 VWWM(w1v!UrE)o16{~!PFe*tpjB0>NF From d53074babf60f0d1b9d93e6c86d130082184f5e1 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 10 Oct 2022 14:06:20 +0200 Subject: [PATCH 442/599] Git - Fix Commit action button enablement regression (#163159) Fix Commit action button enablement regression --- extensions/git/src/actionButton.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index ffc1e73361b..c0bd4624ee3 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -203,7 +203,7 @@ export class ActionButtonCommand { this.state = { ...this.state, HEAD: this.repository.HEAD, - isMergeInProgress: this.repository.mergeInProgress, + isMergeInProgress: this.repository.mergeGroup.resourceStates.length !== 0, isRebaseInProgress: !!this.repository.rebaseCommit, repositoryHasChangesToCommit: this.repositoryHasChangesToCommit() }; From 3a3177c53ad68897510c4ab5d43658de3372c4bc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 15:14:52 +0200 Subject: [PATCH 443/599] speed up tests (#163171) --- .../test/common/configurationService.test.ts | 41 +- .../test/common/globalStateSync.test.ts | 41 +- .../test/common/settingsSync.test.ts | 73 +-- .../test/common/synchronizer.test.ts | 201 ++++---- ...userDataSyncProfilesStorageService.test.ts | 21 +- .../test/browser/configurationService.test.ts | 480 +++++++++--------- .../test/browser/viewContainerModel.test.ts | 69 +-- 7 files changed, 466 insertions(+), 460 deletions(-) diff --git a/src/vs/platform/configuration/test/common/configurationService.test.ts b/src/vs/platform/configuration/test/common/configurationService.test.ts index 451a52e4917..0cb77b1693f 100644 --- a/src/vs/platform/configuration/test/common/configurationService.test.ts +++ b/src/vs/platform/configuration/test/common/configurationService.test.ts @@ -9,6 +9,7 @@ import { Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; @@ -34,7 +35,7 @@ suite('ConfigurationService', () => { teardown(() => disposables.clear()); - test('simple', async () => { + test('simple', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }')); const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); await testObject.initialize(); @@ -44,9 +45,9 @@ suite('ConfigurationService', () => { assert.ok(config); assert.strictEqual(config.foo, 'bar'); - }); + })); - test('config gets flattened', async () => { + test('config gets flattened', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }')); const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); @@ -63,9 +64,9 @@ suite('ConfigurationService', () => { assert.ok(config.testworkbench); assert.ok(config.testworkbench.editor); assert.strictEqual(config.testworkbench.editor.tabs, true); - }); + })); - test('error case does not explode', async () => { + test('error case does not explode', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(settingsResource, VSBuffer.fromString(',,,,')); const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); @@ -75,18 +76,18 @@ suite('ConfigurationService', () => { }>(); assert.ok(config); - }); + })); - test('missing file does not explode', async () => { + test('missing file does not explode', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject = disposables.add(new ConfigurationService(URI.file('__testFile'), fileService, new NullPolicyService(), new NullLogService())); await testObject.initialize(); const config = testObject.getValue<{ foo: string }>(); assert.ok(config); - }); + })); - test('trigger configuration change event when file does not exist', async () => { + test('trigger configuration change event when file does not exist', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); await testObject.initialize(); return new Promise((c, e) => { @@ -97,9 +98,9 @@ suite('ConfigurationService', () => { fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }')).catch(e); }); - }); + })); - test('trigger configuration change event when file exists', async () => { + test('trigger configuration change event when file exists', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }')); await testObject.initialize(); @@ -111,9 +112,9 @@ suite('ConfigurationService', () => { })); fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "barz" }')); }); - }); + })); - test('reloadConfiguration', async () => { + test('reloadConfiguration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }')); const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService())); @@ -132,9 +133,9 @@ suite('ConfigurationService', () => { }>(); assert.ok(config); assert.strictEqual(config.foo, 'changed'); - }); + })); - test('model defaults', async () => { + test('model defaults', () => runWithFakedTimers({ useFakeTimers: true }, async () => { interface ITestSetting { configuration: { service: { @@ -176,9 +177,9 @@ suite('ConfigurationService', () => { setting = testObject.getValue(); assert.ok(setting); assert.strictEqual(setting.configuration.service.testSetting, 'isChanged'); - }); + })); - test('lookup', async () => { + test('lookup', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); configurationRegistry.registerConfiguration({ 'id': '_test', @@ -212,9 +213,9 @@ suite('ConfigurationService', () => { assert.strictEqual(res.userValue, 'bar'); assert.strictEqual(res.value, 'bar'); - }); + })); - test('lookup with null', async () => { + test('lookup with null', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); configurationRegistry.registerConfiguration({ 'id': '_testNull', @@ -242,5 +243,5 @@ suite('ConfigurationService', () => { assert.strictEqual(res.defaultValue, null); assert.strictEqual(res.value, null); assert.strictEqual(res.userValue, null); - }); + })); }); diff --git a/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts b/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts index 20138fb54d7..110991b2d86 100644 --- a/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts +++ b/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { VSBuffer } from 'vs/base/common/buffer'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -37,7 +38,7 @@ suite('GlobalStateSync', () => { teardown(() => disposableStore.clear()); - test('when global state does not exist', async () => { + test('when global state does not exist', () => runWithFakedTimers({ useFakeTimers: true }, async () => { assert.deepStrictEqual(await testObject.getLastSyncUserData(), null); let manifest = await testClient.getResourceManifest(); server.reset(); @@ -62,9 +63,9 @@ suite('GlobalStateSync', () => { server.reset(); await testObject.sync(manifest); assert.deepStrictEqual(server.requests, []); - }); + })); - test('when global state is created after first sync', async () => { + test('when global state is created after first sync', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.sync(await testClient.getResourceManifest()); updateUserStorage('a', 'value1', testClient); @@ -82,9 +83,9 @@ suite('GlobalStateSync', () => { assert.deepStrictEqual(lastSyncUserData!.ref, remoteUserData.ref); assert.deepStrictEqual(lastSyncUserData!.syncData, remoteUserData.syncData); assert.deepStrictEqual(JSON.parse(lastSyncUserData!.syncData!.content).storage, { 'a': { version: 1, value: 'value1' } }); - }); + })); - test('first time sync - outgoing to server (no state)', async () => { + test('first time sync - outgoing to server (no state)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', testClient); updateMachineStorage('b', 'value1', testClient); await updateLocale(testClient); @@ -97,9 +98,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'globalState.argv.locale': { version: 1, value: 'en' }, 'a': { version: 1, value: 'value1' } }); - }); + })); - test('first time sync - incoming from server (no state)', async () => { + test('first time sync - incoming from server (no state)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', client2); await updateLocale(client2); await client2.sync(); @@ -110,9 +111,9 @@ suite('GlobalStateSync', () => { assert.strictEqual(readStorage('a', testClient), 'value1'); assert.strictEqual(await readLocale(testClient), 'en'); - }); + })); - test('first time sync when storage exists', async () => { + test('first time sync when storage exists', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', client2); await client2.sync(); @@ -128,9 +129,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value1' }, 'b': { version: 1, value: 'value2' } }); - }); + })); - test('first time sync when storage exists - has conflicts', async () => { + test('first time sync when storage exists - has conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', client2); await client2.sync(); @@ -146,9 +147,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value1' } }); - }); + })); - test('sync adding a storage value', async () => { + test('sync adding a storage value', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -164,9 +165,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value1' }, 'b': { version: 1, value: 'value2' } }); - }); + })); - test('sync updating a storage value', async () => { + test('sync updating a storage value', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -181,9 +182,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value2' } }); - }); + })); - test('sync removing a storage value', async () => { + test('sync removing a storage value', () => runWithFakedTimers({ useFakeTimers: true }, async () => { updateUserStorage('a', 'value1', testClient); updateUserStorage('b', 'value2', testClient); await testObject.sync(await testClient.getResourceManifest()); @@ -200,9 +201,9 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value1' } }); - }); + })); - test('sync profile state', async () => { + test('sync profile state', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const client2 = disposableStore.add(new UserDataSyncClient(server)); await client2.setUp(true); const profile = await client2.instantiationService.get(IUserDataProfilesService).createNamedProfile('profile1'); @@ -221,7 +222,7 @@ suite('GlobalStateSync', () => { assert.ok(content !== null); const actual = parseGlobalState(content!); assert.deepStrictEqual(actual.storage, { 'a': { version: 1, value: 'value1' } }); - }); + })); function parseGlobalState(content: string): IGlobalState { const syncData: ISyncData = JSON.parse(content); diff --git a/src/vs/platform/userDataSync/test/common/settingsSync.test.ts b/src/vs/platform/userDataSync/test/common/settingsSync.test.ts index 892014f043c..8c13c2cd43f 100644 --- a/src/vs/platform/userDataSync/test/common/settingsSync.test.ts +++ b/src/vs/platform/userDataSync/test/common/settingsSync.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import { VSBuffer } from 'vs/base/common/buffer'; import { Event } from 'vs/base/common/event'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { IFileService } from 'vs/platform/files/common/files'; @@ -47,7 +48,7 @@ suite('SettingsSync - Auto', () => { teardown(() => disposableStore.clear()); - test('when settings file does not exist', async () => { + test('when settings file does not exist', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const fileService = client.instantiationService.get(IFileService); const settingResource = client.instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource; @@ -76,9 +77,9 @@ suite('SettingsSync - Auto', () => { server.reset(); await testObject.sync(manifest); assert.deepStrictEqual(server.requests, []); - }); + })); - test('when settings file is empty and remote has no changes', async () => { + test('when settings file is empty and remote has no changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const fileService = client.instantiationService.get(IFileService); const settingsResource = client.instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource; await fileService.writeFile(settingsResource, VSBuffer.fromString('')); @@ -90,9 +91,9 @@ suite('SettingsSync - Auto', () => { assert.strictEqual(parseSettingsSyncContent(lastSyncUserData!.syncData!.content!)?.settings, '{}'); assert.strictEqual(parseSettingsSyncContent(remoteUserData!.syncData!.content!)?.settings, '{}'); assert.strictEqual((await fileService.readFile(settingsResource)).value.toString(), ''); - }); + })); - test('when settings file is empty and remote has changes', async () => { + test('when settings file is empty and remote has changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const client2 = disposableStore.add(new UserDataSyncClient(server)); await client2.setUp(true); const content = @@ -131,9 +132,9 @@ suite('SettingsSync - Auto', () => { assert.strictEqual(parseSettingsSyncContent(lastSyncUserData!.syncData!.content!)?.settings, content); assert.strictEqual(parseSettingsSyncContent(remoteUserData!.syncData!.content!)?.settings, content); assert.strictEqual((await fileService.readFile(settingsResource)).value.toString(), content); - }); + })); - test('when settings file is created after first sync', async () => { + test('when settings file is created after first sync', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const fileService = client.instantiationService.get(IFileService); const settingsResource = client.instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource; @@ -154,9 +155,9 @@ suite('SettingsSync - Auto', () => { assert.deepStrictEqual(lastSyncUserData!.ref, remoteUserData.ref); assert.deepStrictEqual(lastSyncUserData!.syncData, remoteUserData.syncData); assert.strictEqual(parseSettingsSyncContent(lastSyncUserData!.syncData!.content!)?.settings, '{}'); - }); + })); - test('sync for first time to the server', async () => { + test('sync for first time to the server', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expected = `{ // Always @@ -187,9 +188,9 @@ suite('SettingsSync - Auto', () => { assert.ok(content !== null); const actual = parseSettings(content!); assert.deepStrictEqual(actual, expected); - }); + })); - test('do not sync machine settings', async () => { + test('do not sync machine settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -218,9 +219,9 @@ suite('SettingsSync - Auto', () => { // Workbench "workbench.colorTheme": "GitHub Sharp" }`); - }); + })); - test('do not sync machine settings when spread across file', async () => { + test('do not sync machine settings when spread across file', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -249,9 +250,9 @@ suite('SettingsSync - Auto', () => { // Workbench "workbench.colorTheme": "GitHub Sharp" }`); - }); + })); - test('do not sync machine settings when spread across file - 2', async () => { + test('do not sync machine settings when spread across file - 2', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -280,9 +281,9 @@ suite('SettingsSync - Auto', () => { "workbench.colorTheme": "GitHub Sharp", "files.simpleDialog.enable": true, }`); - }); + })); - test('sync when all settings are machine settings', async () => { + test('sync when all settings are machine settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Machine @@ -298,9 +299,9 @@ suite('SettingsSync - Auto', () => { const actual = parseSettings(content!); assert.deepStrictEqual(actual, `{ }`); - }); + })); - test('sync when all settings are machine settings with trailing comma', async () => { + test('sync when all settings are machine settings with trailing comma', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Machine @@ -317,9 +318,9 @@ suite('SettingsSync - Auto', () => { assert.deepStrictEqual(actual, `{ , }`); - }); + })); - test('local change event is triggered when settings are changed', async () => { + test('local change event is triggered when settings are changed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const content = `{ "files.autoSave": "afterDelay", @@ -335,9 +336,9 @@ suite('SettingsSync - Auto', () => { "files.simpleDialog.enable": true, }`, client); await promise; - }); + })); - test('do not sync ignored settings', async () => { + test('do not sync ignored settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -380,9 +381,9 @@ suite('SettingsSync - Auto', () => { "terminal.integrated.shell.osx" ] }`); - }); + })); - test('do not sync ignored and machine settings', async () => { + test('do not sync ignored and machine settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -428,9 +429,9 @@ suite('SettingsSync - Auto', () => { "terminal.integrated.shell.osx" ], }`); - }); + })); - test('sync throws invalid content error', async () => { + test('sync throws invalid content error', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expected = `{ // Always @@ -463,9 +464,9 @@ suite('SettingsSync - Auto', () => { assert.ok(e instanceof UserDataSyncError); assert.deepStrictEqual((e).code, UserDataSyncErrorCode.LocalInvalidContent); } - }); + })); - test('sync throws invalid content error - content is an array', async () => { + test('sync throws invalid content error - content is an array', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await updateSettings('[]', client); try { await testObject.sync(await client.getResourceManifest()); @@ -474,9 +475,9 @@ suite('SettingsSync - Auto', () => { assert.ok(e instanceof UserDataSyncError); assert.deepStrictEqual((e).code, UserDataSyncErrorCode.LocalInvalidContent); } - }); + })); - test('sync when there are conflicts', async () => { + test('sync when there are conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const client2 = disposableStore.add(new UserDataSyncClient(server)); await client2.setUp(true); await updateSettings(JSON.stringify({ @@ -499,9 +500,9 @@ suite('SettingsSync - Auto', () => { const fileService = client.instantiationService.get(IFileService); const mergeContent = (await fileService.readFile(testObject.conflicts.conflicts[0].previewResource)).value.toString(); assert.strictEqual(mergeContent, ''); - }); + })); - test('sync profile settings', async () => { + test('sync profile settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const client2 = disposableStore.add(new UserDataSyncClient(server)); await client2.setUp(true); const profile = await client2.instantiationService.get(IUserDataProfilesService).createNamedProfile('profile1'); @@ -521,7 +522,7 @@ suite('SettingsSync - Auto', () => { 'a': 1, 'b': 2, }); - }); + })); }); @@ -541,7 +542,7 @@ suite('SettingsSync - Manual', () => { teardown(() => disposableStore.clear()); - test('do not sync ignored settings', async () => { + test('do not sync ignored settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const settingsContent = `{ // Always @@ -587,7 +588,7 @@ suite('SettingsSync - Manual', () => { "terminal.integrated.shell.osx" ] }`); - }); + })); }); diff --git a/src/vs/platform/userDataSync/test/common/synchronizer.test.ts b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts index 495551412ee..a034c184115 100644 --- a/src/vs/platform/userDataSync/test/common/synchronizer.test.ts +++ b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts @@ -11,6 +11,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { isEqual, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { IFileService } from 'vs/platform/files/common/files'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; @@ -188,7 +189,7 @@ suite('TestSynchronizer - Auto Sync', () => { teardown(() => disposableStore.clear()); - test('status is syncing', async () => { + test('status is syncing', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); const actual: SyncStatus[] = []; @@ -203,9 +204,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); testObject.stop(); - }); + })); - test('status is set correctly when sync is finished', async () => { + test('status is set correctly when sync is finished', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); @@ -215,9 +216,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); assert.deepStrictEqual(testObject.status, SyncStatus.Idle); - }); + })); - test('status is set correctly when sync has errors', async () => { + test('status is set correctly when sync has errors', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasError: true, hasConflicts: false }; testObject.syncBarrier.open(); @@ -232,9 +233,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); assert.deepStrictEqual(testObject.status, SyncStatus.Idle); } - }); + })); - test('status is set to hasConflicts when asked to sync if there are conflicts', async () => { + test('status is set to hasConflicts when asked to sync if there are conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -243,9 +244,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.HasConflicts); assertConflicts(testObject.conflicts.conflicts, [testObject.localResource]); - }); + })); - test('sync should not run if syncing already', async () => { + test('sync should not run if syncing already', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); const promise = Event.toPromise(testObject.onDoSyncCall.event); @@ -260,9 +261,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); await testObject.stop(); - }); + })); - test('sync should not run if there are conflicts', async () => { + test('sync should not run if there are conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -274,9 +275,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(actual, []); assert.deepStrictEqual(testObject.status, SyncStatus.HasConflicts); - }); + })); - test('accept preview during conflicts', async () => { + test('accept preview during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -292,9 +293,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); const fileService = client.instantiationService.get(IFileService); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, (await fileService.readFile(testObject.localResource)).value.toString()); - }); + })); - test('accept remote during conflicts', async () => { + test('accept remote during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -315,9 +316,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, currentRemoteContent); assert.strictEqual((await fileService.readFile(testObject.localResource)).value.toString(), currentRemoteContent); - }); + })); - test('accept local during conflicts', async () => { + test('accept local during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -337,9 +338,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, newLocalContent); assert.strictEqual((await fileService.readFile(testObject.localResource)).value.toString(), newLocalContent); - }); + })); - test('accept new content during conflicts', async () => { + test('accept new content during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -360,9 +361,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, mergeContent); assert.strictEqual((await fileService.readFile(testObject.localResource)).value.toString(), mergeContent); - }); + })); - test('accept delete during conflicts', async () => { + test('accept delete during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -382,9 +383,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, ''); assert.ok(!(await fileService.exists(testObject.localResource))); - }); + })); - test('accept deleted local during conflicts', async () => { + test('accept deleted local during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -403,9 +404,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, ''); assert.ok(!(await fileService.exists(testObject.localResource))); - }); + })); - test('accept deleted remote during conflicts', async () => { + test('accept deleted remote during conflicts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); const fileService = client.instantiationService.get(IFileService); @@ -423,9 +424,9 @@ suite('TestSynchronizer - Auto Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Idle); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData, null); assert.ok(!(await fileService.exists(testObject.localResource))); - }); + })); - test('request latest data on precondition failure', async () => { + test('request latest data on precondition failure', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); // Sync once testObject.syncBarrier.open(); @@ -450,9 +451,9 @@ suite('TestSynchronizer - Auto Sync', () => { { type: 'GET', url: `${server.url}/v1/resource/${testObject.resource}/latest`, headers: {} }, { type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': `${parseInt(ref) + 1}` } }, ]); - }); + })); - test('no requests are made to server when local change is triggered', async () => { + test('no requests are made to server when local change is triggered', () => runWithFakedTimers({ useFakeTimers: true }, () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncBarrier.open(); await testObject.sync(await client.getResourceManifest()); @@ -463,9 +464,9 @@ suite('TestSynchronizer - Auto Sync', () => { await promise; assert.deepStrictEqual(server.requests, []); - }); + }))); - test('status is reset when getting latest remote data fails', async () => { + test('status is reset when getting latest remote data fails', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.failWhenGettingLatestRemoteUserData = true; @@ -476,7 +477,7 @@ suite('TestSynchronizer - Auto Sync', () => { } assert.strictEqual(testObject.status, SyncStatus.Idle); - }); + })); }); suite('TestSynchronizer - Manual Sync', () => { @@ -496,7 +497,7 @@ suite('TestSynchronizer - Manual Sync', () => { teardown(() => disposableStore.clear()); - test('preview', async () => { + test('preview', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -506,9 +507,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preview -> merge', async () => { + test('preview -> merge', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -520,9 +521,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preview -> accept', async () => { + test('preview -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -534,9 +535,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preview -> merge -> accept', async () => { + test('preview -> merge -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -549,9 +550,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preview -> merge -> apply', async () => { + test('preview -> merge -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -569,9 +570,9 @@ suite('TestSynchronizer - Manual Sync', () => { const expectedContent = manifest![testObject.resource]; assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preview -> accept -> apply', async () => { + test('preview -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -589,9 +590,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preview -> merge -> accept -> apply', async () => { + test('preview -> merge -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -609,9 +610,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preview -> accept', async () => { + test('preview -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -622,9 +623,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preview -> accept -> apply', async () => { + test('preview -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -642,9 +643,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preivew -> merge -> discard', async () => { + test('preivew -> merge -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -657,9 +658,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> merge -> discard -> accept', async () => { + test('preivew -> merge -> discard -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -673,9 +674,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> accept -> discard', async () => { + test('preivew -> accept -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -688,9 +689,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> accept -> discard -> accept', async () => { + test('preivew -> accept -> discard -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -704,9 +705,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> accept -> discard -> merge', async () => { + test('preivew -> accept -> discard -> merge', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -720,9 +721,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> merge -> accept -> discard', async () => { + test('preivew -> merge -> accept -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -736,9 +737,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('preivew -> merge -> discard -> accept -> apply', async () => { + test('preivew -> merge -> discard -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -756,9 +757,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertConflicts(testObject.conflicts.conflicts, []); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preivew -> accept -> discard -> accept -> apply', async () => { + test('preivew -> accept -> discard -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -777,9 +778,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertConflicts(testObject.conflicts.conflicts, []); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('preivew -> accept -> discard -> merge -> apply', async () => { + test('preivew -> accept -> discard -> merge -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -800,9 +801,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('conflicts: preview', async () => { + test('conflicts: preview', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -812,9 +813,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preview -> merge', async () => { + test('conflicts: preview -> merge', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -826,9 +827,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Conflict); assertConflicts(testObject.conflicts.conflicts, [preview!.resourcePreviews[0].localResource]); - }); + })); - test('conflicts: preview -> merge -> discard', async () => { + test('conflicts: preview -> merge -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -841,9 +842,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preview -> accept', async () => { + test('conflicts: preview -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -856,9 +857,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.deepStrictEqual(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preview -> merge -> accept -> apply', async () => { + test('conflicts: preview -> merge -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -879,9 +880,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('conflicts: preview -> accept', async () => { + test('conflicts: preview -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -893,9 +894,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.deepStrictEqual(testObject.status, SyncStatus.Syncing); assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preview -> accept -> apply', async () => { + test('conflicts: preview -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -915,9 +916,9 @@ suite('TestSynchronizer - Manual Sync', () => { assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('conflicts: preivew -> merge -> discard', async () => { + test('conflicts: preivew -> merge -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -930,9 +931,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preivew -> merge -> discard -> accept', async () => { + test('conflicts: preivew -> merge -> discard -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -946,9 +947,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preivew -> accept -> discard', async () => { + test('conflicts: preivew -> accept -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -961,9 +962,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preivew -> accept -> discard -> accept', async () => { + test('conflicts: preivew -> accept -> discard -> accept', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -977,9 +978,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Accepted); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preivew -> accept -> discard -> merge', async () => { + test('conflicts: preivew -> accept -> discard -> merge', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -993,9 +994,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Conflict); assertConflicts(testObject.conflicts.conflicts, [preview!.resourcePreviews[0].localResource]); - }); + })); - test('conflicts: preivew -> merge -> discard -> merge', async () => { + test('conflicts: preivew -> merge -> discard -> merge', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: true, hasError: false }; testObject.syncBarrier.open(); @@ -1009,9 +1010,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Conflict); assertConflicts(testObject.conflicts.conflicts, [preview!.resourcePreviews[0].localResource]); - }); + })); - test('conflicts: preivew -> merge -> accept -> discard', async () => { + test('conflicts: preivew -> merge -> accept -> discard', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -1025,9 +1026,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertPreviews(preview!.resourcePreviews, [testObject.localResource]); assert.strictEqual(preview!.resourcePreviews[0].mergeState, MergeState.Preview); assertConflicts(testObject.conflicts.conflicts, []); - }); + })); - test('conflicts: preivew -> merge -> discard -> accept -> apply', async () => { + test('conflicts: preivew -> merge -> discard -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -1045,9 +1046,9 @@ suite('TestSynchronizer - Manual Sync', () => { assertConflicts(testObject.conflicts.conflicts, []); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); - test('conflicts: preivew -> accept -> discard -> accept -> apply', async () => { + test('conflicts: preivew -> accept -> discard -> accept -> apply', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined)); testObject.syncResult = { hasConflicts: false, hasError: false }; testObject.syncBarrier.open(); @@ -1066,7 +1067,7 @@ suite('TestSynchronizer - Manual Sync', () => { assertConflicts(testObject.conflicts.conflicts, []); assert.strictEqual((await testObject.getRemoteUserData(null)).syncData?.content, expectedContent); assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent); - }); + })); }); diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts index 66af196c356..a282d1e2d84 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts @@ -11,6 +11,7 @@ import { InMemoryStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest, Stor import { AbstractUserDataSyncProfilesStorageService, IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; import { InMemoryStorageService, loadKeyTargets, StorageTarget, TARGET_KEY } from 'vs/platform/storage/common/storage'; import { IUserDataProfile, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; class TestStorageDatabase extends InMemoryStorageDatabase { @@ -56,13 +57,13 @@ suite('ProfileStorageService', () => { teardown(() => disposables.clear()); - test('read empty storage', async () => { + test('read empty storage', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const actual = await testObject.readStorageData(profile); assert.strictEqual(actual.size, 0); - }); + })); - test('read storage with data', async () => { + test('read storage with data', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storage.set('foo', 'bar'); storage.set(TARGET_KEY, JSON.stringify({ foo: StorageTarget.USER })); await storage.flush(); @@ -71,9 +72,9 @@ suite('ProfileStorageService', () => { assert.strictEqual(actual.size, 1); assert.deepStrictEqual(actual.get('foo'), { 'value': 'bar', 'target': StorageTarget.USER }); - }); + })); - test('write in empty storage', async () => { + test('write in empty storage', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const data = new Map(); data.set('foo', 'bar'); await testObject.updateStorageData(profile, data, StorageTarget.USER); @@ -81,9 +82,9 @@ suite('ProfileStorageService', () => { assert.strictEqual(storage.items.size, 2); assert.deepStrictEqual(loadKeyTargets(storage), { foo: StorageTarget.USER }); assert.strictEqual(storage.get('foo'), 'bar'); - }); + })); - test('write in storage with data', async () => { + test('write in storage with data', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storage.set('foo', 'bar'); storage.set(TARGET_KEY, JSON.stringify({ foo: StorageTarget.USER })); await storage.flush(); @@ -96,9 +97,9 @@ suite('ProfileStorageService', () => { assert.deepStrictEqual(loadKeyTargets(storage), { foo: StorageTarget.USER, abc: StorageTarget.MACHINE }); assert.strictEqual(storage.get('foo'), 'bar'); assert.strictEqual(storage.get('abc'), 'xyz'); - }); + })); - test('write in storage with data (insert, update, remove)', async () => { + test('write in storage with data (insert, update, remove)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storage.set('foo', 'bar'); storage.set('abc', 'xyz'); storage.set(TARGET_KEY, JSON.stringify({ foo: StorageTarget.USER, abc: StorageTarget.MACHINE })); @@ -114,6 +115,6 @@ suite('ProfileStorageService', () => { assert.deepStrictEqual(loadKeyTargets(storage), { abc: StorageTarget.USER, var: StorageTarget.USER }); assert.strictEqual(storage.get('abc'), 'def'); assert.strictEqual(storage.get('var'), 'const'); - }); + })); }); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index b09c88322f5..6fbc0225b97 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -116,7 +116,7 @@ suite('WorkspaceContextService - Folder', () => { assert.strictEqual(actual, testObject.getWorkspace().folders[0]); }); - test('getWorkspaceFolder() - queries in workspace folder', async () => { + test('getWorkspaceFolder() - queries in workspace folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const logService = new NullLogService(); const fileService = disposables.add(new FileService(logService)); @@ -136,9 +136,9 @@ suite('WorkspaceContextService - Folder', () => { const actual = testObject.getWorkspaceFolder(joinPath(folder, 'a')); assert.strictEqual(actual, testObject.getWorkspace().folders[0]); - }); + })); - test('getWorkspaceFolder() - queries in resource', async () => { + test('getWorkspaceFolder() - queries in resource', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const logService = new NullLogService(); const fileService = disposables.add(new FileService(logService)); @@ -159,7 +159,7 @@ suite('WorkspaceContextService - Folder', () => { const actual = testObject.getWorkspaceFolder(joinPath(folder, 'a').with({ query: 'myquery=1' })); assert.strictEqual(actual, testObject.getWorkspace().folders[0]); - }); + })); test('isCurrentWorkspace() => true', () => { assert.ok(testObject.isCurrentWorkspace(folder)); @@ -277,7 +277,7 @@ suite('WorkspaceContextService - Workspace Editing', () => { teardown(() => disposables.clear()); - test('add folders', async () => { + test('add folders', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.addFolders([{ uri: joinPath(ROOT, 'd') }, { uri: joinPath(ROOT, 'c') }]); const actual = testObject.getWorkspace().folders; @@ -286,9 +286,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.strictEqual(basename(actual[1].uri), 'b'); assert.strictEqual(basename(actual[2].uri), 'd'); assert.strictEqual(basename(actual[3].uri), 'c'); - }); + })); - test('add folders (at specific index)', async () => { + test('add folders (at specific index)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.addFolders([{ uri: joinPath(ROOT, 'd') }, { uri: joinPath(ROOT, 'c') }], 0); const actual = testObject.getWorkspace().folders; @@ -297,9 +297,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.strictEqual(basename(actual[1].uri), 'c'); assert.strictEqual(basename(actual[2].uri), 'a'); assert.strictEqual(basename(actual[3].uri), 'b'); - }); + })); - test('add folders (at specific wrong index)', async () => { + test('add folders (at specific wrong index)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.addFolders([{ uri: joinPath(ROOT, 'd') }, { uri: joinPath(ROOT, 'c') }], 10); const actual = testObject.getWorkspace().folders; @@ -308,9 +308,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.strictEqual(basename(actual[1].uri), 'b'); assert.strictEqual(basename(actual[2].uri), 'd'); assert.strictEqual(basename(actual[3].uri), 'c'); - }); + })); - test('add folders (with name)', async () => { + test('add folders (with name)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.addFolders([{ uri: joinPath(ROOT, 'd'), name: 'DDD' }, { uri: joinPath(ROOT, 'c'), name: 'CCC' }]); const actual = testObject.getWorkspace().folders; @@ -321,9 +321,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.strictEqual(basename(actual[3].uri), 'c'); assert.strictEqual(actual[2].name, 'DDD'); assert.strictEqual(actual[3].name, 'CCC'); - }); + })); - test('add folders triggers change event', async () => { + test('add folders triggers change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -336,17 +336,17 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added.map(r => r.uri.toString()), addedFolders.map(a => a.uri.toString())); assert.deepStrictEqual(actual_1.removed, []); assert.deepStrictEqual(actual_1.changed, []); - }); + })); - test('remove folders', async () => { + test('remove folders', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.removeFolders([testObject.getWorkspace().folders[0].uri]); const actual = testObject.getWorkspace().folders; assert.strictEqual(actual.length, 1); assert.strictEqual(basename(actual[0].uri), 'b'); - }); + })); - test('remove folders triggers change event', async () => { + test('remove folders triggers change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -358,9 +358,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added, []); assert.deepStrictEqual(actual_1.removed.map(r => r.uri.toString()), [removedFolder.uri.toString()]); assert.deepStrictEqual(actual_1.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]); - }); + })); - test('remove folders and add them back by writing into the file', async () => { + test('remove folders and add them back by writing into the file', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const folders = testObject.getWorkspace().folders; await testObject.removeFolders([folders[0].uri]); @@ -378,9 +378,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { const workspace = { folders: [{ path: folders[0].uri.path }, { path: folders[1].uri.path }] }; await fileService.writeFile(testObject.getWorkspace().configuration!, VSBuffer.fromString(JSON.stringify(workspace, null, '\t'))); await promise; - }); + })); - test('update folders (remove last and add to end)', async () => { + test('update folders (remove last and add to end)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -393,9 +393,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added.map(r => r.uri.toString()), addedFolders.map(a => a.uri.toString())); assert.deepStrictEqual(actual_1.removed.map(r_1 => r_1.uri.toString()), removedFolders.map(a_1 => a_1.toString())); assert.deepStrictEqual(actual_1.changed, []); - }); + })); - test('update folders (rename first via add and remove)', async () => { + test('update folders (rename first via add and remove)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -408,9 +408,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added, []); assert.deepStrictEqual(actual_1.removed, []); assert.deepStrictEqual(actual_1.changed.map(r => r.uri.toString()), removedFolders.map(a => a.toString())); - }); + })); - test('update folders (remove first and add to end)', async () => { + test('update folders (remove first and add to end)', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -424,9 +424,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added.map(r => r.uri.toString()), addedFolders.map(a => a.uri.toString())); assert.deepStrictEqual(actual_1.removed.map(r_1 => r_1.uri.toString()), removedFolders.map(a_1 => a_1.toString())); assert.deepStrictEqual(actual_1.changed.map(r_2 => r_2.uri.toString()), changedFolders.map(a_2 => a_2.toString())); - }); + })); - test('reorder folders trigger change event', async () => { + test('reorder folders trigger change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -439,9 +439,9 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added, []); assert.deepStrictEqual(actual_1.removed, []); assert.deepStrictEqual(actual_1.changed.map(c => c.uri.toString()), testObject.getWorkspace().folders.map(f => f.uri.toString()).reverse()); - }); + })); - test('rename folders trigger change event', async () => { + test('rename folders trigger change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onWillChangeWorkspaceFolders(target); testObject.onDidChangeWorkspaceFolders(target); @@ -454,7 +454,7 @@ suite('WorkspaceContextService - Workspace Editing', () => { assert.deepStrictEqual(actual_1.added, []); assert.deepStrictEqual(actual_1.removed, []); assert.deepStrictEqual(actual_1.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]); - }); + })); }); @@ -522,7 +522,7 @@ suite('WorkspaceService - Initialization', () => { teardown(() => disposables.clear()); - (isMacintosh ? test.skip : test)('initialize a folder workspace from an empty workspace with no configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a folder workspace from an empty workspace with no configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "initialization.testSetting1": "userValue" }')); @@ -545,9 +545,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[3][0]).removed, []); assert.deepStrictEqual((target.args[3][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a folder workspace from an empty workspace with configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a folder workspace from an empty workspace with configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "initialization.testSetting1": "userValue" }')); @@ -572,9 +572,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[4][0]).removed, []); assert.deepStrictEqual((target.args[4][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a multi root workspace from an empty workspace with no configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a multi root workspace from an empty workspace with no configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "initialization.testSetting1": "userValue" }')); @@ -595,9 +595,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[3][0]).removed, []); assert.deepStrictEqual((target.args[3][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a multi root workspace from an empty workspace with configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a multi root workspace from an empty workspace with configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "initialization.testSetting1": "userValue" }')); @@ -621,9 +621,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[4][0]).removed, []); assert.deepStrictEqual((target.args[4][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a folder workspace from a folder workspace with no configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a folder workspace from a folder workspace with no configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.initialize(convertToWorkspacePayload(joinPath(ROOT, 'a'))); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "initialization.testSetting1": "userValue" }')); @@ -643,9 +643,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[1][0]).removed.map(folder_2 => folder_2.uri.toString()), [joinPath(ROOT, 'a').toString()]); assert.deepStrictEqual((target.args[1][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a folder workspace from a folder workspace with configuration changes', async () => { + (isMacintosh ? test.skip : test)('initialize a folder workspace from a folder workspace with configuration changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.initialize(convertToWorkspacePayload(joinPath(ROOT, 'a'))); const target = sinon.spy(); @@ -665,9 +665,9 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[2][0]).removed.map(folder_2 => folder_2.uri.toString()), [joinPath(ROOT, 'a').toString()]); assert.deepStrictEqual((target.args[2][0]).changed, []); - }); + })); - (isMacintosh ? test.skip : test)('initialize a multi folder workspace from a folder workspacce triggers change events in the right order', async () => { + (isMacintosh ? test.skip : test)('initialize a multi folder workspace from a folder workspacce triggers change events in the right order', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.initialize(convertToWorkspacePayload(joinPath(ROOT, 'a'))); const target = sinon.spy(); testObject.onDidChangeWorkbenchState(target); @@ -686,7 +686,7 @@ suite('WorkspaceService - Initialization', () => { assert.deepStrictEqual((target.args[4][0]).added.map(folder_1 => folder_1.uri.toString()), [joinPath(ROOT, 'b').toString()]); assert.deepStrictEqual((target.args[4][0]).removed, []); assert.deepStrictEqual((target.args[4][0]).changed, []); - }); + })); }); @@ -788,39 +788,39 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(testObject.getValue('configurationService'), { 'folder': { 'applicationSetting': 'isSet', 'machineSetting': 'isSet', 'machineOverridableSetting': 'isSet', 'testSetting': 'isSet', 'languageSetting': 'isSet', 'restrictedSetting': 'isSet', 'policySetting': 'isSet' } }); }); - test('globals override defaults', async () => { + test('globals override defaults', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.testSetting": "userValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.testSetting'), 'userValue'); - }); + })); - test('globals', async () => { + test('globals', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('testworkbench.editor.tabs'), true); - }); + })); - test('workspace settings', async () => { + test('workspace settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "testworkbench.editor.icons": true }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('testworkbench.editor.icons'), true); - }); + })); - test('workspace settings override user settings', async () => { + test('workspace settings override user settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.testSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.testSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue'); - }); + })); - test('machine overridable settings override user Settings', async () => { + test('machine overridable settings override user Settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineOverridableSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.machineOverridableSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineOverridableSetting'), 'workspaceValue'); - }); + })); - test('workspace settings override user settings after defaults are registered ', async () => { + test('workspace settings override user settings after defaults are registered ', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.newSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.newSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); @@ -835,9 +835,9 @@ suite('WorkspaceConfigurationService - Folder', () => { } }); assert.strictEqual(testObject.getValue('configurationService.folder.newSetting'), 'workspaceValue'); - }); + })); - test('machine overridable settings override user settings after defaults are registered ', async () => { + test('machine overridable settings override user settings after defaults are registered ', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.newMachineOverridableSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.newMachineOverridableSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); @@ -853,45 +853,45 @@ suite('WorkspaceConfigurationService - Folder', () => { } }); assert.strictEqual(testObject.getValue('configurationService.folder.newMachineOverridableSetting'), 'workspaceValue'); - }); + })); - test('application settings are not read from workspace', async () => { + test('application settings are not read from workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting'), 'userValue'); - }); + })); - test('application settings are not read from workspace when workspace folder uri is passed', async () => { + test('application settings are not read from workspace when workspace folder uri is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting', { resource: workspaceService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('machine settings are not read from workspace', async () => { + test('machine settings are not read from workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.machineSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting', { resource: workspaceService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('machine settings are not read from workspace when workspace folder uri is passed', async () => { + test('machine settings are not read from workspace when workspace folder uri is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.machineSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting', { resource: workspaceService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('get application scope settings are not loaded after defaults are registered', async () => { + test('get application scope settings are not loaded after defaults are registered', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting-2": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.applicationSetting-2": "workspaceValue" }')); @@ -914,9 +914,9 @@ suite('WorkspaceConfigurationService - Folder', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting-2'), 'userValue'); - }); + })); - test('get application scope settings are not loaded after defaults are registered when workspace folder uri is passed', async () => { + test('get application scope settings are not loaded after defaults are registered when workspace folder uri is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting-3": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.applicationSetting-3": "workspaceValue" }')); @@ -939,9 +939,9 @@ suite('WorkspaceConfigurationService - Folder', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting-3', { resource: workspaceService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('get machine scope settings are not loaded after defaults are registered', async () => { + test('get machine scope settings are not loaded after defaults are registered', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting-2": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.machineSetting-2": "workspaceValue" }')); @@ -964,9 +964,9 @@ suite('WorkspaceConfigurationService - Folder', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting-2'), 'userValue'); - }); + })); - test('get machine scope settings are not loaded after defaults are registered when workspace folder uri is passed', async () => { + test('get machine scope settings are not loaded after defaults are registered when workspace folder uri is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting-3": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.machineSetting-3": "workspaceValue" }')); @@ -989,9 +989,9 @@ suite('WorkspaceConfigurationService - Folder', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting-3', { resource: workspaceService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('policy value override all', async () => { + test('policy value override all', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const result = await runWithFakedTimers({ useFakeTimers: true }, async () => { const promise = Event.toPromise(testObject.onDidChangeConfiguration); await fileService.writeFile(environmentService.policyFile!, VSBuffer.fromString('{ "configurationService.folder.policySetting": "policyValue" }')); @@ -1000,33 +1000,33 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(result.affectedKeys, ['configurationService.folder.policySetting']); assert.strictEqual(testObject.getValue('configurationService.folder.policySetting'), 'policyValue'); assert.strictEqual(testObject.inspect('configurationService.folder.policySetting').policyValue, 'policyValue'); - }); + })); - test('policy settings when policy value is not set', async () => { + test('policy settings when policy value is not set', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.policySetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.policySetting": "workspaceValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.policySetting'), 'workspaceValue'); assert.strictEqual(testObject.inspect('configurationService.folder.policySetting').policyValue, undefined); - }); + })); - test('reload configuration emits events after global configuraiton changes', async () => { + test('reload configuration emits events after global configuraiton changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }')); const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.reloadConfiguration(); assert.ok(target.called); - }); + })); - test('reload configuration emits events after workspace configuraiton changes', async () => { + test('reload configuration emits events after workspace configuraiton changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.testSetting": "workspaceValue" }')); const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.reloadConfiguration(); assert.ok(target.called); - }); + })); - test('reload configuration should not emit event if no changes', async () => { + test('reload configuration should not emit event if no changes', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.testSetting": "workspaceValue" }')); await testObject.reloadConfiguration(); @@ -1034,9 +1034,9 @@ suite('WorkspaceConfigurationService - Folder', () => { testObject.onDidChangeConfiguration(() => { target(); }); await testObject.reloadConfiguration(); assert.ok(!target.called); - }); + })); - test('inspect', async () => { + test('inspect', () => runWithFakedTimers({ useFakeTimers: true }, async () => { let actual = testObject.inspect('something.missing'); assert.strictEqual(actual.defaultValue, undefined); assert.strictEqual(actual.application, undefined); @@ -1094,9 +1094,9 @@ suite('WorkspaceConfigurationService - Folder', () => { } } }); - }); + })); - test('inspect restricted settings', async () => { + test('inspect restricted settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userRestrictedValue" }')); await testObject.reloadConfiguration(); @@ -1182,9 +1182,9 @@ suite('WorkspaceConfigurationService - Folder', () => { } } }); - }); + })); - test('keys', async () => { + test('keys', () => runWithFakedTimers({ useFakeTimers: true }, async () => { let actual = testObject.keys(); assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1); assert.deepStrictEqual(actual.user, []); @@ -1206,7 +1206,7 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(actual.user, ['configurationService.folder.testSetting']); assert.deepStrictEqual(actual.workspace, ['configurationService.folder.testSetting']); assert.deepStrictEqual(actual.workspaceFolder, []); - }); + })); test('update user configuration', () => { return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER) @@ -1223,39 +1223,39 @@ suite('WorkspaceConfigurationService - Folder', () => { .then(() => assert.strictEqual(testObject.getValue('configurationService.folder.testSetting'), 'value')); }); - test('update language configuration using configuration overrides', async () => { + test('update language configuration using configuration overrides', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.languageSetting', 'abcLangValue', { overrideIdentifier: 'abclang' }); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { overrideIdentifier: 'abclang' }), 'abcLangValue'); - }); + })); - test('update language configuration using configuration update overrides', async () => { + test('update language configuration using configuration update overrides', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.languageSetting', 'abcLangValue', { overrideIdentifiers: ['abclang'] }); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { overrideIdentifier: 'abclang' }), 'abcLangValue'); - }); + })); - test('update language configuration for multiple languages', async () => { + test('update language configuration for multiple languages', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.languageSetting', 'multiLangValue', { overrideIdentifiers: ['deflang', 'xyzlang'] }, ConfigurationTarget.USER); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { overrideIdentifier: 'deflang' }), 'multiLangValue'); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { overrideIdentifier: 'xyzlang' }), 'multiLangValue'); assert.deepStrictEqual(testObject.getValue(keyFromOverrideIdentifiers(['deflang', 'xyzlang'])), { 'configurationService.folder.languageSetting': 'multiLangValue' }); - }); + })); - test('update resource language configuration', async () => { + test('update resource language configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.languageSetting', 'value', { resource: workspaceService.getWorkspace().folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting'), 'value'); - }); + })); - test('update resource language configuration for a language using configuration overrides', async () => { + test('update resource language configuration for a language using configuration overrides', () => runWithFakedTimers({ useFakeTimers: true }, async () => { assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifier: 'jsonc' }), 'languageValue'); await testObject.updateValue('configurationService.folder.languageSetting', 'languageValueUpdated', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifier: 'jsonc' }, ConfigurationTarget.WORKSPACE_FOLDER); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifier: 'jsonc' }), 'languageValueUpdated'); - }); + })); - test('update resource language configuration for a language using configuration update overrides', async () => { + test('update resource language configuration for a language using configuration update overrides', () => runWithFakedTimers({ useFakeTimers: true }, async () => { assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifier: 'jsonc' }), 'languageValue'); await testObject.updateValue('configurationService.folder.languageSetting', 'languageValueUpdated', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifiers: ['jsonc'] }, ConfigurationTarget.WORKSPACE_FOLDER); assert.strictEqual(testObject.getValue('configurationService.folder.languageSetting', { resource: workspaceService.getWorkspace().folders[0].uri, overrideIdentifier: 'jsonc' }), 'languageValueUpdated'); - }); + })); test('update application setting into workspace configuration in a workspace is not supported', () => { return testObject.updateValue('configurationService.folder.applicationSetting', 'workspaceValue', {}, ConfigurationTarget.WORKSPACE, true) @@ -1298,7 +1298,7 @@ suite('WorkspaceConfigurationService - Folder', () => { .then(() => assert.ok(target.called)); }); - test('remove setting from all targets', async () => { + test('remove setting from all targets', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const key = 'configurationService.folder.testSetting'; await testObject.updateValue(key, 'workspaceValue', ConfigurationTarget.WORKSPACE); await testObject.updateValue(key, 'userValue', ConfigurationTarget.USER); @@ -1310,19 +1310,19 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.strictEqual(actual.userValue, undefined); assert.strictEqual(actual.workspaceValue, undefined); assert.strictEqual(actual.workspaceFolderValue, undefined); - }); + })); - test('update user configuration to default value when target is not passed', async () => { + test('update user configuration to default value when target is not passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER); await testObject.updateValue('configurationService.folder.testSetting', 'isSet'); assert.strictEqual(testObject.inspect('configurationService.folder.testSetting').userValue, undefined); - }); + })); - test('update user configuration to default value when target is passed', async () => { + test('update user configuration to default value when target is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER); await testObject.updateValue('configurationService.folder.testSetting', 'isSet', ConfigurationTarget.USER); assert.strictEqual(testObject.inspect('configurationService.folder.testSetting').userValue, 'isSet'); - }); + })); test('update task configuration should trigger change event before promise is resolve', () => { const target = sinon.spy(); @@ -1331,19 +1331,19 @@ suite('WorkspaceConfigurationService - Folder', () => { .then(() => assert.ok(target.called)); }); - test('no change event when there are no global tasks', async () => { + test('no change event when there are no global tasks', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await timeout(5); assert.ok(target.notCalled); - }); + })); - test('change event when there are global tasks', async () => { + test('change event when there are global tasks', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(joinPath(environmentService.userRoamingDataHome, 'tasks.json'), VSBuffer.fromString('{ "version": "1.0.0", "tasks": [{ "taskName": "myTask" }')); const promise = Event.toPromise(testObject.onDidChangeConfiguration); await testObject.reloadLocalUserConfiguration(); await promise; - }); + })); test('creating workspace settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.testSetting": "userValue" }')); @@ -1372,7 +1372,7 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.strictEqual(testObject.getValue('configurationService.folder.testSetting'), 'userValue'); })); - test('restricted setting is read from workspace when workspace is trusted', async () => { + test('restricted setting is read from workspace when workspace is trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(true); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1386,9 +1386,9 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(testObject.restrictedSettings.workspace, ['configurationService.folder.restrictedSetting']); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(workspaceService.getWorkspace().folders[0].uri), ['configurationService.folder.restrictedSetting']); - }); + })); - test('restricted setting is not read from workspace when workspace is changed to trusted', async () => { + test('restricted setting is not read from workspace when workspace is changed to trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(true); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1404,9 +1404,9 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(testObject.restrictedSettings.workspace, ['configurationService.folder.restrictedSetting']); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(workspaceService.getWorkspace().folders[0].uri), ['configurationService.folder.restrictedSetting']); - }); + })); - test('change event is triggered when workspace is changed to untrusted', async () => { + test('change event is triggered when workspace is changed to untrusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(true); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1419,9 +1419,9 @@ suite('WorkspaceConfigurationService - Folder', () => { const event = await promise; assert.ok(event.affectedKeys.includes('configurationService.folder.restrictedSetting')); assert.ok(event.affectsConfiguration('configurationService.folder.restrictedSetting')); - }); + })); - test('restricted setting is not read from workspace when workspace is not trusted', async () => { + test('restricted setting is not read from workspace when workspace is not trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1435,9 +1435,9 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(testObject.restrictedSettings.workspace, ['configurationService.folder.restrictedSetting']); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(workspaceService.getWorkspace().folders[0].uri), ['configurationService.folder.restrictedSetting']); - }); + })); - test('restricted setting is read when workspace is changed to trusted', async () => { + test('restricted setting is read when workspace is changed to trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1453,9 +1453,9 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.deepStrictEqual(testObject.restrictedSettings.workspace, ['configurationService.folder.restrictedSetting']); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(workspaceService.getWorkspace().folders[0].uri), ['configurationService.folder.restrictedSetting']); - }); + })); - test('change event is triggered when workspace is changed to trusted', async () => { + test('change event is triggered when workspace is changed to trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1468,7 +1468,7 @@ suite('WorkspaceConfigurationService - Folder', () => { const event = await promise; assert.ok(event.affectedKeys.includes('configurationService.folder.restrictedSetting')); assert.ok(event.affectsConfiguration('configurationService.folder.restrictedSetting')); - }); + })); test('adding an restricted setting triggers change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userValue" }')); @@ -1480,7 +1480,7 @@ suite('WorkspaceConfigurationService - Folder', () => { return promise; })); - test('remove an unregistered setting', async () => { + test('remove an unregistered setting', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const key = 'configurationService.folder.unknownSetting'; await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.unknownSetting": "userValue" }')); await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.unknownSetting": "workspaceValue" }')); @@ -1492,7 +1492,7 @@ suite('WorkspaceConfigurationService - Folder', () => { assert.strictEqual(actual.userValue, undefined); assert.strictEqual(actual.workspaceValue, undefined); assert.strictEqual(actual.workspaceFolderValue, undefined); - }); + })); }); suite('WorkspaceConfigurationService - Profiles', () => { @@ -1563,12 +1563,12 @@ suite('WorkspaceConfigurationService - Profiles', () => { teardown(() => disposables.clear()); - test('initialize', async () => { + test('initialize', () => runWithFakedTimers({ useFakeTimers: true }, async () => { assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting2'), 'applicationValue'); assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting2'), 'profileValue'); - }); + })); - test('inspect', async () => { + test('inspect', () => runWithFakedTimers({ useFakeTimers: true }, async () => { let actual = testObject.inspect('something.missing'); assert.strictEqual(actual.defaultValue, undefined); assert.strictEqual(actual.application, undefined); @@ -1606,23 +1606,23 @@ suite('WorkspaceConfigurationService - Profiles', () => { assert.strictEqual(actual.workspaceValue, undefined); assert.strictEqual(actual.workspaceFolderValue, undefined); assert.strictEqual(actual.value, 'profileValue'); - }); + })); - test('update application scope setting', async () => { + test('update application scope setting', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.profiles.applicationSetting', 'applicationValue'); assert.deepStrictEqual(JSON.parse((await fileService.readFile(instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource)).value.toString()), { 'configurationService.profiles.applicationSetting': 'applicationValue', 'configurationService.profiles.applicationSetting2': 'applicationValue', 'configurationService.profiles.testSetting2': 'userValue' }); assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue'); - }); + })); - test('update normal setting', async () => { + test('update normal setting', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.profiles.testSetting', 'profileValue'); assert.deepStrictEqual(JSON.parse((await fileService.readFile(userDataProfileService.currentProfile.settingsResource)).value.toString()), { 'configurationService.profiles.testSetting': 'profileValue', 'configurationService.profiles.testSetting2': 'profileValue', 'configurationService.profiles.applicationSetting2': 'profileValue' }); assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'profileValue'); - }); + })); - test('switch to default profile', async () => { + test('switch to default profile', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "applicationValue", "configurationService.profiles.testSetting": "userValue" }')); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue", "configurationService.profiles.testSetting": "profileValue" }')); await testObject.reloadConfiguration(); @@ -1634,9 +1634,9 @@ suite('WorkspaceConfigurationService - Profiles', () => { assert.deepStrictEqual(changeEvent.affectedKeys, ['configurationService.profiles.testSetting']); assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue'); assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'userValue'); - }); + })); - test('switch to non default profile', async () => { + test('switch to non default profile', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(instantiationService.get(IUserDataProfilesService).defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "applicationValue", "configurationService.profiles.testSetting": "userValue" }')); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue", "configurationService.profiles.testSetting": "profileValue" }')); await testObject.reloadConfiguration(); @@ -1650,7 +1650,7 @@ suite('WorkspaceConfigurationService - Profiles', () => { assert.deepStrictEqual(changeEvent.affectedKeys, ['configurationService.profiles.testSetting']); assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue'); assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'profileValue2'); - }); + })); }); @@ -1757,43 +1757,43 @@ suite('WorkspaceConfigurationService-Multiroot', () => { teardown(() => disposables.clear()); - test('application settings are not read from workspace', async () => { + test('application settings are not read from workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.applicationSetting': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting'), 'userValue'); - }); + })); - test('application settings are not read from workspace when folder is passed', async () => { + test('application settings are not read from workspace when folder is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.applicationSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.applicationSetting': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.applicationSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('machine settings are not read from workspace', async () => { + test('machine settings are not read from workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting'), 'userValue'); - }); + })); - test('machine settings are not read from workspace when folder is passed', async () => { + test('machine settings are not read from workspace when folder is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.machineSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.folder.machineSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('get application scope settings are not loaded after defaults are registered', async () => { + test('get application scope settings are not loaded after defaults are registered', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.newSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.newSetting': 'workspaceValue' } }], true); @@ -1816,9 +1816,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.newSetting'), 'userValue'); - }); + })); - test('get application scope settings are not loaded after defaults are registered when workspace folder is passed', async () => { + test('get application scope settings are not loaded after defaults are registered when workspace folder is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.newSetting-2": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.newSetting-2': 'workspaceValue' } }], true); @@ -1841,9 +1841,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.newSetting-2', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('workspace settings override user settings after defaults are registered for machine overridable settings ', async () => { + test('workspace settings override user settings after defaults are registered for machine overridable settings ', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.newMachineOverridableSetting": "userValue" }')); await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ path: ['settings'], value: { 'configurationService.workspace.newMachineOverridableSetting': 'workspaceValue' } }], true); @@ -1867,45 +1867,45 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.newMachineOverridableSetting'), 'workspaceValue'); - }); + })); - test('application settings are not read from workspace folder', async () => { + test('application settings are not read from workspace folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.applicationSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.applicationSetting": "workspaceFolderValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue'); - }); + })); - test('application settings are not read from workspace folder when workspace folder is passed', async () => { + test('application settings are not read from workspace folder when workspace folder is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.applicationSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.applicationSetting": "workspaceFolderValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.applicationSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('machine settings are not read from workspace folder', async () => { + test('machine settings are not read from workspace folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.machineSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.machineSetting": "workspaceFolderValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue'); - }); + })); - test('machine settings are not read from workspace folder when workspace folder is passed', async () => { + test('machine settings are not read from workspace folder when workspace folder is passed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.machineSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.machineSetting": "workspaceFolderValue" }')); await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.machineSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('application settings are not read from workspace folder after defaults are registered', async () => { + test('application settings are not read from workspace folder after defaults are registered', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.testNewApplicationSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testNewApplicationSetting": "workspaceFolderValue" }')); @@ -1928,9 +1928,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.testNewApplicationSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('application settings are not read from workspace folder after defaults are registered', async () => { + test('application settings are not read from workspace folder after defaults are registered', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.testNewMachineSetting": "userValue" }')); await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testNewMachineSetting": "workspaceFolderValue" }')); await testObject.reloadConfiguration(); @@ -1953,9 +1953,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); assert.strictEqual(testObject.getValue('configurationService.workspace.testNewMachineSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); - }); + })); - test('resource setting in folder is read after it is registered later', async () => { + test('resource setting in folder is read after it is registered later', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testNewResourceSetting2": "workspaceFolderValue" }')); await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.testNewResourceSetting2': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); @@ -1971,9 +1971,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { } }); assert.strictEqual(testObject.getValue('configurationService.workspace.testNewResourceSetting2', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'workspaceFolderValue'); - }); + })); - test('resource language setting in folder is read after it is registered later', async () => { + test('resource language setting in folder is read after it is registered later', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testNewResourceLanguageSetting2": "workspaceFolderValue" }')); await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.testNewResourceLanguageSetting2': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); @@ -1989,9 +1989,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { } }); assert.strictEqual(testObject.getValue('configurationService.workspace.testNewResourceLanguageSetting2', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'workspaceFolderValue'); - }); + })); - test('machine overridable setting in folder is read after it is registered later', async () => { + test('machine overridable setting in folder is read after it is registered later', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testNewMachineOverridableSetting2": "workspaceFolderValue" }')); await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.testNewMachineOverridableSetting2': 'workspaceValue' } }], true); await testObject.reloadConfiguration(); @@ -2007,9 +2007,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { } }); assert.strictEqual(testObject.getValue('configurationService.workspace.testNewMachineOverridableSetting2', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'workspaceFolderValue'); - }); + })); - test('inspect', async () => { + test('inspect', () => runWithFakedTimers({ useFakeTimers: true }, async () => { let actual = testObject.inspect('something.missing'); assert.strictEqual(actual.defaultValue, undefined); assert.strictEqual(actual.userValue, undefined); @@ -2050,9 +2050,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(actual.workspaceValue, 'workspaceValue'); assert.strictEqual(actual.workspaceFolderValue, 'workspaceFolderValue'); assert.strictEqual(actual.value, 'workspaceFolderValue'); - }); + })); - test('inspect restricted settings', async () => { + test('inspect restricted settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.testRestrictedSetting1': 'workspaceRestrictedValue' } }], true); await testObject.reloadConfiguration(); @@ -2094,9 +2094,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(actual.workspaceValue, 'workspaceRestrictedValue'); assert.strictEqual(actual.workspaceFolderValue, 'workspaceFolderRestrictedValue'); assert.strictEqual(actual.value, 'workspaceFolderRestrictedValue'); - }); + })); - test('get launch configuration', async () => { + test('get launch configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expectedLaunchConfiguration = { 'version': '0.1.0', 'configurations': [ @@ -2117,9 +2117,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); const actual = testObject.getValue('launch'); assert.deepStrictEqual(actual, expectedLaunchConfiguration); - }); + })); - test('inspect launch configuration', async () => { + test('inspect launch configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expectedLaunchConfiguration = { 'version': '0.1.0', 'configurations': [ @@ -2140,10 +2140,10 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); const actual = testObject.inspect('launch').workspaceValue; assert.deepStrictEqual(actual, expectedLaunchConfiguration); - }); + })); - test('get tasks configuration', async () => { + test('get tasks configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expectedTasksConfiguration = { 'version': '2.0.0', 'tasks': [ @@ -2162,9 +2162,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); const actual = testObject.getValue(TasksSchemaProperties.Tasks); assert.deepStrictEqual(actual, expectedTasksConfiguration); - }); + })); - test('inspect tasks configuration', async () => { + test('inspect tasks configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expectedTasksConfiguration = { 'version': '2.0.0', 'tasks': [ @@ -2183,31 +2183,31 @@ suite('WorkspaceConfigurationService-Multiroot', () => { await testObject.reloadConfiguration(); const actual = testObject.inspect('tasks').workspaceValue; assert.deepStrictEqual(actual, expectedTasksConfiguration); - }); + })); - test('update user configuration', async () => { + test('update user configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER); assert.strictEqual(testObject.getValue('configurationService.workspace.testSetting'), 'userValue'); - }); + })); - test('update user configuration should trigger change event before promise is resolve', async () => { + test('update user configuration should trigger change event before promise is resolve', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER); assert.ok(target.called); - }); + })); - test('update workspace configuration', async () => { + test('update workspace configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE); assert.strictEqual(testObject.getValue('configurationService.workspace.testSetting'), 'workspaceValue'); - }); + })); - test('update workspace configuration should trigger change event before promise is resolve', async () => { + test('update workspace configuration should trigger change event before promise is resolve', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE); assert.ok(target.called); - }); + })); test('update application setting into workspace configuration in a workspace is not supported', () => { return testObject.updateValue('configurationService.workspace.applicationSetting', 'workspaceValue', {}, ConfigurationTarget.WORKSPACE, true) @@ -2225,48 +2225,48 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(() => assert.strictEqual(testObject.getValue('configurationService.workspace.testResourceSetting', { resource: workspace.folders[0].uri }), 'workspaceFolderValue')); }); - test('update resource language configuration in workspace folder', async () => { + test('update resource language configuration in workspace folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('configurationService.workspace.testLanguageSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.strictEqual(testObject.getValue('configurationService.workspace.testLanguageSetting', { resource: workspace.folders[0].uri }), 'workspaceFolderValue'); - }); + })); - test('update workspace folder configuration should trigger change event before promise is resolve', async () => { + test('update workspace folder configuration should trigger change event before promise is resolve', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.ok(target.called); - }); + })); - test('update workspace folder configuration second time should trigger change event before promise is resolve', async () => { + test('update workspace folder configuration second time should trigger change event before promise is resolve', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue2', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.ok(target.called); - }); + })); - test('update machine overridable setting in folder', async () => { + test('update machine overridable setting in folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('configurationService.workspace.machineOverridableSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.strictEqual(testObject.getValue('configurationService.workspace.machineOverridableSetting', { resource: workspace.folders[0].uri }), 'workspaceFolderValue'); - }); + })); - test('update memory configuration', async () => { + test('update memory configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await testObject.updateValue('configurationService.workspace.testSetting', 'memoryValue', ConfigurationTarget.MEMORY); assert.strictEqual(testObject.getValue('configurationService.workspace.testSetting'), 'memoryValue'); - }); + })); - test('update memory configuration should trigger change event before promise is resolve', async () => { + test('update memory configuration should trigger change event before promise is resolve', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const target = sinon.spy(); testObject.onDidChangeConfiguration(target); await testObject.updateValue('configurationService.workspace.testSetting', 'memoryValue', ConfigurationTarget.MEMORY); assert.ok(target.called); - }); + })); - test('remove setting from all targets', async () => { + test('remove setting from all targets', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); const key = 'configurationService.workspace.testResourceSetting'; await testObject.updateValue(key, 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); @@ -2280,28 +2280,28 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(actual.userValue, undefined); assert.strictEqual(actual.workspaceValue, undefined); assert.strictEqual(actual.workspaceFolderValue, undefined); - }); + })); - test('update tasks configuration in a folder', async () => { + test('update tasks configuration in a folder', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); assert.deepStrictEqual(testObject.getValue(TasksSchemaProperties.Tasks, { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }); - }); + })); - test('update launch configuration in a workspace', async () => { + test('update launch configuration in a workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('launch', { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true); assert.deepStrictEqual(testObject.getValue('launch'), { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] }); - }); + })); - test('update tasks configuration in a workspace', async () => { + test('update tasks configuration in a workspace', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspace = workspaceContextService.getWorkspace(); const tasks = { 'version': '2.0.0', tasks: [{ 'label': 'myTask' }] }; await testObject.updateValue('tasks', tasks, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true); assert.deepStrictEqual(testObject.getValue(TasksSchemaProperties.Tasks), tasks); - }); + })); - test('configuration of newly added folder is available on configuration change event', async () => { + test('configuration of newly added folder is available on configuration change event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const workspaceService = testObject; const uri = workspaceService.getWorkspace().folders[1].uri; await workspaceService.removeFolders([uri]); @@ -2318,9 +2318,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); workspaceService.addFolders([{ uri }]); }); - }); + })); - test('restricted setting is read from workspace folders when workspace is trusted', async () => { + test('restricted setting is read from workspace folders when workspace is trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(true); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.testRestrictedSetting1": "userValue", "configurationService.workspace.testRestrictedSetting2": "userValue" }')); @@ -2338,9 +2338,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.get(testObject.getWorkspace().folders[0].uri), undefined); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(testObject.getWorkspace().folders[1].uri), ['configurationService.workspace.testRestrictedSetting2']); - }); + })); - test('restricted setting is not read from workspace when workspace is not trusted', async () => { + test('restricted setting is not read from workspace when workspace is not trusted', () => runWithFakedTimers({ useFakeTimers: true }, async () => { testObject.updateWorkspaceTrust(false); await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.testRestrictedSetting1": "userValue", "configurationService.workspace.testRestrictedSetting2": "userValue" }')); @@ -2358,9 +2358,9 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.size, 1); assert.strictEqual(testObject.restrictedSettings.workspaceFolder?.get(testObject.getWorkspace().folders[0].uri), undefined); assert.deepStrictEqual(testObject.restrictedSettings.workspaceFolder?.get(testObject.getWorkspace().folders[1].uri), ['configurationService.workspace.testRestrictedSetting2']); - }); + })); - test('remove an unregistered setting', async () => { + test('remove an unregistered setting', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const key = 'configurationService.workspace.unknownSetting'; await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.unknownSetting": "userValue" }')); await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.unknownSetting': 'workspaceValue' } }], true); @@ -2380,7 +2380,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(actual.userValue, undefined); assert.strictEqual(actual.workspaceValue, undefined); assert.strictEqual(actual.workspaceFolderValue, undefined); - }); + })); }); @@ -2474,23 +2474,23 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { teardown(() => disposables.clear()); - test('remote settings override globals', async () => { + test('remote settings override globals', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(machineSettingsResource, VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); assert.strictEqual(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); - }); + })); - test('remote settings override globals after remote provider is registered on activation', async () => { + test('remote settings override globals after remote provider is registered on activation', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(machineSettingsResource, VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); resolveRemoteEnvironment(); registerRemoteFileSystemProviderOnActivation(); await initialize(); assert.strictEqual(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); - }); + })); - test('remote settings override globals after remote environment is resolved', async () => { + test('remote settings override globals after remote environment is resolved', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(machineSettingsResource, VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); registerRemoteFileSystemProvider(); await initialize(); @@ -2508,9 +2508,9 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { }); resolveRemoteEnvironment(); return promise; - }); + })); - test('remote settings override globals after remote provider is registered on activation and remote environment is resolved', async () => { + test('remote settings override globals after remote provider is registered on activation and remote environment is resolved', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(machineSettingsResource, VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); registerRemoteFileSystemProviderOnActivation(); await initialize(); @@ -2528,52 +2528,52 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { }); resolveRemoteEnvironment(); return promise; - }); + })); - test('machine settings in local user settings does not override defaults', async () => { + test('machine settings in local user settings does not override defaults', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.remote.machineSetting": "globalValue" }')); registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); assert.strictEqual(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); - }); + })); - test('machine overridable settings in local user settings does not override defaults', async () => { + test('machine overridable settings in local user settings does not override defaults', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.remote.machineOverridableSetting": "globalValue" }')); registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); assert.strictEqual(testObject.getValue('configurationService.remote.machineOverridableSetting'), 'isSet'); - }); + })); - test('non machine setting is written in local settings', async () => { + test('non machine setting is written in local settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); await testObject.updateValue('configurationService.remote.applicationSetting', 'applicationValue'); await testObject.reloadConfiguration(); assert.strictEqual(testObject.inspect('configurationService.remote.applicationSetting').userLocalValue, 'applicationValue'); - }); + })); - test('machine setting is written in remote settings', async () => { + test('machine setting is written in remote settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); await testObject.updateValue('configurationService.remote.machineSetting', 'machineValue'); await testObject.reloadConfiguration(); assert.strictEqual(testObject.inspect('configurationService.remote.machineSetting').userRemoteValue, 'machineValue'); - }); + })); - test('machine overridable setting is written in remote settings', async () => { + test('machine overridable setting is written in remote settings', () => runWithFakedTimers({ useFakeTimers: true }, async () => { registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); await initialize(); await testObject.updateValue('configurationService.remote.machineOverridableSetting', 'machineValue'); await testObject.reloadConfiguration(); assert.strictEqual(testObject.inspect('configurationService.remote.machineOverridableSetting').userRemoteValue, 'machineValue'); - }); + })); - test('machine settings in local user settings does not override defaults after defalts are registered ', async () => { + test('machine settings in local user settings does not override defaults after defalts are registered ', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.remote.newMachineSetting": "userValue" }')); registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); @@ -2590,9 +2590,9 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { } }); assert.strictEqual(testObject.getValue('configurationService.remote.newMachineSetting'), 'isSet'); - }); + })); - test('machine overridable settings in local user settings does not override defaults after defaults are registered ', async () => { + test('machine overridable settings in local user settings does not override defaults after defaults are registered ', () => runWithFakedTimers({ useFakeTimers: true }, async () => { await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.remote.newMachineOverridableSetting": "userValue" }')); registerRemoteFileSystemProvider(); resolveRemoteEnvironment(); @@ -2609,7 +2609,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { } }); assert.strictEqual(testObject.getValue('configurationService.remote.newMachineOverridableSetting'), 'isSet'); - }); + })); }); diff --git a/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts b/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts index 06e375acf9d..8fea43d8892 100644 --- a/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts +++ b/src/vs/workbench/services/views/test/browser/viewContainerModel.test.ts @@ -18,6 +18,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Event } from 'vs/base/common/event'; import { getViewsStateStorageId } from 'vs/workbench/services/views/common/viewContainerModel'; +import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; const ViewContainerRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); const ViewsRegistry = Registry.as(ViewContainerExtensions.ViewsRegistry); @@ -95,7 +96,7 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements.length, 0); }); - test('when contexts', async function () { + test('when contexts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -137,9 +138,9 @@ suite('ViewContainerModel', () => { await new Promise(c => setTimeout(c, 30)); assert.strictEqual(testObject.visibleViewDescriptors.length, 0, 'view should not be there anymore'); assert.strictEqual(target.elements.length, 0); - }); + })); - test('when contexts - multiple', async function () { + test('when contexts - multiple', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -160,9 +161,9 @@ suite('ViewContainerModel', () => { assert.deepStrictEqual(target.elements, [view1, view2], 'both views should be visible'); ViewsRegistry.deregisterViews([view1, view2], container); - }); + })); - test('when contexts - multiple 2', async function () { + test('when contexts - multiple 2', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -183,7 +184,7 @@ suite('ViewContainerModel', () => { assert.deepStrictEqual(target.elements, [view1, view2], 'both views should be visible'); ViewsRegistry.deregisterViews([view1, view2], container); - }); + })); test('setVisible', () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); @@ -259,7 +260,7 @@ suite('ViewContainerModel', () => { assert.deepStrictEqual(target.elements, [view1, view2, view3]); }); - test('view states', async function () { + test('view states', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.PROFILE, StorageTarget.MACHINE); container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); @@ -277,9 +278,9 @@ suite('ViewContainerModel', () => { ViewsRegistry.registerViews([viewDescriptor], container); assert.strictEqual(testObject.visibleViewDescriptors.length, 0, 'view should not appear since it was set not visible in view state'); assert.strictEqual(target.elements.length, 0); - }); + })); - test('view states and when contexts', async function () { + test('view states and when contexts', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.PROFILE, StorageTarget.MACHINE); container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); @@ -307,9 +308,9 @@ suite('ViewContainerModel', () => { await new Promise(c => setTimeout(c, 30)); assert.strictEqual(testObject.visibleViewDescriptors.length, 0, 'view should still not appear since it was set not visible in view state'); assert.strictEqual(target.elements.length, 0); - }); + })); - test('view states and when contexts multiple views', async function () { + test('view states and when contexts multiple views', () => runWithFakedTimers({ useFakeTimers: true }, async () => { storageService.store(`${container.id}.state.hidden`, JSON.stringify([{ id: 'view1', isHidden: true }]), StorageScope.PROFILE, StorageTarget.MACHINE); container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); @@ -353,9 +354,9 @@ suite('ViewContainerModel', () => { await new Promise(c => setTimeout(c, 30)); assert.deepStrictEqual(testObject.visibleViewDescriptors, [view2], 'Only view2 should be visible'); assert.deepStrictEqual(target.elements, [view2]); - }); + })); - test('remove event is not triggered if view was hidden and removed', async function () { + test('remove event is not triggered if view was hidden and removed', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -383,9 +384,9 @@ suite('ViewContainerModel', () => { key.set(false); await new Promise(c => setTimeout(c, 30)); assert.ok(!targetEvent.called, 'remove event should not be called since it is already hidden'); - }); + })); - test('add event is not triggered if view was set visible (when visible) and not active', async function () { + test('add event is not triggered if view was set visible (when visible) and not active', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -410,9 +411,9 @@ suite('ViewContainerModel', () => { assert.ok(!targetEvent.called, 'add event should not be called since it is already visible'); assert.strictEqual(testObject.visibleViewDescriptors.length, 0); assert.strictEqual(target.elements.length, 0); - }); + })); - test('remove event is not triggered if view was hidden and not active', async function () { + test('remove event is not triggered if view was hidden and not active', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -437,9 +438,9 @@ suite('ViewContainerModel', () => { assert.ok(!targetEvent.called, 'add event should not be called since it is disabled'); assert.strictEqual(testObject.visibleViewDescriptors.length, 0); assert.strictEqual(target.elements.length, 0); - }); + })); - test('add event is not triggered if view was set visible (when not visible) and not active', async function () { + test('add event is not triggered if view was set visible (when not visible) and not active', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -468,9 +469,9 @@ suite('ViewContainerModel', () => { assert.ok(!targetEvent.called, 'add event should not be called since it is disabled'); assert.strictEqual(testObject.visibleViewDescriptors.length, 0); assert.strictEqual(target.elements.length, 0); - }); + })); - test('added view descriptors are in ascending order in the event', async function () { + test('added view descriptors are in ascending order in the event', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -519,9 +520,9 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements[2].id, 'view3'); assert.strictEqual(target.elements[3].id, 'view4'); assert.strictEqual(target.elements[4].id, 'view5'); - }); + })); - test('add event is triggered only once when view is set visible while it is set active', async function () { + test('add event is triggered only once when view is set visible while it is set active', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -550,9 +551,9 @@ suite('ViewContainerModel', () => { assert.strictEqual(testObject.visibleViewDescriptors.length, 1); assert.strictEqual(target.elements.length, 1); assert.strictEqual(target.elements[0].id, 'view1'); - }); + })); - test('add event is not triggered only when view is set hidden while it is set active', async function () { + test('add event is not triggered only when view is set hidden while it is set active', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -579,9 +580,9 @@ suite('ViewContainerModel', () => { assert.strictEqual(targetEvent.callCount, 0); assert.strictEqual(testObject.visibleViewDescriptors.length, 0); assert.strictEqual(target.elements.length, 0); - }); + })); - test('#142087: view descriptor visibility is not reset', async function () { + test('#142087: view descriptor visibility is not reset', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const viewDescriptor: IViewDescriptor = { @@ -602,9 +603,9 @@ suite('ViewContainerModel', () => { assert.strictEqual(testObject.isVisible(viewDescriptor.id), false); assert.strictEqual(testObject.activeViewDescriptors[0].id, viewDescriptor.id); assert.strictEqual(testObject.visibleViewDescriptors.length, 0); - }); + })); - test('remove event is triggered properly if mutliple views are hidden at the same time', async function () { + test('remove event is triggered properly if mutliple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -660,9 +661,9 @@ suite('ViewContainerModel', () => { }]); assert.strictEqual(target.elements.length, 1); assert.strictEqual(target.elements[0].id, viewDescriptor1.id); - }); + })); - test('add event is triggered properly if mutliple views are hidden at the same time', async function () { + test('add event is triggered properly if mutliple views are hidden at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -728,9 +729,9 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements[0].id, viewDescriptor1.id); assert.strictEqual(target.elements[1].id, viewDescriptor2.id); assert.strictEqual(target.elements[2].id, viewDescriptor3.id); - }); + })); - test('add and remove events are triggered properly if mutliple views are hidden and added at the same time', async function () { + test('add and remove events are triggered properly if mutliple views are hidden and added at the same time', () => runWithFakedTimers({ useFakeTimers: true }, async () => { container = ViewContainerRegistry.registerViewContainer({ id: 'test', title: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); const testObject = viewDescriptorService.getViewContainerModel(container); const target = disposableStore.add(new ViewDescriptorSequence(testObject)); @@ -805,6 +806,6 @@ suite('ViewContainerModel', () => { assert.strictEqual(target.elements.length, 2); assert.strictEqual(target.elements[0].id, viewDescriptor1.id); assert.strictEqual(target.elements[1].id, viewDescriptor3.id); - }); + })); }); From 77f39a3f87be1d96bd235860c15e530005208dce Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 15:34:57 +0200 Subject: [PATCH 444/599] use registerAction2 (#163174) --- .../contrib/logs/browser/logs.contribution.ts | 21 ++++++++--- .../contrib/logs/common/logs.contribution.ts | 20 +++++++--- .../contrib/logs/common/logsActions.ts | 4 +- .../electron-sandbox/logs.contribution.ts | 37 ++++++++++++++++--- .../logs/electron-sandbox/logsActions.ts | 4 +- .../browser/keybindingsEditorModel.test.ts | 23 ++++++------ 6 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts index 992093fe0b3..23f019bac51 100644 --- a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Disposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { LogsDataCleaner } from 'vs/workbench/contrib/logs/common/logsDataCleaner'; class WebLogOutputChannels extends Disposable implements IWorkbenchContribution { @@ -26,8 +25,20 @@ class WebLogOutputChannels extends Disposable implements IWorkbenchContribution private registerWebContributions(): void { this.instantiationService.createInstance(LogsDataCleaner); - const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); - workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenWindowSessionLogFileAction), 'Developer: Open Window Log File (Session)...', Categories.Developer.value); + registerAction2(class extends Action2 { + constructor() { + super({ + id: OpenWindowSessionLogFileAction.ID, + title: OpenWindowSessionLogFileAction.TITLE, + category: Categories.Developer, + f1: true + }); + } + run(servicesAccessor: ServicesAccessor): Promise { + return servicesAccessor.get(IInstantiationService).createInstance(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.TITLE.value).run(); + } + }); + } } diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index f8f07b98ad4..3cd2ad0dd85 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -5,9 +5,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { Action2, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -17,13 +16,24 @@ import { IOutputService, registerLogChannel } from 'vs/workbench/services/output import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IProductService } from 'vs/platform/product/common/productService'; import { URI } from 'vs/base/common/uri'; -const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SetLogLevelAction), 'Developer: Set Log Level...', Categories.Developer.value); +registerAction2(class extends Action2 { + constructor() { + super({ + id: SetLogLevelAction.ID, + title: SetLogLevelAction.TITLE, + category: Categories.Developer, + f1: true + }); + } + run(servicesAccessor: ServicesAccessor): Promise { + return servicesAccessor.get(IInstantiationService).createInstance(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.TITLE.value).run(); + } +}); class LogOutputChannels extends Disposable implements IWorkbenchContribution { diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index a53f539aa00..b5b49b6c12b 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -16,7 +16,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic export class SetLogLevelAction extends Action { static readonly ID = 'workbench.action.setLogLevel'; - static readonly LABEL = nls.localize('setLogLevel', "Set Log Level..."); + static readonly TITLE = { value: nls.localize('setLogLevel', "Set Log Level..."), original: 'Set Log Level...' }; constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -61,7 +61,7 @@ export class SetLogLevelAction extends Action { export class OpenWindowSessionLogFileAction extends Action { static readonly ID = 'workbench.action.openSessionLogFile'; - static readonly LABEL = nls.localize('openSessionLogFile', "Open Window Log File (Session)..."); + static readonly TITLE = { value: nls.localize('openSessionLogFile', "Open Window Log File (Session)..."), original: 'Open Window Log File (Session)...' }; constructor(id: string, label: string, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts index 26e63c77ca9..5066dfcfe34 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts @@ -5,9 +5,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { OpenLogsFolderAction, OpenExtensionLogsFolderAction } from 'vs/workbench/contrib/logs/electron-sandbox/logsActions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; @@ -19,6 +18,8 @@ import { URI } from 'vs/base/common/uri'; import { join } from 'vs/base/common/path'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { registerLogChannel } from 'vs/workbench/services/output/common/output'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; class NativeLogOutputChannels extends Disposable implements IWorkbenchContribution { @@ -43,8 +44,32 @@ class NativeLogOutputChannels extends Disposable implements IWorkbenchContributi } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeLogOutputChannels, LifecyclePhase.Restored); +registerAction2(class extends Action2 { + constructor() { + super({ + id: OpenLogsFolderAction.ID, + title: OpenLogsFolderAction.TITLE, + category: Categories.Developer, + f1: true + }); + } + run(servicesAccessor: ServicesAccessor): Promise { + return servicesAccessor.get(IInstantiationService).createInstance(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.TITLE.value).run(); + } +}); -const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenLogsFolderAction), 'Developer: Open Logs Folder', Categories.Developer.value); -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenExtensionLogsFolderAction), 'Developer: Open Extension Logs Folder', Categories.Developer.value); +registerAction2(class extends Action2 { + constructor() { + super({ + id: OpenExtensionLogsFolderAction.ID, + title: OpenExtensionLogsFolderAction.TITLE, + category: Categories.Developer, + f1: true + }); + } + run(servicesAccessor: ServicesAccessor): Promise { + return servicesAccessor.get(IInstantiationService).createInstance(OpenExtensionLogsFolderAction, OpenExtensionLogsFolderAction.ID, OpenExtensionLogsFolderAction.TITLE.value).run(); + } +}); + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeLogOutputChannels, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts index 1ea86c56d77..25a15ac8d9a 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts @@ -14,7 +14,7 @@ import { IFileService } from 'vs/platform/files/common/files'; export class OpenLogsFolderAction extends Action { static readonly ID = 'workbench.action.openLogsFolder'; - static readonly LABEL = nls.localize('openLogsFolder', "Open Logs Folder"); + static readonly TITLE = { value: nls.localize('openLogsFolder', "Open Logs Folder"), original: 'Open Logs Folder' }; constructor(id: string, label: string, @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, @@ -31,7 +31,7 @@ export class OpenLogsFolderAction extends Action { export class OpenExtensionLogsFolderAction extends Action { static readonly ID = 'workbench.action.openExtensionLogsFolder'; - static readonly LABEL = nls.localize('openExtensionLogsFolder', "Open Extension Logs Folder"); + static readonly TITLE = { value: nls.localize('openExtensionLogsFolder', "Open Extension Logs Folder"), original: 'Open Extension Logs Folder' }; constructor(id: string, label: string, @INativeWorkbenchEnvironmentService private readonly environmentSerice: INativeWorkbenchEnvironmentService, diff --git a/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts index 341f95fd936..62c6d2c84fa 100644 --- a/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts @@ -6,13 +6,9 @@ import * as assert from 'assert'; import * as uuid from 'vs/base/common/uuid'; import { OS, OperatingSystem } from 'vs/base/common/platform'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Action } from 'vs/base/common/actions'; import { KeyCode } from 'vs/base/common/keyCodes'; import { SimpleKeybinding, ChordKeybinding } from 'vs/base/common/keybindings'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -22,6 +18,7 @@ import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayo import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IKeybindingItemEntry } from 'vs/workbench/services/preferences/common/preferences'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; interface Modifiers { metaKey?: boolean; @@ -30,12 +27,6 @@ interface Modifiers { shiftKey?: boolean; } -class AnAction extends Action { - constructor(id: string) { - super(id); - } -} - suite('KeybindingsEditorModel', () => { let instantiationService: TestInstantiationService; @@ -677,8 +668,16 @@ suite('KeybindingsEditorModel', () => { } function registerCommandWithTitle(command: string, title: string): void { - const registry = Registry.as(ActionExtensions.WorkbenchActions); - registry.registerWorkbenchAction(SyncActionDescriptor.create(AnAction, command, title, { primary: 0 }), ''); + registerAction2(class extends Action2 { + constructor() { + super({ + id: command, + title, + f1: true + }); + } + async run(): Promise { } + }); } function assertKeybindingItems(actual: ResolvedKeybindingItem[], expected: ResolvedKeybindingItem[]) { From 8ea1dee83c522efeaac51206b5664a8639b8b987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 10 Oct 2022 06:54:07 -0700 Subject: [PATCH 445/599] Revert "Revert "update inno_updater to 0.9.0 (#162933)" (#163156)" (#163178) This reverts commit 8e1235ee25e3aad3598ab58016c071b5596b826a. --- build/win32/inno_updater.exe | Bin 403456 -> 443904 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index 8c532b9eb5eab2fe843d29b8d488676263e4c1d7..fea47a59c9dae3b351f96a05c4d4d1e9040fe9df 100644 GIT binary patch literal 443904 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°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%0A9)8TdoI|6;GG3~5i)v%cQ8QBLt|FyQov;x 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 VWWM(w1v!UrE)o16{~!PFe*tpjB0>NF literal 403456 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

xi8_O&2bA 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 N{PutT`Tr~e{|o8s+tUC5 From 6ad64356e1ea2f2e44c960519c41e209cf288690 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 16:05:02 +0200 Subject: [PATCH 446/599] Fix #162739 (#163179) --- .../contrib/extensions/browser/extensions.contribution.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index f5bb723e3b7..4bbf610ea74 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -586,7 +586,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)) }, { id: MenuId.ViewContainerTitle, - when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID), + when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), CONTEXT_HAS_GALLERY), group: '1_updates', order: 1 }], @@ -605,7 +605,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, { submenu: autoUpdateExtensionsSubMenu, title: localize('configure auto updating extensions', "Auto Update Extensions"), - when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID), + when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), CONTEXT_HAS_GALLERY), group: '1_updates', order: 5, }); @@ -681,6 +681,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi title: { value: localize('disableAutoUpdate', "Disable Auto Update for all extensions"), original: 'Disable Auto Update for all extensions' }, category: ExtensionsLocalizedLabel, f1: true, + precondition: CONTEXT_HAS_GALLERY, run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, false) }); @@ -689,6 +690,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi title: { value: localize('enableAutoUpdate', "Enable Auto Update for all extensions"), original: 'Enable Auto Update for all extensions' }, category: ExtensionsLocalizedLabel, f1: true, + precondition: CONTEXT_HAS_GALLERY, run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, true) }); @@ -991,11 +993,13 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi id: 'workbench.extensions.action.extensionUpdates', title: { value: localize('extensionUpdates', "Show Extension Updates"), original: 'Show Extension Updates' }, category: ExtensionsLocalizedLabel, + precondition: CONTEXT_HAS_GALLERY, menu: [{ id: MenuId.CommandPalette, }, { id: extensionsFilterSubMenu, group: '3_installed', + when: CONTEXT_HAS_GALLERY, order: 1, }], menuTitles: { From a5a5a7fc73bf6e732b27b6fdf59ef0c52772ee00 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 17:04:31 +0200 Subject: [PATCH 447/599] fix command id for showing output channel (#163185) --- .../workbench/contrib/output/browser/output.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index ab7c785f4f8..f3fbd0f9294 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -140,7 +140,7 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { registeredChannels.set(channel.id, registerAction2(class extends Action2 { constructor() { super({ - id: channel.id, + id: `workbench.action.output.show.${channel.id}`, title, toggled: ACTIVE_OUTPUT_CHANNEL_CONTEXT.isEqualTo(channel.id), menu: { @@ -150,7 +150,7 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { }); } async run(accessor: ServicesAccessor): Promise { - return accessor.get(IOutputService).showChannel(this.desc.id, true); + return accessor.get(IOutputService).showChannel(channel.id, true); } })); } From 96ee91332f0980eb3140ab549403a2e7db19ad19 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 10 Oct 2022 18:16:04 +0200 Subject: [PATCH 448/599] Fix style of comment thread title (#163192) Fixes #163140 --- src/vs/workbench/contrib/comments/browser/media/review.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index b92ceed75a1..bbbd5f93da9 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -326,6 +326,9 @@ font-size: 13px; margin-left: 20px; cursor: default; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .review-widget .head .review-title .dirname:not(:empty) { From 23e6c032afd6747ea25ac9524f3d8addcfe26039 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 10 Oct 2022 19:10:24 +0200 Subject: [PATCH 449/599] Start enforcing the tunnels API (#163187) * Start enforcing the tunnels API * Fix API test --- extensions/vscode-api-tests/package.json | 1 + extensions/vscode-test-resolver/package.json | 3 +- extensions/vscode-test-resolver/tsconfig.json | 1 + .../workbench/api/common/extHost.api.impl.ts | 6 ++-- src/vscode-dts/vscode.proposed.resolvers.d.ts | 29 ++----------------- src/vscode-dts/vscode.proposed.tunnels.d.ts | 10 ++++++- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 07e71c1daaf..c705e53d1fa 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -34,6 +34,7 @@ "taskPresentationGroup", "terminalDataWriteEvent", "terminalDimensions", + "tunnels", "envShellEvent", "testCoverage", "testObserver", diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json index da90e7e3809..167275aa275 100644 --- a/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -6,7 +6,8 @@ "license": "MIT", "enableProposedApi": true, "enabledApiProposals": [ - "resolvers" + "resolvers", + "tunnels" ], "private": true, "engines": { diff --git a/extensions/vscode-test-resolver/tsconfig.json b/extensions/vscode-test-resolver/tsconfig.json index f9a183ef9e1..4a8025df9b5 100644 --- a/extensions/vscode-test-resolver/tsconfig.json +++ b/extensions/vscode-test-resolver/tsconfig.json @@ -9,6 +9,7 @@ "include": [ "src/**/*", "../../src/vscode-dts/vscode.d.ts", + "../../src/vscode-dts/vscode.proposed.tunnels.d.ts", "../../src/vscode-dts/vscode.proposed.resolvers.d.ts" ] } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 8e0c6af5fbd..f03c90350d7 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1010,7 +1010,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables); }, openTunnel: (forward: vscode.TunnelOptions) => { - checkProposedApiEnabled(extension, 'resolvers'); + checkProposedApiEnabled(extension, 'tunnels'); return extHostTunnelService.openTunnel(extension, forward).then(value => { if (!value) { throw new Error('cannot open tunnel'); @@ -1019,11 +1019,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }); }, get tunnels() { - checkProposedApiEnabled(extension, 'resolvers'); + checkProposedApiEnabled(extension, 'tunnels'); return extHostTunnelService.getTunnels(); }, onDidChangeTunnels: (listener, thisArg?, disposables?) => { - checkProposedApiEnabled(extension, 'resolvers'); + checkProposedApiEnabled(extension, 'tunnels'); return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables); }, registerPortAttributesProvider: (portSelector: { pid?: number; portRange?: [number, number]; commandMatcher?: RegExp }, provider: vscode.PortAttributesProvider) => { diff --git a/src/vscode-dts/vscode.proposed.resolvers.d.ts b/src/vscode-dts/vscode.proposed.resolvers.d.ts index 292b5a5fb23..c1c413bc31f 100644 --- a/src/vscode-dts/vscode.proposed.resolvers.d.ts +++ b/src/vscode-dts/vscode.proposed.resolvers.d.ts @@ -43,7 +43,7 @@ declare module 'vscode' { label: string; } - export interface TunnelOptions { + interface TunnelOptions { remoteAddress: { port: number; host: string }; // The desired local port. If this port can't be used, then another will be chosen. localAddressPort?: number; @@ -56,7 +56,7 @@ declare module 'vscode' { protocol?: string; } - export interface TunnelDescription { + interface TunnelDescription { remoteAddress: { port: number; host: string }; //The complete local address(ex. localhost:1234) localAddress: { port: number; host: string } | string; @@ -69,7 +69,7 @@ declare module 'vscode' { protocol?: string; } - export interface Tunnel extends TunnelDescription { + interface Tunnel extends TunnelDescription { // Implementers of Tunnel should fire onDidDispose when dispose is called. onDidDispose: Event; dispose(): void | Thenable; @@ -164,29 +164,6 @@ declare module 'vscode' { candidatePortSource?: CandidatePortSource; } - export namespace workspace { - /** - * Forwards a port. If the current resolver implements RemoteAuthorityResolver:forwardPort then that will be used to make the tunnel. - * By default, openTunnel only support localhost; however, RemoteAuthorityResolver:tunnelFactory can be used to support other ips. - * - * @throws When run in an environment without a remote. - * - * @param tunnelOptions The `localPort` is a suggestion only. If that port is not available another will be chosen. - */ - export function openTunnel(tunnelOptions: TunnelOptions): Thenable; - - /** - * Gets an array of the currently available tunnels. This does not include environment tunnels, only tunnels that have been created by the user. - * Note that these are of type TunnelDescription and cannot be disposed. - */ - // export let tunnels: Thenable; - - /** - * Fired when the list of tunnels has changed. - */ - export const onDidChangeTunnels: Event; - } - export interface ResourceLabelFormatter { scheme: string; authority?: string; diff --git a/src/vscode-dts/vscode.proposed.tunnels.d.ts b/src/vscode-dts/vscode.proposed.tunnels.d.ts index 4ff7a18f037..1f83bbbeb90 100644 --- a/src/vscode-dts/vscode.proposed.tunnels.d.ts +++ b/src/vscode-dts/vscode.proposed.tunnels.d.ts @@ -12,6 +12,10 @@ declare module 'vscode' { // The desired local port. If this port can't be used, then another will be chosen. localAddressPort?: number; label?: string; + /** + * @deprecated Use privacy instead + */ + public?: boolean; privacy?: string; protocol?: string; } @@ -20,6 +24,10 @@ declare module 'vscode' { remoteAddress: { port: number; host: string }; //The complete local address(ex. localhost:1234) localAddress: { port: number; host: string } | string; + /** + * @deprecated Use privacy instead + */ + public?: boolean; privacy?: string; // If protocol is not provided it is assumed to be http, regardless of the localAddress. protocol?: string; @@ -51,6 +59,6 @@ declare module 'vscode' { /** * Fired when the list of tunnels has changed. */ - // export const onDidChangeTunnels: Event; + export const onDidChangeTunnels: Event; } } From 1da18901809e7ac3b0888d39dd2f36a71d271f48 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 10 Oct 2022 10:14:55 -0700 Subject: [PATCH 450/599] Bump milestone in endgame notebooks (#163198) * Bump milestone * Bump milestone in my-endgame notebook --- .vscode/notebooks/endgame.github-issues | 2 +- .vscode/notebooks/my-endgame.github-issues | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index e30128e3b7f..82e9dbfbb8b 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n$MILESTONE=milestone:\"September 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\r\n\r\n$MILESTONE=milestone:\"October 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 6464e61afa6..3bfee2f4e4c 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\n\n$MILESTONE=milestone:\"September 2022\"\n\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n\r\n\r\n$MILESTONE=milestone:\"October 2022\"\r\n\r\n$MINE=assignee:@me" }, { "kind": 1, From b1043c1073390277ee341040123ae77bd37ddce7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 10 Oct 2022 10:25:58 -0700 Subject: [PATCH 451/599] Adopt `trackDisposable` for `DisposableMap` (#163200) --- src/vs/base/common/lifecycle.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 35dae84378c..b57542c8497 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -452,9 +452,14 @@ export class DisposableMap implements ID private readonly _store = new Map(); private _isDisposed = false; + constructor() { + trackDisposable(this); + } + dispose() { - this.clearAndDisposeAll(); + markAsDisposed(this); this._isDisposed = true; + this.clearAndDisposeAll(); } clearAndDisposeAll() { From d39c1b3ee058ade91ce61cdecf36698498dd1579 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 10 Oct 2022 10:35:58 -0700 Subject: [PATCH 452/599] Remove unused field (#163199) --- src/vs/workbench/api/browser/mainThreadWindow.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index a0ad6dbd0e1..79cf2c48a96 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; @@ -16,7 +16,6 @@ export class MainThreadWindow implements MainThreadWindowShape { private readonly proxy: ExtHostWindowShape; private readonly disposables = new DisposableStore(); - private readonly resolved = new Map(); constructor( extHostContext: IExtHostContext, @@ -31,11 +30,6 @@ export class MainThreadWindow implements MainThreadWindowShape { dispose(): void { this.disposables.dispose(); - - for (const value of this.resolved.values()) { - value.dispose(); - } - this.resolved.clear(); } $getWindowVisibility(): Promise { From 1b11bc6724a1b15a9fa129fb02616ba461ed9cc8 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 10 Oct 2022 10:16:02 -0700 Subject: [PATCH 453/599] address pr comments --- build/azure-pipelines/cli/test.yml | 5 - .../darwin/cli-build-darwin.yml | 29 +++--- .../darwin/product-build-darwin-cli-sign.yml | 19 ++-- .../darwin/product-build-darwin.yml | 19 ++-- .../azure-pipelines/linux/cli-build-linux.yml | 35 ++++--- .../linux/product-build-linux-client.yml | 17 ++-- build/azure-pipelines/product-build.yml | 92 +++++++------------ .../azure-pipelines/win32/cli-build-win32.yml | 45 +++++---- .../win32/product-build-win32-cli-sign.yml | 22 +++-- .../win32/product-build-win32.yml | 17 ++-- 10 files changed, 149 insertions(+), 151 deletions(-) diff --git a/build/azure-pipelines/cli/test.yml b/build/azure-pipelines/cli/test.yml index 38db2f166b8..d17175e4758 100644 --- a/build/azure-pipelines/cli/test.yml +++ b/build/azure-pipelines/cli/test.yml @@ -2,11 +2,6 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object - - name: VSCODE_CLI_DIR - type: string - default: './' - - name: VSCODE_CLI_BINARY_NAME - type: string - name: VSCODE_CLI_RUST_CHANNEL type: string default: stable diff --git a/build/azure-pipelines/darwin/cli-build-darwin.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml index f31fb4708d4..bb1a71c9437 100644 --- a/build/azure-pipelines/darwin/cli-build-darwin.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -1,17 +1,22 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string + - name: VSCODE_BUILD_MACOS + type: boolean + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - { target: x86_64-apple-darwin, artifact: unsigned_vscode_cli_darwin_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - { target: aarch64-apple-darwin, artifact: unsigned_vscode_cli_darwin_arm64_cli } + steps: - task: NodeTool@0 inputs: @@ -30,12 +35,12 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} + targets: ${{ variables.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in variables.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -46,7 +51,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index f1aa2f1c5ef..b36e338d78b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -1,9 +1,16 @@ parameters: - - name: VSCODE_CLI_BINARY_NAME - type: string + - name: VSCODE_BUILD_MACOS + type: boolean + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean + +variables: - name: VSCODE_CLI_ARTIFACTS - default: [] - type: object + value: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - unsigned_vscode_cli_darwin_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - unsigned_vscode_cli_darwin_arm64_cli steps: - task: NodeTool@0 @@ -37,7 +44,7 @@ steps: done displayName: Install build dependencies - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - task: DownloadPipelineArtifact@2 displayName: Download ${{ target }} inputs: @@ -63,7 +70,7 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - script: | - ASSET_ID=$(echo "${{ target }}" | sed "s/not_yet_signed_//") + ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 5778b2af54b..86392ecbc43 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -186,10 +182,13 @@ steps: echo "##vso[task.setvariable variable=APP_PATH]$APP_ROOT/$APP_NAME" displayName: Find application path - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: unsigned_vscode_cli_darwin_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: unsigned_vscode_cli_darwin_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -197,9 +196,9 @@ steps: - script: | set -e unzip "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -d "$(APP_PATH)/Contents/Resources/app/bin" - chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" + chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" + mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" fi displayName: Make CLI executable diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml index 9c219919aaf..a96a784b659 100644 --- a/build/azure-pipelines/linux/cli-build-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -1,17 +1,28 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object + - name: VSCODE_BUILD_LINUX_ALPINE + type: boolean + - name: VSCODE_BUILD_LINUX + type: boolean - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_ARCH, 'x86') }}: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } + steps: # inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile - bash: | @@ -37,12 +48,12 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} + targets: ${{ variables.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in variables.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -55,7 +66,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel includeRootFolder: false archiveType: tar tarCompression: gz diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 6e12a1167ce..cf2af3a2af3 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -258,10 +254,13 @@ steps: yarn gulp "transpile-client-swc" "transpile-extensions" displayName: Transpile - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: vscode_cli_linux_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: vscode_cli_linux_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -270,7 +269,7 @@ steps: set -e tar -xzvf $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" + mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" fi displayName: Make CLI executable diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index c0baba98066..419a8c54056 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -141,8 +141,6 @@ variables: value: true - name: Codeql.SkipTaskAutoInjection value: true - - name: VSCODE_CLI_BINARY_NAME - value: code-tunnel resources: containers: @@ -184,21 +182,20 @@ stages: - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: - job: LinuxX86 pool: vscode-1es-linux + variables: + VSCODE_ARCH: x64 steps: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: - - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } + VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} + VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }}: - job: LinuxArm64 pool: vscode-1es-linux-20.04-arm64 + variables: + VSCODE_ARCH: arm64 steps: - task: NodeTool@0 displayName: Install Node.js @@ -213,13 +210,9 @@ stages: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: - - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } + VSCODE_BUILD_ARCH: arm64 + VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} + VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_MACOS, true) }}: - job: MacOS @@ -229,13 +222,8 @@ stages: - template: ./darwin/cli-build-darwin.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - { target: x86_64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - { target: aarch64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_arm64_cli } + VSCODE_BUILD_MACOS: ${{ variables.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ variables.VSCODE_BUILD_MACOS_ARM64 }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_WINDOWS, true) }}: - job: Windows @@ -244,13 +232,8 @@ stages: - template: ./win32/cli-build-win32.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - { target: x86_64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - { target: aarch64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_arm64_cli } + VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -311,12 +294,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: - job: Windows32 @@ -328,6 +309,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false # todo until 32 bit CLI is available VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -342,12 +324,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: - job: windowsCLISign @@ -355,12 +335,8 @@ stages: steps: - template: win32/product-build-win32-cli-sign.yml parameters: - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_ARTIFACTS: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - not_yet_signed_vscode_cli_win32_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - not_yet_signed_vscode_cli_win32_arm64_cli + VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -409,6 +385,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -424,6 +401,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true VSCODE_RUN_SMOKE_TESTS: false @@ -439,6 +417,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: true @@ -455,12 +434,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true), ne(variables['VSCODE_PUBLISH'], 'false')) }}: - job: LinuxSnap @@ -483,6 +460,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false # todo: not build yet VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -509,12 +487,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} # TODO@joaomoreno: We don't ship ARM snaps for now - ${{ if and(false, eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}: @@ -564,6 +540,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -577,6 +554,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true VSCODE_RUN_SMOKE_TESTS: false @@ -590,6 +568,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: true @@ -604,12 +583,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: - job: macOSTest @@ -621,6 +598,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -641,12 +619,8 @@ stages: steps: - template: darwin/product-build-darwin-cli-sign.yml parameters: - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_ARTIFACTS: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - not_yet_signed_vscode_cli_darwin_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - not_yet_signed_vscode_cli_darwin_arm64_cli + VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 @@ -658,12 +632,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: - job: macOSARM64Sign diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index f203f430942..3b5525b930d 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -1,17 +1,22 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object + - name: VSCODE_BUILD_WIN32 + type: boolean + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - { target: x86_64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - { target: aarch64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_arm64_cli } + steps: - task: NodeTool@0 inputs: @@ -33,20 +38,20 @@ steps: parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - template: ../vcpkg-install.yml - parameters: - targets: - - ${{ if eq(target.target, 'x86_64-pc-windows-msvc') }}: - - x64-windows-static-md - - ${{ if eq(target.target, 'aarch64-pc-windows-msvc') }}: - - arm64-windows-static-md - vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg - targetDirectory: $(Build.ArtifactStagingDirectory)/deps + - template: ../vcpkg-install.yml + parameters: + targets: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - x64-windows-static-md + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - arm64-windows-static-md + vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg + targetDirectory: $(Build.ArtifactStagingDirectory)/deps - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -63,7 +68,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel.exe includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index db38e753738..f1b2e80a117 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -1,10 +1,16 @@ parameters: - - name: VSCODE_CLI_BINARY_NAME - type: string - - name: VSCODE_CLI_ARTIFACTS - default: [] - type: object + - name: VSCODE_BUILD_WIN32 + type: boolean + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean +variables: + - name: VSCODE_CLI_ARTIFACTS + value: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - unsigned_vscode_cli_win32_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - unsigned_vscode_cli_win32_arm64_cli steps: - task: NodeTool@0 displayName: "Use Node.js" @@ -24,7 +30,7 @@ steps: KeyVaultName: vscode SecretsFilter: "ESRP-PKI,esrp-aad-username,esrp-aad-password" - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - task: DownloadPipelineArtifact@2 displayName: Download artifacts inputs: @@ -63,13 +69,13 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - powershell: | - $ASSET_ID = "${{ target }}".replace("not_yet_signed_", ""); + $ASSET_ID = "${{ target }}".replace("unsigned_", ""); echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - task: ArchiveFiles@2 inputs: - rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code-tunnel.exe includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index caec3dc49e2..6827c27d5eb 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -181,10 +177,13 @@ steps: echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)" displayName: Build - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: unsigned_vscode_cli_win32_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: unsigned_vscode_cli_win32_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -195,7 +194,7 @@ steps: if ("$(VSCODE_QUALITY)" -ne "stable") { - Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME).exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY).exe" + Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY).exe" } displayName: Move VS Code CLI From 191dc770d1393b262d8cf8c98b12d04053ae5109 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 10 Oct 2022 10:16:02 -0700 Subject: [PATCH 454/599] address pr comments --- build/azure-pipelines/cli/test.yml | 5 - .../darwin/cli-build-darwin.yml | 29 +++--- .../darwin/product-build-darwin-cli-sign.yml | 19 ++-- .../darwin/product-build-darwin.yml | 19 ++-- .../azure-pipelines/linux/cli-build-linux.yml | 35 ++++--- .../linux/product-build-linux-client.yml | 17 ++-- build/azure-pipelines/product-build.yml | 92 +++++++------------ .../azure-pipelines/win32/cli-build-win32.yml | 45 +++++---- .../win32/product-build-win32-cli-sign.yml | 22 +++-- .../win32/product-build-win32.yml | 17 ++-- 10 files changed, 149 insertions(+), 151 deletions(-) diff --git a/build/azure-pipelines/cli/test.yml b/build/azure-pipelines/cli/test.yml index 38db2f166b8..d17175e4758 100644 --- a/build/azure-pipelines/cli/test.yml +++ b/build/azure-pipelines/cli/test.yml @@ -2,11 +2,6 @@ parameters: - name: VSCODE_CLI_TARGETS default: [] type: object - - name: VSCODE_CLI_DIR - type: string - default: './' - - name: VSCODE_CLI_BINARY_NAME - type: string - name: VSCODE_CLI_RUST_CHANNEL type: string default: stable diff --git a/build/azure-pipelines/darwin/cli-build-darwin.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml index f31fb4708d4..bb1a71c9437 100644 --- a/build/azure-pipelines/darwin/cli-build-darwin.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -1,17 +1,22 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string + - name: VSCODE_BUILD_MACOS + type: boolean + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - { target: x86_64-apple-darwin, artifact: unsigned_vscode_cli_darwin_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - { target: aarch64-apple-darwin, artifact: unsigned_vscode_cli_darwin_arm64_cli } + steps: - task: NodeTool@0 inputs: @@ -30,12 +35,12 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} + targets: ${{ variables.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in variables.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -46,7 +51,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index f1aa2f1c5ef..b36e338d78b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -1,9 +1,16 @@ parameters: - - name: VSCODE_CLI_BINARY_NAME - type: string + - name: VSCODE_BUILD_MACOS + type: boolean + - name: VSCODE_BUILD_MACOS_ARM64 + type: boolean + +variables: - name: VSCODE_CLI_ARTIFACTS - default: [] - type: object + value: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - unsigned_vscode_cli_darwin_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - unsigned_vscode_cli_darwin_arm64_cli steps: - task: NodeTool@0 @@ -37,7 +44,7 @@ steps: done displayName: Install build dependencies - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - task: DownloadPipelineArtifact@2 displayName: Download ${{ target }} inputs: @@ -63,7 +70,7 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - script: | - ASSET_ID=$(echo "${{ target }}" | sed "s/not_yet_signed_//") + ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 5778b2af54b..86392ecbc43 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -186,10 +182,13 @@ steps: echo "##vso[task.setvariable variable=APP_PATH]$APP_ROOT/$APP_NAME" displayName: Find application path - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: unsigned_vscode_cli_darwin_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: unsigned_vscode_cli_darwin_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -197,9 +196,9 @@ steps: - script: | set -e unzip "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -d "$(APP_PATH)/Contents/Resources/app/bin" - chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" + chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)" "$(APP_PATH)/Contents/Resources/app/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" + mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" fi displayName: Make CLI executable diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml index 9c219919aaf..a96a784b659 100644 --- a/build/azure-pipelines/linux/cli-build-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -1,17 +1,28 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object + - name: VSCODE_BUILD_LINUX_ALPINE + type: boolean + - name: VSCODE_BUILD_LINUX + type: boolean - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_ARCH, 'x86') }}: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } + steps: # inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile - bash: | @@ -37,12 +48,12 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} + targets: ${{ variables.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in variables.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -55,7 +66,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel includeRootFolder: false archiveType: tar tarCompression: gz diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 6e12a1167ce..cf2af3a2af3 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -258,10 +254,13 @@ steps: yarn gulp "transpile-client-swc" "transpile-extensions" displayName: Transpile - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: vscode_cli_linux_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: vscode_cli_linux_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -270,7 +269,7 @@ steps: set -e tar -xzvf $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY)" + mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" fi displayName: Make CLI executable diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index c0baba98066..419a8c54056 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -141,8 +141,6 @@ variables: value: true - name: Codeql.SkipTaskAutoInjection value: true - - name: VSCODE_CLI_BINARY_NAME - value: code-tunnel resources: containers: @@ -184,21 +182,20 @@ stages: - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: - job: LinuxX86 pool: vscode-1es-linux + variables: + VSCODE_ARCH: x64 steps: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: - - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } + VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} + VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }}: - job: LinuxArm64 pool: vscode-1es-linux-20.04-arm64 + variables: + VSCODE_ARCH: arm64 steps: - task: NodeTool@0 displayName: Install Node.js @@ -213,13 +210,9 @@ stages: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: - - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } + VSCODE_BUILD_ARCH: arm64 + VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} + VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_MACOS, true) }}: - job: MacOS @@ -229,13 +222,8 @@ stages: - template: ./darwin/cli-build-darwin.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - { target: x86_64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - { target: aarch64-apple-darwin, artifact: not_yet_signed_vscode_cli_darwin_arm64_cli } + VSCODE_BUILD_MACOS: ${{ variables.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ variables.VSCODE_BUILD_MACOS_ARM64 }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_WINDOWS, true) }}: - job: Windows @@ -244,13 +232,8 @@ stages: - template: ./win32/cli-build-win32.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_CLI_DIR: $(Build.SourcesDirectory)/cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_TARGETS: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - { target: x86_64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - { target: aarch64-pc-windows-msvc, artifact: not_yet_signed_vscode_cli_win32_arm64_cli } + VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -311,12 +294,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true)) }}: - job: Windows32 @@ -328,6 +309,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false # todo until 32 bit CLI is available VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -342,12 +324,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_win32_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true)) }}: - job: windowsCLISign @@ -355,12 +335,8 @@ stages: steps: - template: win32/product-build-win32-cli-sign.yml parameters: - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_ARTIFACTS: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - not_yet_signed_vscode_cli_win32_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - not_yet_signed_vscode_cli_win32_arm64_cli + VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -409,6 +385,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -424,6 +401,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true VSCODE_RUN_SMOKE_TESTS: false @@ -439,6 +417,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: true @@ -455,12 +434,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX, true), ne(variables['VSCODE_PUBLISH'], 'false')) }}: - job: LinuxSnap @@ -483,6 +460,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false # todo: not build yet VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -509,12 +487,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} # TODO@joaomoreno: We don't ship ARM snaps for now - ${{ if and(false, eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}: @@ -564,6 +540,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -577,6 +554,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true VSCODE_RUN_SMOKE_TESTS: false @@ -590,6 +568,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: true @@ -604,12 +583,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_x64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(parameters.VSCODE_STEP_ON_IT, false) }}: - job: macOSTest @@ -621,6 +598,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: false VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -641,12 +619,8 @@ stages: steps: - template: darwin/product-build-darwin-cli-sign.yml parameters: - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - VSCODE_CLI_ARTIFACTS: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - not_yet_signed_vscode_cli_darwin_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - not_yet_signed_vscode_cli_darwin_arm64_cli + VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }} - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}: - job: macOSARM64 @@ -658,12 +632,10 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - VSCODE_CLI_ARTIFACT: not_yet_signed_vscode_cli_darwin_arm64_cli - VSCODE_CLI_BINARY_NAME: ${{ variables.VSCODE_CLI_BINARY_NAME }} - ${{ if eq(variables['VSCODE_PUBLISH'], true) }}: - job: macOSARM64Sign diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index f203f430942..3b5525b930d 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -1,17 +1,22 @@ parameters: - - name: VSCODE_CLI_TARGETS - default: [] - type: object + - name: VSCODE_BUILD_WIN32 + type: boolean + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean - name: VSCODE_QUALITY type: string - - name: VSCODE_CLI_DIR - type: string - - name: VSCODE_CLI_BINARY_NAME - type: string - name: channel type: string default: stable +variables: + - name: VSCODE_CLI_TARGETS + value: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - { target: x86_64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_x64_cli } + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - { target: aarch64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_arm64_cli } + steps: - task: NodeTool@0 inputs: @@ -33,20 +38,20 @@ steps: parameters: targets: ${{ parameters.VSCODE_CLI_TARGETS }} - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - template: ../vcpkg-install.yml - parameters: - targets: - - ${{ if eq(target.target, 'x86_64-pc-windows-msvc') }}: - - x64-windows-static-md - - ${{ if eq(target.target, 'aarch64-pc-windows-msvc') }}: - - arm64-windows-static-md - vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg - targetDirectory: $(Build.ArtifactStagingDirectory)/deps + - template: ../vcpkg-install.yml + parameters: + targets: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - x64-windows-static-md + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - arm64-windows-static-md + vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg + targetDirectory: $(Build.ArtifactStagingDirectory)/deps - - script: cargo build --release --target ${{ target.target }} --bin=${{ parameters.VSCODE_CLI_BINARY_NAME }} + - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: + - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel displayName: Compile ${{ target.artifact }} - workingDirectory: ${{ parameters.VSCODE_CLI_DIR }} + workingDirectory: $(Build.SourcesDirectory)/cli env: VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) @@ -63,7 +68,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel.exe includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index db38e753738..f1b2e80a117 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -1,10 +1,16 @@ parameters: - - name: VSCODE_CLI_BINARY_NAME - type: string - - name: VSCODE_CLI_ARTIFACTS - default: [] - type: object + - name: VSCODE_BUILD_WIN32 + type: boolean + - name: VSCODE_BUILD_WIN32_ARM64 + type: boolean +variables: + - name: VSCODE_CLI_ARTIFACTS + value: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - unsigned_vscode_cli_win32_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - unsigned_vscode_cli_win32_arm64_cli steps: - task: NodeTool@0 displayName: "Use Node.js" @@ -24,7 +30,7 @@ steps: KeyVaultName: vscode SecretsFilter: "ESRP-PKI,esrp-aad-username,esrp-aad-password" - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - task: DownloadPipelineArtifact@2 displayName: Download artifacts inputs: @@ -63,13 +69,13 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - powershell: | - $ASSET_ID = "${{ target }}".replace("not_yet_signed_", ""); + $ASSET_ID = "${{ target }}".replace("unsigned_", ""); echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" displayName: Set asset id variable - task: ArchiveFiles@2 inputs: - rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/${{ parameters.VSCODE_CLI_BINARY_NAME }}.exe + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code-tunnel.exe includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index caec3dc49e2..6827c27d5eb 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -9,12 +9,8 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean - - name: VSCODE_CLI_ARTIFACT - type: string - default: '' - - name: VSCODE_CLI_BINARY_NAME - type: string - default: '' + - name: VSCODE_BUILD_TUNNEL_CLI + type: boolean steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -181,10 +177,13 @@ steps: echo "##vso[task.setvariable variable=CodeSigningFolderPath]$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)" displayName: Build - - ${{ if ne(parameters.VSCODE_CLI_ARTIFACT, '') }}: + - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: + artifact: unsigned_vscode_cli_win32_x64_cli + ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: + artifact: unsigned_vscode_cli_win32_arm64_cli patterns: '**' path: $(Build.ArtifactStagingDirectory) displayName: Download VS Code CLI @@ -195,7 +194,7 @@ steps: if ("$(VSCODE_QUALITY)" -ne "stable") { - Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME).exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$(VSCODE_CLI_BINARY_NAME)-$(VSCODE_QUALITY).exe" + Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY).exe" } displayName: Move VS Code CLI From 1c42eb1c3d001a58f54f55e81329fe0b171d25f3 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 10 Oct 2022 19:42:46 +0200 Subject: [PATCH 455/599] View badge extension API documentation wrong (#163202) Fixes #162900 --- src/vs/workbench/api/common/extHostTreeViews.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 9a76fc9daa7..6650025a660 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -122,11 +122,13 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { return treeView.badge; }, set badge(badge: vscode.ViewBadge | undefined) { - if (ExtHostViewBadge.isViewBadge(badge)) { + if ((badge !== undefined) && ExtHostViewBadge.isViewBadge(badge)) { treeView.badge = { value: Math.floor(Math.abs(badge.value)), tooltip: badge.tooltip }; + } else if (badge === undefined) { + treeView.badge = undefined; } }, reveal: (element: T, options?: IRevealOptions): Promise => { From e929233fc81b9d72bea8adecbe758399e3c713e9 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 10 Oct 2022 20:32:12 +0200 Subject: [PATCH 456/599] Fixes #162115 (#163206) --- .../browser/view/conflictActions.ts | 226 ++++++++---------- .../browser/view/fixedZoneWidget.ts | 55 +++++ .../browser/view/media/mergeEditor.css | 10 +- .../mergeEditor/browser/view/mergeEditor.ts | 46 +--- 4 files changed, 175 insertions(+), 162 deletions(-) create mode 100644 src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index dfb6979f5b1..e382534f4fe 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { h, $, reset, createStyleSheet, isInShadowDOM } from 'vs/base/browser/dom'; +import { $, createStyleSheet, h, isInShadowDOM, reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { hash } from 'vs/base/common/hash'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { autorun, derived, IObservable, transaction } from 'vs/base/common/observable'; -import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { EditorOption, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { localize } from 'vs/nls'; import { ModifiedBaseRange, ModifiedBaseRangeState } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; +import { FixedZoneWidget } from 'vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; export class ConflictActionsFactory extends Disposable { - private id = 0; private readonly _styleClassName: string; private readonly _styleElement: HTMLStyleElement; @@ -75,96 +75,7 @@ export class ConflictActionsFactory extends Disposable { }; } - createContentWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IContentWidget { - - function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { - return { - text: title, - action, - tooltip, - }; - } - - const items = derived('items', reader => { - if (!viewModel.model.hasBaseRange(modifiedBaseRange)) { - return []; - } - - const state = viewModel.model.getState(modifiedBaseRange).read(reader); - const handled = viewModel.model.isHandled(modifiedBaseRange).read(reader); - const model = viewModel.model; - - const result: IContentWidgetAction[] = []; - - const inputData = inputNumber === 1 ? viewModel.model.input1 : viewModel.model.input2; - const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); - - if (!modifiedBaseRange.isConflicting && handled && !showNonConflictingChanges) { - return []; - } - - const otherInputNumber = inputNumber === 1 ? 2 : 1; - - if (!state.conflicting && !state.isInputIncluded(inputNumber)) { - result.push( - !state.isInputIncluded(inputNumber) - ? command(localize('accept', "Accept {0}", inputData.title), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - state.withInputValue(inputNumber, true), - true, - tx - ); - }); - }, localize('acceptTooltip', "Accept {0} in the result document.", inputData.title)) - : command(localize('remove', "Remove {0}", inputData.title), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - state.withInputValue(inputNumber, false), - true, - tx - ); - }); - }, localize('removeTooltip', "Remove {0} from the result document.", inputData.title)), - ); - - if (modifiedBaseRange.canBeCombined && state.isEmpty) { - result.push( - state.input1 && state.input2 - ? command(localize('removeBoth', "Remove Both"), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - ModifiedBaseRangeState.default, - true, - tx - ); - }); - }, localize('removeBothTooltip', "Remove both changes from the result document.")) - : command(localize('acceptBoth', "Accept Both"), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - state - .withInputValue(inputNumber, true) - .withInputValue(otherInputNumber, true), - true, - tx - ); - }); - }, localize('acceptBothTooltip', "Accept an automatic combination of both sides in the result document.")), - ); - } - } - return result; - }); - return new ActionsContentWidget((this.id++).toString(), this._styleClassName, lineNumber, items); - } - - createResultWidget(lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange): IContentWidget { - + addResultWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange): IDisposable { function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { return { text: title, @@ -260,7 +171,95 @@ export class ConflictActionsFactory extends Disposable { } return result; }); - return new ActionsContentWidget((this.id++).toString(), this._styleClassName, lineNumber, items); + + return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, 16, this._styleClassName, items); + } + + addContentWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IDisposable { + function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { + return { + text: title, + action, + tooltip, + }; + } + + const items = derived('items', reader => { + if (!viewModel.model.hasBaseRange(modifiedBaseRange)) { + return []; + } + + const state = viewModel.model.getState(modifiedBaseRange).read(reader); + const handled = viewModel.model.isHandled(modifiedBaseRange).read(reader); + const model = viewModel.model; + + const result: IContentWidgetAction[] = []; + + const inputData = inputNumber === 1 ? viewModel.model.input1 : viewModel.model.input2; + const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + + if (!modifiedBaseRange.isConflicting && handled && !showNonConflictingChanges) { + return []; + } + + const otherInputNumber = inputNumber === 1 ? 2 : 1; + + if (!state.conflicting && !state.isInputIncluded(inputNumber)) { + result.push( + !state.isInputIncluded(inputNumber) + ? command(localize('accept', "Accept {0}", inputData.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(inputNumber, true), + true, + tx + ); + }); + }, localize('acceptTooltip', "Accept {0} in the result document.", inputData.title)) + : command(localize('remove', "Remove {0}", inputData.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(inputNumber, false), + true, + tx + ); + }); + }, localize('removeTooltip', "Remove {0} from the result document.", inputData.title)), + ); + + if (modifiedBaseRange.canBeCombined && state.isEmpty) { + result.push( + state.input1 && state.input2 + ? command(localize('removeBoth', "Remove Both"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + ModifiedBaseRangeState.default, + true, + tx + ); + }); + }, localize('removeBothTooltip', "Remove both changes from the result document.")) + : command(localize('acceptBoth', "Accept Both"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state + .withInputValue(inputNumber, true) + .withInputValue(otherInputNumber, true), + true, + tx + ); + }); + }, localize('acceptBothTooltip', "Accept an automatic combination of both sides in the result document.")), + ); + } + } + return result; + }); + return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, 16, this._styleClassName, items); } } @@ -271,16 +270,21 @@ interface IContentWidgetAction { action?: () => Promise; } -class ActionsContentWidget extends Disposable implements IContentWidget { +class ActionsContentWidget extends FixedZoneWidget { private readonly _domNode = h('div.merge-editor-conflict-actions').root; constructor( - private readonly id: string, + editor: ICodeEditor, + viewZoneAccessor: IViewZoneChangeAccessor, + afterLineNumber: number, + height: number, + className: string, - private readonly lineNumber: number, items: IObservable, ) { - super(); + super(editor, viewZoneAccessor, afterLineNumber, height); + + this.widgetDomNode.appendChild(this._domNode); this._domNode.classList.add(className); @@ -310,28 +314,4 @@ class ActionsContentWidget extends Disposable implements IContentWidget { reset(this._domNode, ...children); } - - getId(): string { - return this.id; - } - - getDomNode(): HTMLElement { - return this._domNode; - } - - getPosition(): IContentWidgetPosition | null { - // We cannot put the content widget after line 0, as line 0 gets normalized to line 1. - // Thus, we put the content widget before line 1 to make it slightly less buggy. - // TODO: Fix this properly. - if (this.lineNumber === 0) { - return { - position: { lineNumber: 1, column: 1, }, - preference: [ContentWidgetPositionPreference.ABOVE], - }; - } - return { - position: { lineNumber: this.lineNumber, column: 1, }, - preference: [ContentWidgetPositionPreference.BELOW], - }; - } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts new file mode 100644 index 00000000000..12c2f930933 --- /dev/null +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { h } from 'vs/base/browser/dom'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ICodeEditor, IOverlayWidget, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; + +export abstract class FixedZoneWidget extends Disposable { + private static counter = 0; + private readonly overlayWidgetId = `fixedZoneWidget-${FixedZoneWidget.counter++}`; + private readonly viewZoneId: string; + + protected readonly widgetDomNode = h('div.fixed-zone-widget').root; + private readonly overlayWidget: IOverlayWidget = { + getId: () => this.overlayWidgetId, + getDomNode: () => this.widgetDomNode, + getPosition: () => null + }; + + constructor( + private readonly editor: ICodeEditor, + viewZoneAccessor: IViewZoneChangeAccessor, + afterLineNumber: number, + height: number, + ) { + super(); + + this.viewZoneId = viewZoneAccessor.addZone({ + domNode: document.createElement('div'), + afterLineNumber: afterLineNumber, + heightInPx: height, + onComputedHeight: (height) => { + this.widgetDomNode.style.height = `${height}px`; + }, + onDomNodeTop: (top) => { + this.widgetDomNode.style.top = `${top}px`; + } + }); + + this.widgetDomNode.style.left = this.editor.getLayoutInfo().contentLeft + 'px'; + + this.editor.addOverlayWidget(this.overlayWidget); + + this._register({ + dispose: () => { + this.editor.removeOverlayWidget(this.overlayWidget); + this.editor.changeViewZones(accessor => { + accessor.removeZone(this.viewZoneId); + }); + }, + }); + } +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css index 684f8bad077..18d6b104934 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css @@ -231,10 +231,7 @@ } .merge-editor-conflict-actions { - margin: -4px 3px; -} - -.merge-editor-conflict-actions { + margin: 0px 3px; overflow: hidden; display: inline-block; text-overflow: ellipsis; @@ -247,7 +244,6 @@ user-select: none; -webkit-user-select: none; white-space: nowrap; - vertical-align: sub; } .merge-editor-conflict-actions>a { @@ -272,3 +268,7 @@ .merge-editor-conflict-actions>a:hover .codicon::before { cursor: pointer; } + +.fixed-zone-widget { + width: 100%; +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 32216d538b5..1fb8ca23bcb 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -408,43 +408,21 @@ export class MergeEditor extends AbstractTextEditor { let lastModifiedBaseRange: ModifiedBaseRange | undefined = undefined; let lastBaseResultDiff: DetailedLineRangeMapping | undefined = undefined; for (const m of baseRangeWithStoreAndTouchingDiffs) { - if (shouldShowCodeLenses && m.left && (m.left.isConflicting || showNonConflictingChanges || !model.isHandled(m.left).read(reader))) { - - input1ViewZoneIds.push(input1ViewZoneAccessor.addZone({ - afterLineNumber: m.left.input1Range.startLineNumber - 1, - heightInPx: 16, - domNode: $('div.conflict-actions-placeholder'), - })); - const w1 = this.conflictActionsFactoryInput1.createContentWidget(m.left.input1Range.startLineNumber - 1, viewModel, m.left, this.input1View.inputNumber); - input1Editor.addContentWidget(w1); - disposableStore.add(toDisposable(() => { - input1Editor.removeContentWidget(w1); - })); - - - input2ViewZoneIds.push(input2ViewZoneAccessor.addZone({ - afterLineNumber: m.left.input2Range.startLineNumber - 1, - heightInPx: 16, - domNode: $('div.conflict-actions-placeholder'), - })); - const w2 = this.conflictActionsFactoryInput2.createContentWidget(m.left.input2Range.startLineNumber - 1, viewModel, m.left, this.input2View.inputNumber); - input2Editor.addContentWidget(w2); - disposableStore.add(toDisposable(() => { - input2Editor.removeContentWidget(w2); - })); + disposableStore.add( + this.conflictActionsFactoryInput1.addContentWidget( + input1ViewZoneAccessor, m.left.input1Range.startLineNumber - 1, viewModel, m.left, this.input1View.inputNumber + ) + ); + disposableStore.add( + this.conflictActionsFactoryInput2.addContentWidget( + input2ViewZoneAccessor, m.left.input2Range.startLineNumber - 1, viewModel, m.left, this.input2View.inputNumber + ) + ); const afterLineNumber = m.left.baseRange.startLineNumber + (lastBaseResultDiff?.resultingDeltaFromOriginalToModified ?? 0) - 1; - resultViewZoneIds.push(resultViewZoneAccessor.addZone({ - afterLineNumber, - heightInPx: 16, - domNode: $('div.conflict-actions-placeholder'), - })); - const w3 = this.conflictActionsFactoryResult.createResultWidget(afterLineNumber, viewModel, m.left); - resultEditor.addContentWidget(w3); - disposableStore.add(toDisposable(() => { - resultEditor.removeContentWidget(w3); - })); + + disposableStore.add(this.conflictActionsFactoryResult.addResultWidget(resultViewZoneAccessor, afterLineNumber, viewModel, m.left)); if (shouldAlignBase && baseViewZoneAccessor) { baseViewZoneIds.push(baseViewZoneAccessor.addZone({ From 241e230b24dc60dc8969992d0c9ec8f0b6874564 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2022 20:43:59 +0200 Subject: [PATCH 457/599] Fix #163180 (#163208) - cyclic dep. remove output view dependency on output service --- .../output/browser/output.contribution.ts | 3 --- .../contrib/output/browser/outputServices.ts | 12 ++++++++- .../contrib/output/browser/outputView.ts | 27 +++++-------------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index f3fbd0f9294..edf6f945f10 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -240,9 +240,6 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { when: ContextKeyExpr.equals('view', OUTPUT_VIEW_ID), group: 'navigation', order: 4 - }, { - id: MenuId.CommandPalette, - when: CONTEXT_ACTIVE_LOG_OUTPUT, }], icon: Codicon.goToFile, precondition: CONTEXT_ACTIVE_LOG_OUTPUT diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index 29ce15adbac..4fd042c0c9a 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -9,7 +9,7 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IOutputChannel, IOutputService, OUTPUT_VIEW_ID, OUTPUT_SCHEME, LOG_SCHEME, LOG_MIME, OUTPUT_MIME, OutputChannelUpdateMode, IOutputChannelDescriptor, Extensions, IOutputChannelRegistry, ACTIVE_OUTPUT_CHANNEL_CONTEXT } from 'vs/workbench/services/output/common/output'; +import { IOutputChannel, IOutputService, OUTPUT_VIEW_ID, OUTPUT_SCHEME, LOG_SCHEME, LOG_MIME, OUTPUT_MIME, OutputChannelUpdateMode, IOutputChannelDescriptor, Extensions, IOutputChannelRegistry, ACTIVE_OUTPUT_CHANNEL_CONTEXT, CONTEXT_ACTIVE_LOG_OUTPUT } from 'vs/workbench/services/output/common/output'; import { OutputLinkProvider } from 'vs/workbench/contrib/output/browser/outputLinkProvider'; import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { ITextModel } from 'vs/editor/common/model'; @@ -73,6 +73,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo readonly onActiveOutputChannel: Event = this._onActiveOutputChannel.event; private readonly activeOutputChannelContext: IContextKey; + private readonly activeLogOutputChannelContext: IContextKey; constructor( @IStorageService private readonly storageService: IStorageService, @@ -89,6 +90,8 @@ export class OutputService extends Disposable implements IOutputService, ITextMo this.activeOutputChannelContext.set(this.activeChannelIdInStorage); this._register(this.onActiveOutputChannel(channel => this.activeOutputChannelContext.set(channel))); + this.activeLogOutputChannelContext = CONTEXT_ACTIVE_LOG_OUTPUT.bindTo(contextKeyService); + // Register as text model content provider for output textModelResolverService.registerTextModelContentProvider(OUTPUT_SCHEME, this); instantiationService.createInstance(OutputLinkProvider); @@ -106,6 +109,12 @@ export class OutputService extends Disposable implements IOutputService, ITextMo this.setActiveChannel(channels && channels.length > 0 ? this.getChannel(channels[0].id) : undefined); } + this._register(Event.filter(this.viewsService.onDidChangeViewVisibility, e => e.id === OUTPUT_VIEW_ID && e.visible)(() => { + if (this.activeChannel) { + this.viewsService.getActiveViewWithId(OUTPUT_VIEW_ID)?.showChannel(this.activeChannel, true); + } + })); + this._register(this.lifecycleService.onDidShutdown(() => this.dispose())); } @@ -187,6 +196,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private setActiveChannel(channel: OutputChannel | undefined): void { this.activeChannel = channel; + this.activeLogOutputChannelContext.set(!!channel?.outputChannelDescriptor?.file && channel?.outputChannelDescriptor?.log); if (this.activeChannel) { this.storageService.store(OUTPUT_ACTIVE_CHANNEL_KEY, this.activeChannel.id, StorageScope.WORKSPACE, StorageTarget.USER); diff --git a/src/vs/workbench/contrib/output/browser/outputView.ts b/src/vs/workbench/contrib/output/browser/outputView.ts index ca71904b6cd..9f84798c50c 100644 --- a/src/vs/workbench/contrib/output/browser/outputView.ts +++ b/src/vs/workbench/contrib/output/browser/outputView.ts @@ -13,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { AbstractTextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; -import { OUTPUT_VIEW_ID, IOutputService, CONTEXT_IN_OUTPUT, IOutputChannel, CONTEXT_ACTIVE_LOG_OUTPUT, CONTEXT_OUTPUT_SCROLL_LOCK } from 'vs/workbench/services/output/common/output'; +import { OUTPUT_VIEW_ID, CONTEXT_IN_OUTPUT, IOutputChannel, CONTEXT_OUTPUT_SCROLL_LOCK } from 'vs/workbench/services/output/common/output'; import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -51,7 +51,6 @@ export class OutputViewPane extends ViewPane { @IContextKeyService contextKeyService: IContextKeyService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IInstantiationService instantiationService: IInstantiationService, - @IOutputService private readonly outputService: IOutputService, @IOpenerService openerService: IOpenerService, @IThemeService themeService: IThemeService, @ITelemetryService telemetryService: ITelemetryService, @@ -80,15 +79,14 @@ export class OutputViewPane extends ViewPane { this.editorPromise?.then(() => this.editor.focus()); } - override renderBody(container: HTMLElement): void { + protected override renderBody(container: HTMLElement): void { super.renderBody(container); this.editor.create(container); container.classList.add('output-view'); const codeEditor = this.editor.getControl(); codeEditor.setAriaOptions({ role: 'document', activeDescendant: undefined }); this._register(codeEditor.onDidChangeModelContent(() => { - const activeChannel = this.outputService.getActiveChannel(); - if (activeChannel && !this.scrollLock) { + if (!this.scrollLock) { this.editor.revealLastLine(); } })); @@ -118,21 +116,13 @@ export class OutputViewPane extends ViewPane { private onDidChangeVisibility(visible: boolean): void { this.editor.setVisible(visible); - let channel: IOutputChannel | undefined = undefined; - if (visible) { - channel = this.channelId ? this.outputService.getChannel(this.channelId) : this.outputService.getActiveChannel(); - } - if (channel) { - this.setInput(channel); - } else { + if (!visible) { this.clearInput(); } } private setInput(channel: IOutputChannel): void { this.channelId = channel.id; - const descriptor = this.outputService.getChannelDescriptor(channel.id); - CONTEXT_ACTIVE_LOG_OUTPUT.bindTo(this.contextKeyService).set(!!descriptor?.file && descriptor?.log); const input = this.createInput(channel); if (!this.editor.input || !input.matches(this.editor.input)) { @@ -144,7 +134,7 @@ export class OutputViewPane extends ViewPane { } private clearInput(): void { - CONTEXT_ACTIVE_LOG_OUTPUT.bindTo(this.contextKeyService).set(false); + this.channelId = undefined; this.editor.clearInput(); this.editorPromise = null; } @@ -155,7 +145,7 @@ export class OutputViewPane extends ViewPane { } -export class OutputEditor extends AbstractTextResourceEditor { +class OutputEditor extends AbstractTextResourceEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -164,7 +154,6 @@ export class OutputEditor extends AbstractTextResourceEditor { @IConfigurationService private readonly configurationService: IConfigurationService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IThemeService themeService: IThemeService, - @IOutputService private readonly outputService: IOutputService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IFileService fileService: IFileService @@ -215,9 +204,7 @@ export class OutputEditor extends AbstractTextResourceEditor { } protected getAriaLabel(): string { - const channel = this.outputService.getActiveChannel(); - - return channel ? nls.localize('outputViewWithInputAriaLabel', "{0}, Output panel", channel.label) : nls.localize('outputViewAriaLabel', "Output panel"); + return this.input ? this.input.getAriaLabel() : nls.localize('outputViewAriaLabel', "Output panel"); } override async setInput(input: TextResourceEditorInput, options: ITextEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { From b2d7afc63411280698947960df9c48ab3567623c Mon Sep 17 00:00:00 2001 From: jannisspeer <115073497+jannisspeer@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:32:26 +0200 Subject: [PATCH 458/599] Remove Snakefile from being classified as Python (#162749) Update package.json Co-authored-by: Alex Ross --- extensions/python/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/python/package.json b/extensions/python/package.json index 6134d05a215..17cbe7787e1 100644 --- a/extensions/python/package.json +++ b/extensions/python/package.json @@ -28,7 +28,6 @@ "py" ], "filenames": [ - "Snakefile", "SConstruct", "SConscript" ], From bcaa389a8fba1a31209db3c2ada4ac63d943e027 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Mon, 10 Oct 2022 12:42:15 -0700 Subject: [PATCH 459/599] move editor features to submenu in view menu (#163209) refs #158458 --- .../contrib/stickyScroll/browser/stickyScrollActions.ts | 2 +- src/vs/platform/actions/common/actions.ts | 1 + .../workbench/browser/parts/editor/breadcrumbsControl.ts | 2 +- .../workbench/browser/parts/editor/editor.contribution.ts | 8 ++++++++ .../workbench/contrib/codeEditor/browser/toggleMinimap.ts | 3 +-- .../codeEditor/browser/toggleRenderControlCharacter.ts | 3 +-- .../contrib/codeEditor/browser/toggleRenderWhitespace.ts | 3 +-- .../contrib/codeEditor/browser/toggleWordWrap.ts | 3 +-- 8 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts index 6f0c4adff12..e13331895c9 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts @@ -28,7 +28,7 @@ export class ToggleStickyScroll extends Action2 { }, menu: [ { id: MenuId.CommandPalette }, - { id: MenuId.MenubarViewMenu, group: '5_editor', order: 6 }, + { id: MenuId.MenubarEditorFeaturesMenu, order: 6 }, { id: MenuId.StickyScrollContext } ] }); diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 100e88560ed..7ea373d798a 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -82,6 +82,7 @@ export class MenuId { static readonly MenubarGoMenu = new MenuId('MenubarGoMenu'); static readonly MenubarHelpMenu = new MenuId('MenubarHelpMenu'); static readonly MenubarLayoutMenu = new MenuId('MenubarLayoutMenu'); + static readonly MenubarEditorFeaturesMenu = new MenuId('MenubarEditorFeaturesMenu'); static readonly MenubarNewBreakpointMenu = new MenuId('MenubarNewBreakpointMenu'); static readonly MenubarPanelAlignmentMenu = new MenuId('MenubarPanelAlignmentMenu'); static readonly MenubarPanelPositionMenu = new MenuId('MenubarPanelPositionMenu'); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 657bea0cea4..0e7150e5a96 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -515,7 +515,7 @@ registerAction2(class ToggleBreadcrumb extends Action2 { }, menu: [ { id: MenuId.CommandPalette }, - { id: MenuId.MenubarViewMenu, group: '5_editor', order: 3 }, + { id: MenuId.MenubarEditorFeaturesMenu, order: 3 }, { id: MenuId.NotebookToolbar, group: 'notebookLayout', order: 2 }, { id: MenuId.StickyScrollContext } ] diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 82ca36f22a6..80a9fe8e82d 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -779,6 +779,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { order: 9 }); +// Features menu +MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { + group: '2_appearance', + title: localize({ key: 'miEditorFeatures', comment: ['&& denotes a mnemonic'] }, "Editor &&Features"), + submenu: MenuId.MenubarEditorFeaturesMenu, + order: 3 +}); + // Main Menu Bar Contributions: MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts index 33be24d8270..6703497db2d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -26,8 +26,7 @@ export class ToggleMinimapAction extends Action2 { f1: true, toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true), menu: { - id: MenuId.MenubarViewMenu, - group: '5_editor', + id: MenuId.MenubarEditorFeaturesMenu, order: 2 } }); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts index 9bc7a2b18ed..9e3029dd0d8 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts @@ -26,8 +26,7 @@ export class ToggleRenderControlCharacterAction extends Action2 { f1: true, toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true), menu: { - id: MenuId.MenubarViewMenu, - group: '5_editor', + id: MenuId.MenubarEditorFeaturesMenu, order: 5 } }); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts index 297c10d0cbb..88e06bc7547 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts @@ -26,8 +26,7 @@ class ToggleRenderWhitespaceAction extends Action2 { f1: true, toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none'), menu: { - id: MenuId.MenubarViewMenu, - group: '5_editor', + id: MenuId.MenubarEditorFeaturesMenu, order: 4 } }); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 56e5219cb2b..1348eb4557a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -305,8 +305,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { // View menu -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', +MenuRegistry.appendMenuItem(MenuId.MenubarEditorFeaturesMenu, { command: { id: TOGGLE_WORD_WRAP_ID, title: nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "&&Word Wrap"), From 5dfca53892a1061b1c103542afe49d51f1041778 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 10 Oct 2022 21:43:02 +0200 Subject: [PATCH 460/599] Try out a new razor grammar (#163212) Part of #163149 --- extensions/razor/build/update-grammar.mjs | 18 + extensions/razor/cgmanifest.json | 46 +- extensions/razor/package.json | 3 + .../razor/syntaxes/cshtml.tmLanguage.json | 1692 ++++++++++++++--- .../test/colorize-results/test_cshtml.json | 1162 +++++------ 5 files changed, 1984 insertions(+), 937 deletions(-) create mode 100644 extensions/razor/build/update-grammar.mjs diff --git a/extensions/razor/build/update-grammar.mjs b/extensions/razor/build/update-grammar.mjs new file mode 100644 index 00000000000..259f4278466 --- /dev/null +++ b/extensions/razor/build/update-grammar.mjs @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check + +import * as vscodeGrammarUpdater from 'vscode-grammar-updater'; + +function patchGrammar(grammar) { + grammar.scopeName = 'text.html.cshtml'; + return grammar; +} + +const razorGrammarRepo = 'OmniSharp/omnisharp-vscode'; +const grammarPath = 'src/razor/syntaxes/aspnetcorerazor.tmLanguage.json'; +vscodeGrammarUpdater.update(razorGrammarRepo, grammarPath, './syntaxes/cshtml.tmLanguage.json', grammar => patchGrammar(grammar)); + + diff --git a/extensions/razor/cgmanifest.json b/extensions/razor/cgmanifest.json index c0de1392dd5..22f3f066f95 100644 --- a/extensions/razor/cgmanifest.json +++ b/extensions/razor/cgmanifest.json @@ -4,38 +4,38 @@ "component": { "type": "git", "git": { - "name": "demyte/language-cshtml", - "repositoryUrl": "https://github.com/demyte/language-cshtml", - "commitHash": "e6e54d5a86a28cc1e44609a32aaa10a244cd3f81" + "name": "OmniSharp/omnisharp-vscode", + "repositoryUrl": "https://github.com/OmniSharp/omnisharp-vscode", + "commitHash": "85d6eeea14e9aef51934697de78c77fbddbf1aa8" } }, "license": "MIT", - "version": "0.3.0", + "version": "1.24.0", "licenseDetail": [ - "The MIT License (MIT)", + "MIT License", "", - "Copyright (c) 2014 James Summerton", + "Copyright (c) .NET Foundation and Contributors", + "All Rights Reserved", "", - "Permission is hereby granted, free of charge, to any person obtaining", - "a copy of this software and associated documentation files (the", - "\"Software\"), to deal in the Software without restriction, including", - "without limitation the rights to use, copy, modify, merge, publish,", - "distribute, sublicense, and/or sell copies of the Software, and to", - "permit persons to whom the Software is furnished to do so, subject to", - "the following conditions:", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", "", - "The above copyright notice and this permission notice shall be", - "included in all copies or substantial portions of the Software.", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,", - "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF", - "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND", - "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE", - "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", - "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION", - "WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." ] } ], "version": 1 -} +} \ No newline at end of file diff --git a/extensions/razor/package.json b/extensions/razor/package.json index ace1ed7f959..2312ce86c48 100644 --- a/extensions/razor/package.json +++ b/extensions/razor/package.json @@ -8,6 +8,9 @@ "engines": { "vscode": "0.10.x" }, + "scripts": { + "update-grammar": "node ./build/update-grammar.mjs" + }, "contributes": { "languages": [ { diff --git a/extensions/razor/syntaxes/cshtml.tmLanguage.json b/extensions/razor/syntaxes/cshtml.tmLanguage.json index c662cee2fa3..0f48c15e575 100644 --- a/extensions/razor/syntaxes/cshtml.tmLanguage.json +++ b/extensions/razor/syntaxes/cshtml.tmLanguage.json @@ -1,57 +1,480 @@ { "information_for_contributors": [ - "This file has been converted from https://github.com/demyte/language-cshtml/blob/master/grammars/cshtml.json", + "This file has been converted from https://github.com/OmniSharp/omnisharp-vscode/blob/master/src/razor/syntaxes/aspnetcorerazor.tmLanguage.json", "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/demyte/language-cshtml/commit/e6e54d5a86a28cc1e44609a32aaa10a244cd3f81", + "version": "https://github.com/OmniSharp/omnisharp-vscode/commit/85d6eeea14e9aef51934697de78c77fbddbf1aa8", "name": "ASP.NET Razor", "scopeName": "text.html.cshtml", "patterns": [ { - "include": "#razor-directives" - }, - { - "include": "#razor-code-block" - }, - { - "include": "#razor-else-if" - }, - { - "include": "#razor-if" - }, - { - "include": "#razor-else" - }, - { - "include": "#razor-foreach" - }, - { - "include": "#explicit-razor-expression" - }, - { - "include": "#implicit-razor-expression" + "include": "#razor-control-structures" }, { "include": "text.html.basic" } ], "repository": { - "comments": { - "begin": "@\\*", - "captures": { - "0": { - "name": "punctuation.definition.comment.source.cshtml" - } - }, - "end": "\\*@", - "name": "comment.block.cshtml" - }, - "razor-directives": { - "name": "meta.directive.cshtml", + "razor-control-structures": { "patterns": [ { - "include": "#using-directive" + "include": "#razor-comment" + }, + { + "include": "#razor-codeblock" + }, + { + "include": "#explicit-razor-expression" + }, + { + "include": "#escaped-transition" + }, + { + "include": "#directives" + }, + { + "include": "#transitioned-csharp-control-structures" + }, + { + "include": "#implicit-expression" + } + ] + }, + "escaped-transition": { + "name": "constant.character.escape.razor.transition", + "match": "@@" + }, + "transition": { + "match": "@", + "name": "keyword.control.cshtml.transition" + }, + "razor-codeblock": { + "name": "meta.structure.razor.codeblock", + "begin": "(@)(\\{)", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.codeblock.open" + } + }, + "contentName": "source.cs", + "patterns": [ + { + "include": "#razor-codeblock-body" + } + ], + "end": "(\\})", + "endCaptures": { + "1": { + "name": "keyword.control.razor.directive.codeblock.close" + } + } + }, + "razor-codeblock-body": { + "patterns": [ + { + "include": "#text-tag" + }, + { + "include": "#wellformed-html" + }, + { + "include": "#razor-single-line-markup" + }, + { + "include": "#razor-control-structures" + }, + { + "include": "source.cs" + } + ] + }, + "razor-single-line-markup": { + "match": "(\\@\\:)([^$]*)$", + "captures": { + "1": { + "name": "keyword.control.razor.singleLineMarkup" + }, + "2": { + "patterns": [ + { + "include": "#razor-control-structures" + }, + { + "include": "text.html.basic" + } + ] + } + } + }, + "text-tag": { + "begin": "()", + "beginCaptures": { + "1": { + "name": "keyword.control.cshtml.transition.textTag.open" + } + }, + "patterns": [ + { + "include": "#wellformed-html" + }, + { + "include": "$self" + } + ], + "end": "()", + "endCaptures": { + "1": { + "name": "keyword.control.cshtml.transition.textTag.close" + } + } + }, + "razor-comment": { + "name": "meta.comment.razor", + "begin": "(@)(\\*)", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.comment.star" + } + }, + "contentName": "comment.block.razor", + "end": "(\\*)(@)", + "endCaptures": { + "1": { + "name": "keyword.control.razor.comment.star" + }, + "2": { + "patterns": [ + { + "include": "#transition" + } + ] + } + } + }, + "wellformed-html": { + "patterns": [ + { + "include": "#void-tag" + }, + { + "include": "#non-void-tag" + } + ] + }, + "void-tag": { + "name": "meta.tag.structure.$3.void.html", + "begin": "(?i)(<)(!)?(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "constant.character.escape.razor.tagHelperOptOut" + }, + "3": { + "name": "entity.name.tag.html" + } + }, + "patterns": [ + { + "include": "text.html.basic#attribute" + } + ], + "end": "/?>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + } + }, + "non-void-tag": { + "begin": "(?=<(!)?([^/\\s>]+)(\\s|/?>))", + "end": "()|(/>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "entity.name.tag.html" + }, + "3": { + "name": "punctuation.definition.tag.end.html" + }, + "4": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "begin": "(<)(!)?([^/\\s>]+)(?=\\s|/?>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.html" + }, + "2": { + "name": "constant.character.escape.razor.tagHelperOptOut" + }, + "3": { + "name": "entity.name.tag.html" + } + }, + "end": "(?=/?>)", + "patterns": [ + { + "include": "#razor-control-structures" + }, + { + "include": "text.html.basic#attribute" + } + ] + }, + { + "begin": ">", + "beginCaptures": { + "0": { + "name": "punctuation.definition.tag.end.html" + } + }, + "end": "(?=\\{\\}\\)\\]'\"])" + }, + "implicit-expression-body": { + "patterns": [ + { + "include": "#implicit-expression-invocation-start" + }, + { + "include": "#implicit-expression-accessor-start" + } + ], + "end": "(?=[\\s<>\\{\\}\\)\\]'\"])" + }, + "implicit-expression-invocation-start": { + "begin": "([_[:alpha:]][_[:alnum:]]*)(?=\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.cs" + } + }, + "patterns": [ + { + "include": "#implicit-expression-continuation" + } + ], + "end": "(?=[\\s<>\\{\\}\\)\\]'\"])" + }, + "implicit-expression-accessor-start": { + "begin": "([_[:alpha:]][_[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "variable.other.object.cs" + } + }, + "patterns": [ + { + "include": "#implicit-expression-continuation" + } + ], + "end": "(?=[\\s<>\\{\\}\\)\\]'\"])" + }, + "implicit-expression-continuation": { + "patterns": [ + { + "include": "#balanced-parenthesis-csharp" + }, + { + "include": "#balanced-brackets-csharp" + }, + { + "include": "#implicit-expression-invocation" + }, + { + "include": "#implicit-expression-accessor" + }, + { + "include": "#implicit-expression-extension" + } + ], + "end": "(?=[\\s<>\\{\\}\\)\\]'\"])" + }, + "implicit-expression-accessor": { + "match": "(?<=\\.)[_[:alpha:]][_[:alnum:]]*", + "name": "variable.other.object.property.cs" + }, + "implicit-expression-invocation": { + "match": "(?<=\\.)[_[:alpha:]][_[:alnum:]]*(?=\\()", + "name": "entity.name.function.cs" + }, + "implicit-expression-operator": { + "patterns": [ + { + "include": "#implicit-expression-dot-operator" + }, + { + "include": "#implicit-expression-null-conditional-operator" + }, + { + "include": "#implicit-expression-null-forgiveness-operator" + } + ] + }, + "implicit-expression-dot-operator": { + "match": "(\\.)(?=[_[:alpha:]][_[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.cs" + } + } + }, + "implicit-expression-null-conditional-operator": { + "match": "(\\?)(?=[.\\[])", + "captures": { + "1": { + "name": "keyword.operator.null-conditional.cs" + } + } + }, + "implicit-expression-null-forgiveness-operator": { + "match": "(\\!)(?=(?:\\.[_[:alpha:]][_[:alnum:]]*)|\\?|[\\[\\(])", + "captures": { + "1": { + "name": "keyword.operator.logical.cs" + } + } + }, + "balanced-parenthesis-csharp": { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.parenthesis.open.cs" + } + }, + "name": "razor.test.balanced.parenthesis", + "patterns": [ + { + "include": "source.cs" + } + ], + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.parenthesis.close.cs" + } + } + }, + "balanced-brackets-csharp": { + "begin": "(\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.squarebracket.open.cs" + } + }, + "name": "razor.test.balanced.brackets", + "patterns": [ + { + "include": "source.cs" + } + ], + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.squarebracket.close.cs" + } + } + }, + "directives": { + "patterns": [ + { + "include": "#code-directive" + }, + { + "include": "#functions-directive" + }, + { + "include": "#page-directive" + }, + { + "include": "#addTagHelper-directive" + }, + { + "include": "#removeTagHelper-directive" + }, + { + "include": "#tagHelperPrefix-directive" }, { "include": "#model-directive" @@ -59,283 +482,1030 @@ { "include": "#inherits-directive" }, + { + "include": "#implements-directive" + }, + { + "include": "#namespace-directive" + }, { "include": "#inject-directive" }, { - "include": "#implements-directive" + "include": "#attribute-directive" + }, + { + "include": "#section-directive" }, { "include": "#layout-directive" }, { - "include": "#page-directive" - }, - { - "include": "#functions-directive" + "include": "#using-directive" } ] }, - "explicit-razor-expression": { - "name": "meta.expression.explicit.cshtml", - "begin": "(@)\\(", - "captures": { - "0": { - "name": "keyword.control.cshtml" + "code-directive": { + "begin": "(@)(code)\\s*", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.code" } }, "patterns": [ { - "include": "source.cs" + "include": "#directive-codeblock" } ], - "end": "\\)" - }, - "implicit-razor-expression": { - "name": "meta.expression.implicit.cshtml", - "begin": "(@)([a-zA-Z0-9\\.\\_\\(\\)]+)", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "end": "$" - }, - "using-directive": { - "name": "meta.directive.using.cshtml", - "begin": "(@using)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-namespace-identifier" - } - ], - "end": "$" - }, - "model-directive": { - "name": "meta.directive.model.cshtml", - "begin": "(@model)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-type-name" - } - ], - "end": "$" - }, - "inherits-directive": { - "name": "meta.directive.inherits.cshtml", - "begin": "(@inherits)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-type-name" - } - ], - "end": "$" - }, - "inject-directive": { - "name": "meta.directive.inject.cshtml", - "begin": "(@inject)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-type-name" - } - ], - "end": "$" - }, - "implements-directive": { - "name": "meta.directive.implements.cshtml", - "begin": "(@implements)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-type-name" - } - ], - "end": "$" - }, - "layout-directive": { - "name": "meta.directive.layout.cshtml", - "begin": "(@layout)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "#csharp-type-name" - } - ], - "end": "$" - }, - "page-directive": { - "name": "meta.directive.page.cshtml", - "begin": "(@page)\\s+", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, - "patterns": [ - { - "include": "source.cs" - } - ], - "end": "$" + "end": "(?<=})|\\s" }, "functions-directive": { - "name": "meta.directive.functions.cshtml", - "match": "(@functions)", - "captures": { - "0": { - "name": "keyword.control.cshtml" + "begin": "(@)(functions)\\s*", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.functions" + } + }, + "patterns": [ + { + "include": "#directive-codeblock" + } + ], + "end": "(?<=})|\\s" + }, + "directive-codeblock": { + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "keyword.control.razor.directive.codeblock.open" + } + }, + "name": "meta.structure.razor.directive.codeblock", + "contentName": "source.cs", + "patterns": [ + { + "include": "source.cs" + } + ], + "end": "(\\})", + "endCaptures": { + "1": { + "name": "keyword.control.razor.directive.codeblock.close" } } }, - "razor-if": { - "begin": "(@if)", + "page-directive": { + "name": "meta.directive", + "match": "(@)(page)\\s+([^$]+)?", "captures": { - "0": { - "name": "keyword.control.cshtml" + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.page" + }, + "3": { + "patterns": [ + { + "include": "source.cs#string-literal" + } + ] } - }, - "patterns": [ - { - "include": "source.cs" - } - ], - "end": "$" + } }, - "razor-else": { - "begin": "(else)", + "addTagHelper-directive": { + "name": "meta.directive", + "match": "(@)(addTagHelper)\\s+([^$]+)?", "captures": { - "0": { - "name": "keyword.control.cshtml" + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.addTagHelper" + }, + "3": { + "patterns": [ + { + "include": "#tagHelper-directive-argument" + } + ] } - }, - "patterns": [ - { - "include": "source.cs" - } - ], - "end": "$" + } }, - "razor-else-if": { - "begin": "(else\\s+if)", + "removeTagHelper-directive": { + "name": "meta.directive", + "match": "(@)(removeTagHelper)\\s+([^$]+)?", "captures": { - "0": { - "name": "keyword.control.cshtml" + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.removeTagHelper" + }, + "3": { + "patterns": [ + { + "include": "#tagHelper-directive-argument" + } + ] } - }, - "patterns": [ - { - "include": "source.cs" - } - ], - "end": "$" + } }, - "razor-foreach": { - "begin": "(@foreach)\\s+\\(", + "tagHelperPrefix-directive": { + "name": "meta.directive", + "match": "(@)(tagHelperPrefix)\\s+([^$]+)?", "captures": { - "0": { - "name": "keyword.control.cshtml" + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.tagHelperPrefix" + }, + "3": { + "patterns": [ + { + "include": "#tagHelper-directive-argument" + } + ] } - }, - "patterns": [ - { - "include": "source.cs" - } - ], - "end": "\\)" + } }, - "razor-code-block": { - "begin": "@?\\{", - "captures": { - "0": { - "name": "keyword.control.cshtml" - } - }, + "tagHelper-directive-argument": { "patterns": [ { - "include": "text.html.cshtml" + "include": "source.cs#string-literal" }, { - "include": "source.cs" - } - ], - "end": "\\}" - }, - "csharp-namespace-identifier": { - "patterns": [ - { - "name": "entity.name.type.namespace.cs", - "match": "[_[:alpha:]][_[:alnum:]]*" + "include": "#unquoted-string-argument" } ] }, - "csharp-type-name": { + "unquoted-string-argument": { + "name": "string.quoted.double.cs", + "match": "[^$]+" + }, + "model-directive": { + "name": "meta.directive", + "match": "(@)(model)\\s+([^$]+)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.model" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "inherits-directive": { + "name": "meta.directive", + "match": "(@)(inherits)\\s+([^$]+)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.inherits" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "implements-directive": { + "name": "meta.directive", + "match": "(@)(implements)\\s+([^$]+)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.implements" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "layout-directive": { + "name": "meta.directive", + "match": "(@)(layout)\\s+([^$]+)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.layout" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "namespace-directive": { + "name": "meta.directive", + "match": "(@)(namespace)\\s+([^\\s]+)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.namespace" + }, + "3": { + "patterns": [ + { + "include": "#namespace-directive-argument" + } + ] + } + } + }, + "namespace-directive-argument": { + "match": "([_[:alpha:]][_[:alnum:]]*)(\\.)?", + "captures": { + "1": { + "name": "entity.name.type.namespace.cs" + }, + "2": { + "name": "punctuation.accessor.cs" + } + } + }, + "inject-directive": { + "name": "meta.directive", + "match": "(@)(inject)\\s*([\\S\\s]+?)?\\s*([_[:alpha:]][_[:alnum:]]*)?\\s*(?=$)", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.inject" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + }, + "4": { + "name": "entity.name.variable.property.cs" + } + } + }, + "attribute-directive": { + "name": "meta.directive", + "begin": "(@)(attribute)\\b\\s+", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.razor.directive.attribute" + } + }, "patterns": [ { - "match": "([_[:alpha:]][_[:alnum:]]*)\\s*(\\:\\:)", - "captures": { - "1": { - "name": "entity.name.type.alias.cs" - }, - "2": { - "name": "punctuation.separator.coloncolon.cs" + "include": "source.cs#attribute-section" + } + ], + "end": "(?<=\\])|$" + }, + "section-directive": { + "name": "meta.directive.block", + "begin": "(@)(section)\\b\\s+([_[:alpha:]][_[:alnum:]]*)?", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" } - } + ] + }, + "2": { + "name": "keyword.control.razor.directive.section" + }, + "3": { + "name": "variable.other.razor.directive.sectionName" + } + }, + "patterns": [ + { + "include": "#directive-markupblock" + } + ], + "end": "(?<=})" + }, + "directive-markupblock": { + "name": "meta.structure.razor.directive.markblock", + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "keyword.control.razor.directive.codeblock.open" + } + }, + "patterns": [ + { + "include": "$self" + } + ], + "end": "(\\})", + "endCaptures": { + "1": { + "name": "keyword.control.razor.directive.codeblock.close" + } + } + }, + "using-directive": { + "name": "meta.directive", + "match": "(@)(using)\\b\\s+(?!\\(|\\s)(.+?)?(;)?$", + "captures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.other.using.cs" + }, + "3": { + "patterns": [ + { + "include": "#using-static-directive" + }, + { + "include": "#using-alias-directive" + }, + { + "include": "#using-standard-directive" + } + ] + }, + "4": { + "name": "keyword.control.razor.optionalSemicolon" + } + } + }, + "using-static-directive": { + "match": "(static)\\b\\s+(.+)", + "captures": { + "1": { + "name": "keyword.other.static.cs" + }, + "2": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "using-alias-directive": { + "match": "([_[:alpha:]][_[:alnum:]]*)\\b\\s*(=)\\s*(.+)\\s*", + "captures": { + "1": { + "name": "entity.name.type.alias.cs" + }, + "2": { + "name": "keyword.operator.assignment.cs" + }, + "3": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + } + } + }, + "using-standard-directive": { + "match": "([_[:alpha:]][_[:alnum:]]*)\\s*", + "captures": { + "1": { + "name": "entity.name.type.namespace.cs" + } + } + }, + "transitioned-csharp-control-structures": { + "patterns": [ + { + "include": "#using-statement" }, { - "match": "([_[:alpha:]][_[:alnum:]]*)\\s*(\\.)", - "captures": { - "1": { - "name": "storage.type.cs" - }, - "2": { - "name": "punctuation.accessor.cs" - } - } + "include": "#if-statement" }, { - "match": "(\\.)\\s*([_[:alpha:]][_[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.cs" - }, - "2": { - "name": "storage.type.cs" - } - } + "include": "#else-part" }, { - "name": "storage.type.cs", - "match": "[_[:alpha:]][_[:alnum:]]*" + "include": "#foreach-statement" + }, + { + "include": "#for-statement" + }, + { + "include": "#while-statement" + }, + { + "include": "#switch-statement" + }, + { + "include": "#lock-statement" + }, + { + "include": "#do-statement" + }, + { + "include": "#try-statement" } ] + }, + "using-statement": { + "name": "meta.statement.using.razor", + "begin": "(?:^\\s*|(@))(using)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.other.using.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "if-statement": { + "name": "meta.statement.if.razor", + "begin": "(?:^\\s*|(@))(if)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.conditional.if.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "else-part": { + "name": "meta.statement.else.razor", + "begin": "(?:^|(?<=}))\\s*(else)\\b\\s*?(?: (if))?\\s*?(?=[\\n\\(\\{])", + "beginCaptures": { + "1": { + "name": "keyword.control.conditional.else.cs" + }, + "2": { + "name": "keyword.control.conditional.if.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "for-statement": { + "name": "meta.statement.for.razor", + "begin": "(?:^\\s*|(@))(for)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.loop.for.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "foreach-statement": { + "name": "meta.statement.foreach.razor", + "begin": "(?:^\\s*|(@)(await\\s+)?)(foreach)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#await-prefix" + } + ] + }, + "3": { + "name": "keyword.control.loop.foreach.cs" + } + }, + "patterns": [ + { + "include": "#foreach-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "foreach-condition": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.parenthesis.open.cs" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.parenthesis.close.cs" + } + }, + "patterns": [ + { + "match": "(?x)\n(?:\n (\\bvar\\b)|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\n)\\s+\n(\\g)\\s+\n\\b(in)\\b", + "captures": { + "1": { + "name": "keyword.other.var.cs" + }, + "2": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + }, + "7": { + "name": "entity.name.variable.local.cs" + }, + "8": { + "name": "keyword.control.loop.in.cs" + } + } + }, + { + "match": "(?x) # match foreach (var (x, y) in ...)\n(?:\\b(var)\\b\\s*)?\n(?\\((?:[^\\(\\)]|\\g)+\\))\\s+\n\\b(in)\\b", + "captures": { + "1": { + "name": "keyword.other.var.cs" + }, + "2": { + "patterns": [ + { + "include": "source.cs#tuple-declaration-deconstruction-element-list" + } + ] + }, + "3": { + "name": "keyword.control.loop.in.cs" + } + } + }, + { + "include": "source.cs#expression" + } + ] + }, + "do-statement": { + "name": "meta.statement.do.razor", + "begin": "(?:^\\s*|(@))(do)\\b\\s*", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.loop.do.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "while-statement": { + "name": "meta.statement.while.razor", + "begin": "(?:(@)|^\\s*|(?<=})\\s*)(while)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.loop.while.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cs" + } + } + }, + "switch-statement": { + "name": "meta.statement.switch.razor", + "begin": "(?:^\\s*|(@))(switch)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.switch.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#switch-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "switch-code-block": { + "name": "meta.structure.razor.csharp.codeblock.switch", + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.curlybrace.open.cs" + } + }, + "patterns": [ + { + "include": "source.cs#switch-label" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.curlybrace.close.cs" + } + } + }, + "lock-statement": { + "name": "meta.statement.lock.razor", + "begin": "(?:^\\s*|(@))(lock)\\b\\s*(?=\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.other.lock.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "try-statement": { + "patterns": [ + { + "include": "#try-block" + }, + { + "include": "#catch-clause" + }, + { + "include": "#finally-clause" + } + ] + }, + "try-block": { + "name": "meta.statement.try.razor", + "begin": "(?:^\\s*|(@))(try)\\b\\s*", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#transition" + } + ] + }, + "2": { + "name": "keyword.control.try.cs" + } + }, + "patterns": [ + { + "include": "#csharp-condition" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "catch-clause": { + "name": "meta.statement.catch.razor", + "begin": "(?:^|(?<=}))\\s*(catch)\\b\\s*?(?=[\\n\\(\\{])", + "beginCaptures": { + "1": { + "name": "keyword.control.try.catch.cs" + } + }, + "patterns": [ + { + "include": "#catch-condition" + }, + { + "include": "source.cs#when-clause" + }, + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "catch-condition": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.parenthesis.open.cs" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.parenthesis.close.cs" + } + }, + "patterns": [ + { + "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?:(\\g)\\b)?", + "captures": { + "1": { + "patterns": [ + { + "include": "source.cs#type" + } + ] + }, + "6": { + "name": "entity.name.variable.local.cs" + } + } + } + ] + }, + "finally-clause": { + "name": "meta.statement.finally.razor", + "begin": "(?:^|(?<=}))\\s*(finally)\\b\\s*?(?=[\\n\\{])", + "beginCaptures": { + "1": { + "name": "keyword.control.try.finally.cs" + } + }, + "patterns": [ + { + "include": "#csharp-code-block" + }, + { + "include": "#razor-codeblock-body" + } + ], + "end": "(?<=})" + }, + "await-prefix": { + "name": "keyword.other.await.cs", + "match": "(await)\\s+" + }, + "csharp-code-block": { + "name": "meta.structure.razor.csharp.codeblock", + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.curlybrace.open.cs" + } + }, + "patterns": [ + { + "include": "#razor-codeblock-body" + } + ], + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.curlybrace.close.cs" + } + } + }, + "csharp-condition": { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.parenthesis.open.cs" + } + }, + "patterns": [ + { + "include": "source.cs#local-variable-declaration" + }, + { + "include": "source.cs#expression" + }, + { + "include": "source.cs#punctuation-comma" + }, + { + "include": "source.cs#punctuation-semicolon" + } + ], + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.parenthesis.close.cs" + } + } } } } \ No newline at end of file diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json index eefa012ecba..4ab45dd0d66 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json @@ -1,7 +1,19 @@ [ { - "c": "@{", - "t": "text.html.cshtml keyword.control.cshtml", + "c": "@", + "t": "text.html.cshtml meta.structure.razor.codeblock keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "{", + "t": "text.html.cshtml meta.structure.razor.codeblock keyword.control.razor.directive.codeblock.open", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -13,7 +25,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -25,7 +37,7 @@ }, { "c": "var", - "t": "text.html.cshtml keyword.other.var.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.other.var.cs", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -37,7 +49,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -49,7 +61,7 @@ }, { "c": "total", - "t": "text.html.cshtml entity.name.variable.local.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs entity.name.variable.local.cs", "r": { "dark_plus": "entity.name.variable: #9CDCFE", "light_plus": "entity.name.variable: #001080", @@ -61,7 +73,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -73,7 +85,7 @@ }, { "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.operator.assignment.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -85,7 +97,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -97,7 +109,7 @@ }, { "c": "0", - "t": "text.html.cshtml constant.numeric.decimal.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs constant.numeric.decimal.cs", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #098658", @@ -109,7 +121,7 @@ }, { "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs punctuation.terminator.statement.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -121,7 +133,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -133,7 +145,7 @@ }, { "c": "var", - "t": "text.html.cshtml keyword.other.var.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.other.var.cs", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -145,7 +157,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -157,7 +169,7 @@ }, { "c": "totalMessage", - "t": "text.html.cshtml entity.name.variable.local.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs entity.name.variable.local.cs", "r": { "dark_plus": "entity.name.variable: #9CDCFE", "light_plus": "entity.name.variable: #001080", @@ -169,7 +181,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -181,7 +193,7 @@ }, { "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.operator.assignment.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -193,7 +205,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -205,7 +217,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.begin.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs string.quoted.double.cs punctuation.definition.string.begin.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -217,7 +229,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.end.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs string.quoted.double.cs punctuation.definition.string.end.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -229,235 +241,7 @@ }, { "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": " @", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "*", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "a", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "multiline", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "razor", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "comment", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "embedded", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "in", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "csharp", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "*", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "@", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs punctuation.terminator.statement.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -469,7 +253,91 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "@", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "*", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor keyword.control.razor.comment.star", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": " a multiline", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor comment.block.razor", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": " razor comment embedded in csharp ", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor comment.block.razor", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "*", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor keyword.control.razor.comment.star", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "@", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.comment.razor keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": " ", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -481,7 +349,7 @@ }, { "c": "if", - "t": "text.html.cshtml keyword.control.conditional.if.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor keyword.control.conditional.if.cs", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -493,7 +361,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -505,7 +373,7 @@ }, { "c": "(", - "t": "text.html.cshtml punctuation.parenthesis.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor punctuation.parenthesis.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -517,7 +385,7 @@ }, { "c": "IsPost", - "t": "text.html.cshtml variable.other.readwrite.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor variable.other.readwrite.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -529,7 +397,7 @@ }, { "c": ")", - "t": "text.html.cshtml punctuation.parenthesis.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor punctuation.parenthesis.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -541,7 +409,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -553,7 +421,7 @@ }, { "c": "{", - "t": "text.html.cshtml punctuation.curlybrace.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.curlybrace.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -565,7 +433,7 @@ }, { "c": " ", - "t": "text.html.cshtml punctuation.whitespace.comment.leading.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.whitespace.comment.leading.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -577,7 +445,7 @@ }, { "c": "//", - "t": "text.html.cshtml comment.line.double-slash.cs punctuation.definition.comment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs punctuation.definition.comment.cs", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -589,7 +457,7 @@ }, { "c": " Retrieve the numbers that the user entered.", - "t": "text.html.cshtml comment.line.double-slash.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -601,7 +469,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -613,7 +481,7 @@ }, { "c": "var", - "t": "text.html.cshtml keyword.other.var.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.other.var.cs", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -625,7 +493,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -637,7 +505,7 @@ }, { "c": "num1", - "t": "text.html.cshtml entity.name.variable.local.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.variable.local.cs", "r": { "dark_plus": "entity.name.variable: #9CDCFE", "light_plus": "entity.name.variable: #001080", @@ -649,7 +517,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -661,7 +529,7 @@ }, { "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.operator.assignment.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -673,7 +541,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -685,7 +553,7 @@ }, { "c": "Request", - "t": "text.html.cshtml variable.other.object.property.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock variable.other.object.property.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -697,7 +565,7 @@ }, { "c": "[", - "t": "text.html.cshtml punctuation.squarebracket.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.squarebracket.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -709,7 +577,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.begin.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs punctuation.definition.string.begin.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -721,7 +589,7 @@ }, { "c": "text1", - "t": "text.html.cshtml string.quoted.double.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -733,7 +601,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.end.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs punctuation.definition.string.end.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -745,7 +613,7 @@ }, { "c": "]", - "t": "text.html.cshtml punctuation.squarebracket.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.squarebracket.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -757,7 +625,7 @@ }, { "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.terminator.statement.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -769,7 +637,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -781,7 +649,7 @@ }, { "c": "var", - "t": "text.html.cshtml keyword.other.var.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.other.var.cs", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -793,7 +661,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -805,7 +673,7 @@ }, { "c": "num2", - "t": "text.html.cshtml entity.name.variable.local.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.variable.local.cs", "r": { "dark_plus": "entity.name.variable: #9CDCFE", "light_plus": "entity.name.variable: #001080", @@ -817,7 +685,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -829,7 +697,7 @@ }, { "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.operator.assignment.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -841,7 +709,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -853,7 +721,7 @@ }, { "c": "Request", - "t": "text.html.cshtml variable.other.object.property.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock variable.other.object.property.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -865,7 +733,7 @@ }, { "c": "[", - "t": "text.html.cshtml punctuation.squarebracket.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.squarebracket.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -877,7 +745,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.begin.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs punctuation.definition.string.begin.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -889,7 +757,7 @@ }, { "c": "text2", - "t": "text.html.cshtml string.quoted.double.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -901,7 +769,7 @@ }, { "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.end.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock string.quoted.double.cs punctuation.definition.string.end.cs", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -913,7 +781,7 @@ }, { "c": "]", - "t": "text.html.cshtml punctuation.squarebracket.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.squarebracket.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -925,7 +793,7 @@ }, { "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.terminator.statement.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -937,7 +805,7 @@ }, { "c": " ", - "t": "text.html.cshtml punctuation.whitespace.comment.leading.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.whitespace.comment.leading.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -949,7 +817,7 @@ }, { "c": "//", - "t": "text.html.cshtml comment.line.double-slash.cs punctuation.definition.comment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs punctuation.definition.comment.cs", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -961,7 +829,7 @@ }, { "c": " Convert the entered strings into integers numbers and add.", - "t": "text.html.cshtml comment.line.double-slash.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -973,7 +841,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -985,7 +853,7 @@ }, { "c": "total", - "t": "text.html.cshtml variable.other.readwrite.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock variable.other.readwrite.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -997,7 +865,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1009,7 +877,7 @@ }, { "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.operator.assignment.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1021,7 +889,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1033,7 +901,7 @@ }, { "c": "num1", - "t": "text.html.cshtml variable.other.object.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock variable.other.object.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1045,7 +913,7 @@ }, { "c": ".", - "t": "text.html.cshtml punctuation.accessor.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.accessor.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1057,7 +925,7 @@ }, { "c": "AsInt", - "t": "text.html.cshtml entity.name.function.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.function.cs", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1069,7 +937,7 @@ }, { "c": "(", - "t": "text.html.cshtml punctuation.parenthesis.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.parenthesis.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1081,7 +949,7 @@ }, { "c": ")", - "t": "text.html.cshtml punctuation.parenthesis.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.parenthesis.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1093,7 +961,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1105,7 +973,7 @@ }, { "c": "+", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.operator.arithmetic.cs", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1117,7 +985,7 @@ }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1129,7 +997,7 @@ }, { "c": "num2", - "t": "text.html.cshtml variable.other.object.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock variable.other.object.cs", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1141,7 +1009,7 @@ }, { "c": ".", - "t": "text.html.cshtml punctuation.accessor.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.accessor.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1153,7 +1021,7 @@ }, { "c": "AsInt", - "t": "text.html.cshtml entity.name.function.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.function.cs", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1165,7 +1033,7 @@ }, { "c": "(", - "t": "text.html.cshtml punctuation.parenthesis.open.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.parenthesis.open.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1177,7 +1045,7 @@ }, { "c": ")", - "t": "text.html.cshtml punctuation.parenthesis.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.parenthesis.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1189,7 +1057,7 @@ }, { "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.terminator.statement.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1201,7 +1069,7 @@ }, { "c": "\t\t", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1213,295 +1081,163 @@ }, { "c": "<", - "t": "text.html.cshtml keyword.operator.relational.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.begin.html", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" } }, { "c": "italic", - "t": "text.html.cshtml variable.other.readwrite.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.tag.html", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": "><", - "t": "text.html.cshtml keyword.operator.relational.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "bold", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6", + "hc_light": "entity.name.tag: #0F4A85" } }, { "c": ">", - "t": "text.html.cshtml keyword.operator.relational.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.end.html", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "totalMessage", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "=", - "t": "text.html.cshtml keyword.operator.assignment.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.begin.cs", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178", - "hc_light": "string: #0F4A85" - } - }, - { - "c": "Total = ", - "t": "text.html.cshtml string.quoted.double.cs", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178", - "hc_light": "string: #0F4A85" - } - }, - { - "c": "\"", - "t": "text.html.cshtml string.quoted.double.cs punctuation.definition.string.end.cs", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178", - "hc_light": "string: #0F4A85" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "+", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "total", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": ";", - "t": "text.html.cshtml punctuation.terminator.statement.cs", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" } }, { "c": "<", - "t": "text.html.cshtml keyword.operator.relational.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.begin.html", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "/", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" } }, { "c": "bold", - "t": "text.html.cshtml variable.other.readwrite.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock entity.name.tag.html", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" - } - }, - { - "c": "><", - "t": "text.html.cshtml keyword.operator.relational.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "/", - "t": "text.html.cshtml keyword.operator.arithmetic.cs", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" - } - }, - { - "c": "italic", - "t": "text.html.cshtml variable.other.readwrite.cs", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE", - "hc_light": "variable: #001080" + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6", + "hc_light": "entity.name.tag: #0F4A85" } }, { "c": ">", - "t": "text.html.cshtml keyword.operator.relational.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.end.html", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4", - "hc_light": "keyword.operator: #000000" + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" + } + }, + { + "c": "totalMessage = \"Total = \" + total;", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" + } + }, + { + "c": "", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" } }, { "c": " ", - "t": "text.html.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1513,7 +1249,7 @@ }, { "c": "}", - "t": "text.html.cshtml punctuation.curlybrace.close.cs", + "t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.curlybrace.close.cs", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1525,7 +1261,7 @@ }, { "c": "}", - "t": "text.html.cshtml keyword.control.cshtml", + "t": "text.html.cshtml meta.structure.razor.codeblock keyword.control.razor.directive.codeblock.close", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -3672,7 +3408,7 @@ } }, { - "c": "\t@* now we call the totalMessage method", + "c": "\t", "t": "text.html.cshtml", "r": { "dark_plus": "default: #D4D4D4", @@ -3684,68 +3420,8 @@ } }, { - "c": "\t (a multi line razor comment outside code) *@", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": " ", - "t": "text.html.cshtml", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" - } - }, - { - "c": "<", - "t": "text.html.cshtml meta.tag.structure.p.start.html punctuation.definition.tag.begin.html", - "r": { - "dark_plus": "punctuation.definition.tag: #808080", - "light_plus": "punctuation.definition.tag: #800000", - "dark_vs": "punctuation.definition.tag: #808080", - "light_vs": "punctuation.definition.tag: #800000", - "hc_black": "punctuation.definition.tag: #808080", - "hc_light": "punctuation.definition.tag: #0F4A85" - } - }, - { - "c": "p", - "t": "text.html.cshtml meta.tag.structure.p.start.html entity.name.tag.html", - "r": { - "dark_plus": "entity.name.tag: #569CD6", - "light_plus": "entity.name.tag: #800000", - "dark_vs": "entity.name.tag: #569CD6", - "light_vs": "entity.name.tag: #800000", - "hc_black": "entity.name.tag: #569CD6", - "hc_light": "entity.name.tag: #0F4A85" - } - }, - { - "c": ">", - "t": "text.html.cshtml meta.tag.structure.p.start.html punctuation.definition.tag.end.html", - "r": { - "dark_plus": "punctuation.definition.tag: #808080", - "light_plus": "punctuation.definition.tag: #800000", - "dark_vs": "punctuation.definition.tag: #808080", - "light_vs": "punctuation.definition.tag: #800000", - "hc_black": "punctuation.definition.tag: #808080", - "hc_light": "punctuation.definition.tag: #0F4A85" - } - }, - { - "c": "@totalMessage", - "t": "text.html.cshtml meta.expression.implicit.cshtml keyword.control.cshtml", + "c": "@", + "t": "text.html.cshtml meta.comment.razor keyword.control.cshtml.transition", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -3756,15 +3432,63 @@ } }, { - "c": "

", - "t": "text.html.cshtml meta.expression.implicit.cshtml", + "c": "*", + "t": "text.html.cshtml meta.comment.razor keyword.control.razor.comment.star", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "hc_light": "default: #292929" + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": " now we call the totalMessage method", + "t": "text.html.cshtml meta.comment.razor comment.block.razor", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "\t (a multi line razor comment outside code) ", + "t": "text.html.cshtml meta.comment.razor comment.block.razor", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668", + "hc_light": "comment: #515151" + } + }, + { + "c": "*", + "t": "text.html.cshtml meta.comment.razor keyword.control.razor.comment.star", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "@", + "t": "text.html.cshtml meta.comment.razor keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" } }, { @@ -3816,7 +3540,127 @@ } }, { - "c": "@(", + "c": "@", + "t": "text.html.cshtml meta.expression.implicit.cshtml keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "totalMessage", + "t": "text.html.cshtml meta.expression.implicit.cshtml source.cs variable.other.object.cs", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE", + "hc_light": "variable: #001080" + } + }, + { + "c": "", + "t": "text.html.cshtml meta.tag.structure.p.end.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" + } + }, + { + "c": " ", + "t": "text.html.cshtml", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" + } + }, + { + "c": "<", + "t": "text.html.cshtml meta.tag.structure.p.start.html punctuation.definition.tag.begin.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" + } + }, + { + "c": "p", + "t": "text.html.cshtml meta.tag.structure.p.start.html entity.name.tag.html", + "r": { + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6", + "hc_light": "entity.name.tag: #0F4A85" + } + }, + { + "c": ">", + "t": "text.html.cshtml meta.tag.structure.p.start.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080", + "hc_light": "punctuation.definition.tag: #0F4A85" + } + }, + { + "c": "@", + "t": "text.html.cshtml meta.expression.explicit.cshtml keyword.control.cshtml.transition", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0", + "hc_light": "keyword.control: #B5200D" + } + }, + { + "c": "(", "t": "text.html.cshtml meta.expression.explicit.cshtml keyword.control.cshtml", "r": { "dark_plus": "keyword.control: #C586C0", @@ -3936,7 +3780,7 @@ } }, { - "c": " An email address (with escaped at character): name@", + "c": " An email address (with escaped at character): name", "t": "text.html.cshtml", "r": { "dark_plus": "default: #D4D4D4", @@ -3948,15 +3792,27 @@ } }, { - "c": "@domain.com", - "t": "text.html.cshtml meta.expression.implicit.cshtml keyword.control.cshtml", + "c": "@@", + "t": "text.html.cshtml constant.character.escape.razor.transition", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0", - "hc_light": "keyword.control: #B5200D" + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #EE0000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "constant.character: #569CD6", + "hc_light": "constant.character.escape: #EE0000" + } + }, + { + "c": "domain.com", + "t": "text.html.cshtml", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF", + "hc_light": "default: #292929" } }, { From 47aab333189313be5cee01f3fe45c8f4a1ccc789 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 10 Oct 2022 12:55:31 -0700 Subject: [PATCH 461/599] Allow kernel source command to throw (#163216) --- .../notebook/browser/services/notebookKernelServiceImpl.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts index 2ce63b5332e..fac4b35285c 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts @@ -71,7 +71,11 @@ class SourceAction extends Disposable implements ISourceAction { } private async _runAction(): Promise { - await this.action.run(); + try { + await this.action.run(); + } catch (error) { + console.warn(`Kernel source command failed: ${error}`); + } } } From 63e8654374e4bf59eea7e4fc4628a725f0120c52 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 10 Oct 2022 13:05:53 -0700 Subject: [PATCH 462/599] Make debug start button wider to match other workbench menu buttons (#163217) Fix #163193 --- .../workbench/contrib/debug/browser/media/debugViewlet.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 3af216decd0..c9d7cb9eea3 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -41,6 +41,12 @@ flex-shrink: 0; } +.monaco-workbench .part > .title > .title-actions .start-debug-action-item .codicon-debug-start { + width: 18px; + height: 21px; + padding-left: 2px; +} + .monaco-workbench .monaco-action-bar .start-debug-action-item .configuration .monaco-select-box { border: none; margin-top: 0px; From f5b9fe32eb952187a35c947506b4f0da15693434 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Mon, 10 Oct 2022 21:08:14 +0000 Subject: [PATCH 463/599] =?UTF-8?q?=F0=9F=90=9B=20Fix=20unawaited=20call?= =?UTF-8?q?=20to=20show=20CWD=20picker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Babak K. Shandiz --- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index d4a0e680568..8d3c016c4ae 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -973,7 +973,7 @@ export class TerminalService implements ITerminalService { const splitActiveTerminal = typeof options?.location === 'object' && 'splitActiveTerminal' in options.location ? options.location.splitActiveTerminal : typeof options?.location === 'object' ? 'parentTerminal' in options.location : false; - this._resolveCwd(shellLaunchConfig, splitActiveTerminal, options); + await this._resolveCwd(shellLaunchConfig, splitActiveTerminal, options); // Launch the contributed profile if (contributedProfile) { From fefd5519f91f54fb0c32cde5a4adc42cbb636f38 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 10 Oct 2022 15:16:56 -0700 Subject: [PATCH 464/599] Make sure we still clear DisposableMap if dispose throws (#163226) Make sure we clear DisposableMap if dispose throws --- src/vs/base/common/lifecycle.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index b57542c8497..08e4da78072 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -456,15 +456,22 @@ export class DisposableMap implements ID trackDisposable(this); } - dispose() { + dispose(): void { markAsDisposed(this); this._isDisposed = true; this.clearAndDisposeAll(); } - clearAndDisposeAll() { - dispose(this._store.values()); - this._store.clear(); + clearAndDisposeAll(): void { + if (!this._store.size) { + return; + } + + try { + dispose(this._store.values()); + } finally { + this._store.clear(); + } } has(key: K): boolean { From dc69e229847e2a3d6b5228099e8a3b516511c5eb Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 10 Oct 2022 11:08:59 -0700 Subject: [PATCH 465/599] fix build --- .../cli/cli-compile-and-publish.yml | 50 +++++++++++ build/azure-pipelines/cli/cli-darwin-sign.yml | 39 +++++++++ build/azure-pipelines/cli/cli-win32-sign.yml | 65 +++++++++++++++ .../cli/install-rust-posix.yml | 4 +- .../cli/install-rust-win32.yml | 4 +- .../darwin/cli-build-darwin.yml | 45 ++++------ .../darwin/product-build-darwin-cli-sign.yml | 48 ++--------- .../darwin/product-build-darwin.yml | 19 +++-- .../azure-pipelines/linux/cli-build-linux.yml | 82 ++++++++++--------- .../linux/product-build-linux-client.yml | 18 ++-- build/azure-pipelines/product-build.yml | 37 ++++----- .../azure-pipelines/win32/cli-build-win32.yml | 51 ++++-------- .../win32/product-build-win32-cli-sign.yml | 73 ++--------------- .../win32/product-build-win32.yml | 19 +++-- 14 files changed, 303 insertions(+), 251 deletions(-) create mode 100644 build/azure-pipelines/cli/cli-compile-and-publish.yml create mode 100644 build/azure-pipelines/cli/cli-darwin-sign.yml create mode 100644 build/azure-pipelines/cli/cli-win32-sign.yml diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml new file mode 100644 index 00000000000..a97446c274b --- /dev/null +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -0,0 +1,50 @@ +parameters: + - name: VSCODE_CLI_TARGET + type: string + - name: VSCODE_CLI_ARTIFACT + type: string + - name: VSCODE_CLI_ENV + type: object + default: {} + +steps: + - script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code-tunnel + displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }} + workingDirectory: $(Build.SourcesDirectory)/cli + env: + VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) + VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) + VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) + VSCODE_CLI_ASSET_NAME: ${{ parameters.VSCODE_CLI_ARTIFACT }} + VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) + VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) + ${{ each pair in parameters.VSCODE_CLI_ENV }}: + ${{ pair.key }}: ${{ pair.value }} + + - ${{ if or(contains(parameters.VSCODE_CLI_TARGET, '-windows-'), contains(parameters.VSCODE_CLI_TARGET, '-darwin')) }}: + - task: ArchiveFiles@2 + inputs: + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-')}}: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel.exe + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin')}}: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip + + - publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip + artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact + + - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-linux-') }}: + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel + includeRootFolder: false + archiveType: tar + tarCompression: gz + archiveFile: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz + + - publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz + artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} + displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact diff --git a/build/azure-pipelines/cli/cli-darwin-sign.yml b/build/azure-pipelines/cli/cli-darwin-sign.yml new file mode 100644 index 00000000000..30d2bc3b566 --- /dev/null +++ b/build/azure-pipelines/cli/cli-darwin-sign.yml @@ -0,0 +1,39 @@ +parameters: + - name: VSCODE_CLI_ARTIFACTS + type: object + default: [] + +steps: + - task: UseDotNet@2 + inputs: + version: 2.x + + - task: EsrpClientTool@1 + displayName: Download ESRPClient + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - task: DownloadPipelineArtifact@2 + displayName: Download ${{ target }} + inputs: + artifact: ${{ target }} + path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + + - script: | + set -e + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" + displayName: Codesign + + - script: | + set -e + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" + displayName: Notarize + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - script: | + ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") + mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip + echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" + displayName: Set asset id variable + + - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip + artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/cli/cli-win32-sign.yml b/build/azure-pipelines/cli/cli-win32-sign.yml new file mode 100644 index 00000000000..91e069617d8 --- /dev/null +++ b/build/azure-pipelines/cli/cli-win32-sign.yml @@ -0,0 +1,65 @@ +parameters: + - name: VSCODE_CLI_ARTIFACTS + type: object + default: [] + +steps: + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "ESRP-PKI,esrp-aad-username,esrp-aad-password" + + - task: UseDotNet@2 + displayName: "Use .NET" + inputs: + version: 3.x + + - task: EsrpClientTool@1 + displayName: "Use ESRP client" + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - task: DownloadPipelineArtifact@2 + displayName: Download artifacts + inputs: + artifact: ${{ target }} + path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} + + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip + destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $EsrpClientTool = (gci -directory -filter EsrpClientTool_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName + $EsrpCliZip = (gci -recurse -filter esrpcli.*.zip $EsrpClientTool | Select-Object -last 1).FullName + mkdir -p $(Agent.TempDirectory)\esrpcli + Expand-Archive -Path $EsrpCliZip -DestinationPath $(Agent.TempDirectory)\esrpcli + $EsrpCliDllPath = (gci -recurse -filter esrpcli.dll $(Agent.TempDirectory)\esrpcli | Select-Object -last 1).FullName + echo "##vso[task.setvariable variable=EsrpCliDllPath]$EsrpCliDllPath" + displayName: Find ESRP CLI + + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" } + displayName: "Code sign" + + - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: + - powershell: | + $ASSET_ID = "${{ target }}".replace("unsigned_", ""); + echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" + displayName: Set asset id variable + + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code-tunnel.exe + includeRootFolder: false + archiveType: zip + archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + + - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip + artifact: $(ASSET_ID) diff --git a/build/azure-pipelines/cli/install-rust-posix.yml b/build/azure-pipelines/cli/install-rust-posix.yml index 16eee1a1b98..7dddfb5eb9b 100644 --- a/build/azure-pipelines/cli/install-rust-posix.yml +++ b/build/azure-pipelines/cli/install-rust-posix.yml @@ -25,8 +25,8 @@ steps: displayName: "Set Rust version" - ${{ each target in parameters.targets }}: - - script: rustup target add ${{ target.target }} - displayName: "🎯 Adding '${{ target.target }}'" + - script: rustup target add ${{ target }} + displayName: "Adding Rust target '${{ target }}'" - script: | rustc --version diff --git a/build/azure-pipelines/cli/install-rust-win32.yml b/build/azure-pipelines/cli/install-rust-win32.yml index 595201cc7c7..0b345892ab2 100644 --- a/build/azure-pipelines/cli/install-rust-win32.yml +++ b/build/azure-pipelines/cli/install-rust-win32.yml @@ -26,8 +26,8 @@ steps: displayName: "Set Rust version" - ${{ each target in parameters.targets }}: - - script: rustup target add ${{ target.target }} - displayName: "🎯 Adding '${{ target.target }}'" + - script: rustup target add ${{ target }} + displayName: "Adding Rust target '${{ target }}'" - script: | rustc --version diff --git a/build/azure-pipelines/darwin/cli-build-darwin.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml index bb1a71c9437..42632c280e6 100644 --- a/build/azure-pipelines/darwin/cli-build-darwin.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -9,14 +9,6 @@ parameters: type: string default: stable -variables: - - name: VSCODE_CLI_TARGETS - value: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - { target: x86_64-apple-darwin, artifact: unsigned_vscode_cli_darwin_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - { target: aarch64-apple-darwin, artifact: unsigned_vscode_cli_darwin_arm64_cli } - steps: - task: NodeTool@0 inputs: @@ -35,27 +27,20 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ variables.VSCODE_CLI_TARGETS }} + targets: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - x86_64-apple-darwin + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - aarch64-apple-darwin - - ${{ each target in variables.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel - displayName: Compile ${{ target.artifact }} - workingDirectory: $(Build.SourcesDirectory)/cli - env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-apple-darwin + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_x64_cli - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel - includeRootFolder: false - archiveType: zip - archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip - - - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip - artifact: ${{ target.artifact }} - displayName: Publish ${{ target.artifact }} artifact + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-apple-darwin + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_arm64_cli diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index b36e338d78b..431eb8ec09b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -4,14 +4,6 @@ parameters: - name: VSCODE_BUILD_MACOS_ARM64 type: boolean -variables: - - name: VSCODE_CLI_ARTIFACTS - value: - - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - unsigned_vscode_cli_darwin_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - unsigned_vscode_cli_darwin_arm64_cli - steps: - task: NodeTool@0 inputs: @@ -44,36 +36,10 @@ steps: done displayName: Install build dependencies - - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - - task: DownloadPipelineArtifact@2 - displayName: Download ${{ target }} - inputs: - artifact: ${{ target }} - path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} - - - task: UseDotNet@2 - inputs: - version: 2.x - - - task: EsrpClientTool@1 - displayName: Download ESRPClient - - - script: | - set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-sign $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" - displayName: Codesign - - - script: | - set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" darwin-notarize $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/pkg "*.zip" - displayName: Notarize - - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - - script: | - ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") - mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip - echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" - displayName: Set asset id variable - - - publish: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$(ASSET_ID).zip - artifact: $(ASSET_ID) + - template: ../cli/cli-darwin-sign.yml + parameters: + VSCODE_CLI_ARTIFACTS: + - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: + - unsigned_vscode_cli_darwin_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: + - unsigned_vscode_cli_darwin_arm64_cli diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 86392ecbc43..f8e3e1d2666 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -185,17 +185,24 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: - artifact: unsigned_vscode_cli_darwin_x64_cli - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: - artifact: unsigned_vscode_cli_darwin_arm64_cli + artifact: unsigned_vscode_cli_darwin_arm64_cli patterns: '**' - path: $(Build.ArtifactStagingDirectory) + path: $(Build.ArtifactStagingDirectory)/cli displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_darwin_x64_cli + patterns: '**' + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - script: | set -e - unzip "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -d "$(APP_PATH)/Contents/Resources/app/bin" + ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) + unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(APP_PATH)/Contents/Resources/app/bin" chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml index a96a784b659..2f6db518991 100644 --- a/build/azure-pipelines/linux/cli-build-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -1,28 +1,22 @@ parameters: - name: VSCODE_BUILD_LINUX_ALPINE type: boolean + default: false - name: VSCODE_BUILD_LINUX type: boolean + default: false + - name: VSCODE_BUILD_LINUX_ALPINE_ARM64 + type: boolean + default: false + - name: VSCODE_BUILD_LINUX_ARM64 + type: boolean + default: false - name: VSCODE_QUALITY type: string - name: channel type: string default: stable -variables: - - name: VSCODE_CLI_TARGETS - value: - - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: - - { target: aarch64-unknown-linux-musl, artifact: vscode_cli_alpine_arm64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - - { target: aarch64-unknown-linux-gnu, artifact: vscode_cli_linux_arm64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_ARCH, 'x86') }}: - - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: - - { target: x86_64-unknown-linux-musl, artifact: vscode_cli_alpine_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - - { target: x86_64-unknown-linux-gnu, artifact: vscode_cli_linux_x64_cli } - steps: # inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile - bash: | @@ -48,30 +42,42 @@ steps: - template: ../cli/install-rust-posix.yml parameters: - targets: ${{ variables.VSCODE_CLI_TARGETS }} + targets: + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - aarch64-unknown-linux-musl + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - x86_64-unknown-linux-musl + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - aarch64-unknown-linux-gnu + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - x86_64-unknown-linux-gnu - - ${{ each target in variables.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel - displayName: Compile ${{ target.artifact }} - workingDirectory: $(Build.SourcesDirectory)/cli - env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - CXX_aarch64-unknown-linux-musl: musl-g++ - CC_aarch64-unknown-linux-musl: musl-gcc + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-unknown-linux-musl + VSCODE_CLI_ARTIFACT: vscode_cli_alpine_arm64_cli + VSCODE_CLI_ENV: + CXX_aarch64-unknown-linux-musl: musl-g++ + CC_aarch64-unknown-linux-musl: musl-gcc - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel - includeRootFolder: false - archiveType: tar - tarCompression: gz - archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-unknown-linux-musl + VSCODE_CLI_ARTIFACT: vscode_cli_alpine_x64_cli + VSCODE_CLI_ENV: + CXX_aarch64-unknown-linux-musl: musl-g++ + CC_aarch64-unknown-linux-musl: musl-gcc - - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.tar.gz - artifact: ${{ target.artifact }} - displayName: Publish ${{ target.artifact }} artifact + - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-unknown-linux-gnu + VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli + + - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-unknown-linux-gnu + VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index cf2af3a2af3..13f48d400da 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -257,17 +257,23 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: - artifact: vscode_cli_linux_x64_cli - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: - artifact: vscode_cli_linux_arm64_cli + artifact: vscode_cli_linux_arm64_cli patterns: '**' - path: $(Build.ArtifactStagingDirectory) + path: $(Build.ArtifactStagingDirectory)/cli displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_x64_cli + patterns: '**' + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - script: | set -e - tar -xzvf $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin + tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" fi diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 419a8c54056..d51073fb0c4 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -182,20 +182,16 @@ stages: - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE, true)) }}: - job: LinuxX86 pool: vscode-1es-linux - variables: - VSCODE_ARCH: x64 steps: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} - VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} + VSCODE_BUILD_LINUX_ALPINE: ${{ parameters.VSCODE_BUILD_LINUX_ALPINE }} + VSCODE_BUILD_LINUX: ${{ parameters.VSCODE_BUILD_LINUX }} - ${{ if or(eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true), eq(parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64, true)) }}: - job: LinuxArm64 pool: vscode-1es-linux-20.04-arm64 - variables: - VSCODE_ARCH: arm64 steps: - task: NodeTool@0 displayName: Install Node.js @@ -210,9 +206,8 @@ stages: - template: ./linux/cli-build-linux.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_ARCH: arm64 - VSCODE_BUILD_LINUX_ALPINE: ${{ variables.VSCODE_BUILD_LINUX_ALPINE }} - VSCODE_BUILD_LINUX: ${{ variables.VSCODE_BUILD_LINUX }} + VSCODE_BUILD_LINUX_ALPINE_ARM64: ${{ parameters.VSCODE_BUILD_LINUX_ALPINE_ARM64 }} + VSCODE_BUILD_LINUX_ARM64: ${{ parameters.VSCODE_BUILD_LINUX_ARM64 }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_MACOS, true) }}: - job: MacOS @@ -222,8 +217,8 @@ stages: - template: ./darwin/cli-build-darwin.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_MACOS: ${{ variables.VSCODE_BUILD_MACOS }} - VSCODE_BUILD_MACOS_ARM64: ${{ variables.VSCODE_BUILD_MACOS_ARM64 }} + VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }} + VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }} - ${{ if eq(variables.VSCODE_BUILD_STAGE_WINDOWS, true) }}: - job: Windows @@ -232,8 +227,8 @@ stages: - template: ./win32/cli-build-win32.yml parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} - VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} + VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -294,7 +289,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -324,7 +319,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -335,8 +330,8 @@ stages: steps: - template: win32/product-build-win32-cli-sign.yml parameters: - VSCODE_BUILD_WIN32: ${{ variables.VSCODE_BUILD_WIN32 }} - VSCODE_BUILD_WIN32_ARM64: ${{ variables.VSCODE_BUILD_WIN32_ARM64 }} + VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} + VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies @@ -434,7 +429,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_SMOKE_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -487,7 +482,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -583,7 +578,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false @@ -632,7 +627,7 @@ stages: parameters: VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_BUILD_TUNNEL_CLI: ${{ variables.VSCODE_BUILD_TUNNEL_CLI }} + VSCODE_BUILD_TUNNEL_CLI: ${{ parameters.VSCODE_BUILD_TUNNEL_CLI }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false VSCODE_RUN_SMOKE_TESTS: false diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index 3b5525b930d..2b77bccfd2a 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -9,14 +9,6 @@ parameters: type: string default: stable -variables: - - name: VSCODE_CLI_TARGETS - value: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - { target: x86_64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_x64_cli } - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - { target: aarch64-pc-windows-msvc, artifact: unsigned_vscode_cli_win32_arm64_cli } - steps: - task: NodeTool@0 inputs: @@ -36,7 +28,11 @@ steps: - template: ../cli/install-rust-win32.yml parameters: - targets: ${{ parameters.VSCODE_CLI_TARGETS }} + targets: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - x86_64-pc-windows-msvc + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - aarch64-pc-windows-msvc - template: ../vcpkg-install.yml parameters: @@ -48,31 +44,20 @@ steps: vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg targetDirectory: $(Build.ArtifactStagingDirectory)/deps - - ${{ each target in parameters.VSCODE_CLI_TARGETS }}: - - script: cargo build --release --target ${{ target.target }} --bin=code-tunnel - displayName: Compile ${{ target.artifact }} - workingDirectory: $(Build.SourcesDirectory)/cli - env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ target.artifact }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) - ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: x86_64-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_x64_cli + VSCODE_CLI_ENV: OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include - ${{ if eq(target, 'aarch64-pc-windows-msvc') }}: + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: aarch64-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_arm64_cli + VSCODE_CLI_ENV: OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include - - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ target.target }}/release/code-tunnel.exe - includeRootFolder: false - archiveType: zip - archiveFile: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip - - - publish: $(Build.ArtifactStagingDirectory)/${{ target.artifact }}.zip - artifact: ${{ target.artifact }} - displayName: Publish ${{ target.artifact }} artifact diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index f1b2e80a117..ee493bc6f05 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -4,13 +4,6 @@ parameters: - name: VSCODE_BUILD_WIN32_ARM64 type: boolean -variables: - - name: VSCODE_CLI_ARTIFACTS - value: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - unsigned_vscode_cli_win32_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - unsigned_vscode_cli_win32_arm64_cli steps: - task: NodeTool@0 displayName: "Use Node.js" @@ -23,62 +16,10 @@ steps: exec { yarn } displayName: Install build dependencies - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "ESRP-PKI,esrp-aad-username,esrp-aad-password" - - - ${{ each target in variables.VSCODE_CLI_ARTIFACTS }}: - - task: DownloadPipelineArtifact@2 - displayName: Download artifacts - inputs: - artifact: ${{ target }} - path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }} - - - task: ExtractFiles@1 - inputs: - archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip - destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }} - - - task: UseDotNet@2 - displayName: "Use .NET" - inputs: - version: 3.x - - - task: EsrpClientTool@1 - displayName: "Use ESRP client" - - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $EsrpClientTool = (gci -directory -filter EsrpClientTool_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName - $EsrpCliZip = (gci -recurse -filter esrpcli.*.zip $EsrpClientTool | Select-Object -last 1).FullName - mkdir -p $(Agent.TempDirectory)\esrpcli - Expand-Archive -Path $EsrpCliZip -DestinationPath $(Agent.TempDirectory)\esrpcli - $EsrpCliDllPath = (gci -recurse -filter esrpcli.dll $(Agent.TempDirectory)\esrpcli | Select-Object -last 1).FullName - echo "##vso[task.setvariable variable=EsrpCliDllPath]$EsrpCliDllPath" - displayName: Find ESRP CLI - - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build\azure-pipelines\common\sign $env:EsrpCliDllPath windows $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) $(Build.ArtifactStagingDirectory)/sign "*.exe" } - displayName: "Code sign" - - - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - - powershell: | - $ASSET_ID = "${{ target }}".replace("unsigned_", ""); - echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" - displayName: Set asset id variable - - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code-tunnel.exe - includeRootFolder: false - archiveType: zip - archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip - - - publish: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip - artifact: $(ASSET_ID) + - template: ../cli/cli-win32-sign.yml + parameters: + VSCODE_CLI_ARTIFACTS: + - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: + - unsigned_vscode_cli_win32_x64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: + - unsigned_vscode_cli_win32_arm64_cli diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 6827c27d5eb..0c0bcf8b40b 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -180,17 +180,24 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - task: DownloadPipelineArtifact@2 inputs: - ${{ if eq(variables.VSCODE_ARCH, 'x64') }}: - artifact: unsigned_vscode_cli_win32_x64_cli - ${{ if eq(variables.VSCODE_ARCH, 'arm64') }}: - artifact: unsigned_vscode_cli_win32_arm64_cli + artifact: unsigned_vscode_cli_win32_arm64_cli patterns: '**' - path: $(Build.ArtifactStagingDirectory) + path: $(Build.ArtifactStagingDirectory)/cli displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_win32_x64_cli + patterns: '**' + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - powershell: | . build/azure-pipelines/win32/exec.ps1 - Expand-Archive -Path "$(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip" -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" + $ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName + Expand-Archive -Path $ArtifactName -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" if ("$(VSCODE_QUALITY)" -ne "stable") { From ae34e8d2df286f8c8882d22db417e6dc4cdb01f5 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 10 Oct 2022 16:28:24 -0700 Subject: [PATCH 466/599] Fix Download command not appearing in the remote indicator (#163232) --- src/vs/workbench/contrib/update/browser/update.contribution.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index bfaa857ef3b..68185b8ea63 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -155,7 +155,8 @@ class DownloadAction extends Action2 { precondition: IsWebContext, // Only show when running in a web browser f1: true, menu: [{ - id: MenuId.StatusBarRemoteIndicatorMenu, + id: MenuId.StatusBarWindowIndicatorMenu, + when: IsWebContext }] }); } From f4c58486f4a33b8c61f30a244374ef0d27dc19c3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 10 Oct 2022 21:15:14 -0700 Subject: [PATCH 467/599] Run all webview panels of a given viewtype in the same origin (#163236) For #132464 --- .../api/browser/mainThreadWebviewPanels.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index d33c3fba499..d50996eacd1 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -6,12 +6,16 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; import { WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; @@ -75,6 +79,43 @@ class WebviewViewTypeTransformer { } } +/** + * Stores the unique origins for webviews. + * + * These are randomly generated, but keyed on extension and webview viewType. + */ +class WebviewOriginStore { + + private readonly memento: Memento; + private readonly state: MementoObject; + + constructor( + storageKey: string, + @IStorageService storageService: IStorageService, + ) { + this.memento = new Memento(storageKey, storageService); + this.state = this.memento.getMemento(StorageScope.APPLICATION, StorageTarget.MACHINE); + } + + public getOrigin(extId: ExtensionIdentifier, viewType: string): string { + const key = this.getKey(extId, viewType); + + const existing = this.state[key]; + if (existing && typeof existing === 'string') { + return existing; + } + + const newOrigin = generateUuid(); + this.state[key] = newOrigin; + this.memento.saveMemento(); + return newOrigin; + } + + private getKey(extId: ExtensionIdentifier, viewType: string): string { + return JSON.stringify([extId.value, viewType]); + } +} + export class MainThreadWebviewPanels extends Disposable implements extHostProtocol.MainThreadWebviewPanelsShape { private readonly webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-'); @@ -85,6 +126,8 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc private readonly _revivers = this._register(new DisposableMap()); + private readonly webviewOriginStore: WebviewOriginStore; + constructor( context: IExtHostContext, private readonly _mainThreadWebviews: MainThreadWebviews, @@ -92,11 +135,14 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IEditorService private readonly _editorService: IEditorService, @IExtensionService extensionService: IExtensionService, + @IStorageService storageService: IStorageService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, ) { super(); + this.webviewOriginStore = new WebviewOriginStore('mainThreadWebviewPanel.origins', storageService); + this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewPanels); this._register(_editorService.onDidActiveEditorChange(() => { @@ -152,9 +198,11 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc } : {}; const extension = reviveWebviewExtension(extensionData); + const origin = this.webviewOriginStore.getOrigin(extension.id, viewType); const webview = this._webviewWorkbenchService.openWebview({ id: handle, + origin, providedViewType: viewType, options: reviveWebviewOptions(initData.panelOptions), contentOptions: reviveWebviewContentOptions(initData.webviewOptions), From 645c718a996a92aced1354f88cb861c5154047d8 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 11 Oct 2022 00:15:02 -0700 Subject: [PATCH 468/599] Revert "Debt - extract Continue On picker and contrib into separate class (#163002)" (#163251) This reverts commit a8fe1cc1578ee6dfb7ad8d7d4d627b0af2def1a4. --- .../editSessions/browser/continueOnPicker.ts | 160 --------------- .../browser/editSessions.contribution.ts | 191 +++++++++++++++++- 2 files changed, 183 insertions(+), 168 deletions(-) delete mode 100644 src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts diff --git a/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts b/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts deleted file mode 100644 index e9b3df9ac79..00000000000 --- a/src/vs/workbench/contrib/editSessions/browser/continueOnPicker.ts +++ /dev/null @@ -1,160 +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 { MenuRegistry } from 'vs/platform/actions/common/actions'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; -import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { localize } from 'vs/nls'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const IContinueOnPicker = createDecorator('IContinueOnPicker'); -export interface IContinueOnPicker { - _serviceBrand: undefined; - - pick(): Promise; -} - -export class ContinueOnPicker extends Disposable implements IContinueOnPicker { - _serviceBrand = undefined; - - private continueEditSessionOptions: ContinueEditSessionItem[] = []; - - constructor( - @IQuickInputService private readonly quickInputService: IQuickInputService, - @ICommandService private commandService: ICommandService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - ) { - super(); - - this.registerContributedEditSessionOptions(); - } - - private registerContributedEditSessionOptions() { - continueEditSessionExtPoint.setHandler(extensions => { - const continueEditSessionOptions: ContinueEditSessionItem[] = []; - for (const extension of extensions) { - if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) { - continue; - } - if (!Array.isArray(extension.value)) { - continue; - } - for (const contribution of extension.value) { - const command = MenuRegistry.getCommand(contribution.command); - if (!command) { - return; - } - - const icon = command.icon; - const title = typeof command.title === 'string' ? command.title : command.title.value; - - continueEditSessionOptions.push(new ContinueEditSessionItem( - ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title, - command.id, - command.source, - ContextKeyExpr.deserialize(contribution.when) - )); - } - } - this.continueEditSessionOptions = continueEditSessionOptions; - }); - } - - async pick(): Promise { - const quickPick = this.quickInputService.createQuickPick(); - - const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER - ? this.contextService.getWorkspace().folders[0].name - : this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', '); - quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`); - quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working'); - quickPick.items = this.createPickItems(); - - const command = await new Promise((resolve, reject) => { - quickPick.onDidHide(() => resolve(undefined)); - - quickPick.onDidAccept((e) => { - const selection = quickPick.activeItems[0].command; - resolve(selection); - quickPick.hide(); - }); - - quickPick.show(); - }); - - quickPick.dispose(); - - if (command === undefined) { - return undefined; - } - - try { - const uri = await this.commandService.executeCommand(command); - - // Some continue on commands do not return a URI - // to support extensions which want to be in control - // of how the destination is opened - if (uri === undefined) { return 'noDestinationUri'; } - - return URI.isUri(uri) ? uri : undefined; - } catch (ex) { - return undefined; - } - } - - private createPickItems(): ContinueEditSessionItem[] { - const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when)); - return items.sort((item1, item2) => item1.label.localeCompare(item2.label)); - } -} - -class ContinueEditSessionItem implements IQuickPickItem { - constructor( - public readonly label: string, - public readonly command: string, - public readonly description?: string, - public readonly when?: ContextKeyExpression, - ) { } -} - -interface ICommand { - command: string; - group: string; - when: string; -} - -const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint({ - extensionPoint: 'continueEditSession', - jsonSchema: { - description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'), - type: 'array', - items: { - type: 'object', - properties: { - command: { - description: localize('continueEditSessionExtPoint.command', 'Identifier of the command to execute. The command must be declared in the \'commands\'-section and return a URI representing a different environment where the current edit session can be continued.'), - type: 'string' - }, - group: { - description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'), - type: 'string' - }, - when: { - description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'), - type: 'string' - } - }, - required: ['command'] - } - } -}); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 3538149f973..af450bcd68e 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -7,7 +7,7 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, IAction2Options, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { IEditSessionsStorageService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions'; @@ -20,17 +20,24 @@ import { encodeBase64 } from 'vs/base/common/buffer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { EditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/browser/editSessionsStorageService'; -import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { getFileNamesMessage, IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { getFileNamesMessage, IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ContextKeyExpr, ContextKeyExpression, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtualWorkspace'; +import { Schemas } from 'vs/base/common/network'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; +import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { EditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessionsLogService'; import { IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -38,20 +45,20 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews'; import { EditSessionsFileSystemProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsFileSystemProvider'; +import { isNative } from 'vs/base/common/platform'; import { WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { equals } from 'vs/base/common/objects'; import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IOutputService } from 'vs/workbench/services/output/common/output'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { sha1Hex } from 'vs/base/browser/hash'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { ContinueOnPicker, IContinueOnPicker } from 'vs/workbench/contrib/editSessions/browser/continueOnPicker'; registerSingleton(IEditSessionsLogService, EditSessionsLogService, false); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false); -registerSingleton(IContinueOnPicker, ContinueOnPicker, InstantiationType.Delayed); const continueWorkingOnCommand: IAction2Options = { id: '_workbench.editSessions.actions.continueEditSession', @@ -59,6 +66,12 @@ const continueWorkingOnCommand: IAction2Options = { precondition: WorkspaceFolderCountContext.notEqualsTo('0'), f1: true }; +const openLocalFolderCommand: IAction2Options = { + id: '_workbench.editSessions.actions.continueEditSession.openLocalFolder', + title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' }, + category: EDIT_SESSION_SYNC_CATEGORY, + precondition: IsWebContext +}; const showOutputChannelCommand: IAction2Options = { id: 'workbench.editSessions.actions.showOutputChannel', title: { value: localize('show log', 'Show Log'), original: 'Show Log' }, @@ -73,6 +86,9 @@ const queryParamName = 'editSessionId'; const useEditSessionsWithContinueOn = 'workbench.editSessions.continueOn'; export class EditSessionsContribution extends Disposable implements IWorkbenchContribution { + + private continueEditSessionOptions: ContinueEditSessionItem[] = []; + private readonly shouldShowViewsContext: IContextKey; private static APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn'; @@ -94,11 +110,13 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo @IConfigurationService private configurationService: IConfigurationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IEditSessionIdentityService private readonly editSessionIdentityService: IEditSessionIdentityService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @ICommandService private commandService: ICommandService, @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IStorageService private readonly storageService: IStorageService, @IActivityService private readonly activityService: IActivityService, - @IContinueOnPicker private readonly continueOnPicker: IContinueOnPicker, ) { super(); @@ -106,6 +124,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerActions(); this.registerViews(); + this.registerContributedEditSessionOptions(); this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService); @@ -218,6 +237,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerResumeLatestEditSessionAction(); this.registerStoreLatestEditSessionAction(); + this.registerContinueInLocalFolderAction(); + this.registerShowEditSessionViewAction(); this.registerShowEditSessionOutputChannelAction(); } @@ -271,7 +292,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo const shouldStoreEditSession = await that.shouldContinueOnWithEditSession(); - let uri = workspaceUri ?? await that.continueOnPicker.pick(); + let uri = workspaceUri ?? await that.pickContinueEditSessionDestination(); if (uri === undefined) { return; } // Run the store action to get back a ref @@ -627,8 +648,162 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo return false; } + + //#region Continue Edit Session extension contribution point + + private registerContributedEditSessionOptions() { + continueEditSessionExtPoint.setHandler(extensions => { + const continueEditSessionOptions: ContinueEditSessionItem[] = []; + for (const extension of extensions) { + if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) { + continue; + } + if (!Array.isArray(extension.value)) { + continue; + } + for (const contribution of extension.value) { + const command = MenuRegistry.getCommand(contribution.command); + if (!command) { + return; + } + + const icon = command.icon; + const title = typeof command.title === 'string' ? command.title : command.title.value; + + continueEditSessionOptions.push(new ContinueEditSessionItem( + ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title, + command.id, + command.source, + ContextKeyExpr.deserialize(contribution.when) + )); + } + } + this.continueEditSessionOptions = continueEditSessionOptions; + }); + } + + private registerContinueInLocalFolderAction(): void { + const that = this; + this._register(registerAction2(class ContinueInLocalFolderAction extends Action2 { + constructor() { + super(openLocalFolderCommand); + } + + async run(accessor: ServicesAccessor): Promise { + const selection = await that.fileDialogService.showOpenDialog({ + title: localize('continueEditSession.openLocalFolder.title', 'Select a local folder to continue your edit session in'), + canSelectFolders: true, + canSelectMany: false, + canSelectFiles: false, + availableFileSystems: [Schemas.file] + }); + + return selection?.length !== 1 ? undefined : URI.from({ + scheme: that.productService.urlProtocol, + authority: Schemas.file, + path: selection[0].path + }); + } + })); + } + + private async pickContinueEditSessionDestination(): Promise { + const quickPick = this.quickInputService.createQuickPick(); + + const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER + ? this.contextService.getWorkspace().folders[0].name + : this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', '); + quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`); + quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working'); + quickPick.items = this.createPickItems(); + + const command = await new Promise((resolve, reject) => { + quickPick.onDidHide(() => resolve(undefined)); + + quickPick.onDidAccept((e) => { + const selection = quickPick.activeItems[0].command; + resolve(selection); + quickPick.hide(); + }); + + quickPick.show(); + }); + + quickPick.dispose(); + + if (command === undefined) { + return undefined; + } + + try { + const uri = await this.commandService.executeCommand(command); + + // Some continue on commands do not return a URI + // to support extensions which want to be in control + // of how the destination is opened + if (uri === undefined) { return 'noDestinationUri'; } + + return URI.isUri(uri) ? uri : undefined; + } catch (ex) { + return undefined; + } + } + + private createPickItems(): ContinueEditSessionItem[] { + const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when)); + + if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) { + items.push(new ContinueEditSessionItem( + '$(folder) ' + localize('continueEditSessionItem.openInLocalFolder.v2', 'Open in Local Folder'), + openLocalFolderCommand.id, + localize('continueEditSessionItem.builtin', 'Built-in') + )); + } + + return items.sort((item1, item2) => item1.label.localeCompare(item2.label)); + } } +class ContinueEditSessionItem implements IQuickPickItem { + constructor( + public readonly label: string, + public readonly command: string, + public readonly description?: string, + public readonly when?: ContextKeyExpression, + ) { } +} + +interface ICommand { + command: string; + group: string; + when: string; +} + +const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'continueEditSession', + jsonSchema: { + description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'), + type: 'array', + items: { + type: 'object', + properties: { + command: { + description: localize('continueEditSessionExtPoint.command', 'Identifier of the command to execute. The command must be declared in the \'commands\'-section and return a URI representing a different environment where the current edit session can be continued.'), + type: 'string' + }, + group: { + description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'), + type: 'string' + }, + when: { + description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'), + type: 'string' + } + }, + required: ['command'] + } + } +}); //#endregion From 3f2adbfe3e6d07c60bc4c61b4ff7bdcf1c451792 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Tue, 11 Oct 2022 00:23:42 -0700 Subject: [PATCH 469/599] Update language-configuration.json (#163182) --- extensions/cpp/language-configuration.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index 79ef8aec28b..0f365702269 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -13,8 +13,8 @@ { "open": "{", "close": "}" }, { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string", "comment"] }, - { "open": "\"", "close": "\"", "notIn": ["string"] } - { "open": "/*", "close": "*/", "notIn": ["string", "comment"] }, + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "/*", "close": "*/", "notIn": ["string", "comment"] } ], "surroundingPairs": [ ["{", "}"], From e8fe2d07d31f30698b9262dd5e1fcc59a85c6bb1 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 11 Oct 2022 11:11:54 +0200 Subject: [PATCH 470/599] Fixes #162999 (#163263) --- .../contrib/mergeEditor/browser/model/mergeEditorModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 0ba8f83e655..f386c1cb21e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -181,7 +181,7 @@ export class MergeEditorModel extends EditorModel { appendLinesToResult(baseLines, LineRange.fromLineNumbers(baseStartLineNumber, baseLines.length + 1)); - return resultLines.join('\n'); + return resultLines.join(this.resultTextModel.getEOL()); } public hasBaseRange(baseRange: ModifiedBaseRange): boolean { From 3594aec1d4b3cd0f904537782cb4682955194a83 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 11 Oct 2022 13:19:29 +0200 Subject: [PATCH 471/599] bring back switch output action (#163264) --- .../contrib/output/browser/output.contribution.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index edf6f945f10..85f81a2afde 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -114,6 +114,19 @@ class OutputContribution extends Disposable implements IWorkbenchContribution { } private registerSwitchOutputAction(): void { + this._register(registerAction2(class extends Action2 { + constructor() { + super({ + id: `workbench.output.action.switchBetweenOutputs`, + title: nls.localize('switchBetweenOutputs.label', "Switch Output"), + }); + } + async run(accessor: ServicesAccessor, channelId: string): Promise { + if (channelId) { + accessor.get(IOutputService).showChannel(channelId, true); + } + } + })); const switchOutputMenu = new MenuId('workbench.output.menu.switchOutput'); this._register(MenuRegistry.appendMenuItem(MenuId.ViewTitle, { submenu: switchOutputMenu, From bdd63955e5b50a74d1ac1241b9c4d454b6d45469 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 11 Oct 2022 15:38:03 +0200 Subject: [PATCH 472/599] fix an issue with sticky scroll failing to pick an outline group (#163293) --- .../editor/contrib/stickyScroll/browser/stickyScrollProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts index 7846d007c17..d93642d2d4d 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts @@ -225,7 +225,7 @@ class StickyOutlineElement { outlineElements = provider.children; } else { let tempID = ''; - let maxTotalSumOfRanges = 0; + let maxTotalSumOfRanges = -1; let optimalOutlineGroup = undefined; for (const [_key, outlineGroup] of outlineModel.children.entries()) { const totalSumRanges = StickyOutlineElement.findSumOfRangesOfGroup(outlineGroup); From 9b0ae4dd79e05597cefa4e411e144a21e2fc7ceb Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 11 Oct 2022 15:52:33 +0200 Subject: [PATCH 473/599] Push an undo stop before committing an inline suggestion (#163296) --- .../contrib/inlineCompletions/browser/inlineCompletionsModel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index 562960aa1ce..61595c2b880 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -512,6 +512,7 @@ export class InlineCompletionsSession extends BaseGhostTextWidgetModel { // otherwise command args might get disposed. const cache = this.cache.clearAndLeak(); + this.editor.pushUndoStop(); if (completion.snippetInfo) { this.editor.executeEdits( 'inlineSuggestion.accept', From 2149a31611e00bbc8a5e16715029a9c4581c0043 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 11 Oct 2022 16:25:07 +0200 Subject: [PATCH 474/599] Toggle word wrap state (if defined) also on the other side when opening a diff editor (#163297) Fixes #161412: Toggle word wrap state (if defined) also on the other side when opening a diff editor --- src/vs/editor/browser/editorBrowser.ts | 6 ++ .../editor/browser/widget/diffEditorWidget.ts | 5 + src/vs/monaco.d.ts | 5 + .../codeEditor/browser/toggleWordWrap.ts | 92 ++++++++++++++----- 4 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index d768689d23a..8acb399f7ce 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -1121,6 +1121,12 @@ export interface IDiffEditor extends editorCommon.IEditor { */ readonly onDidUpdateDiff: Event; + /** + * An event emitted when the diff model is changed (i.e. the diff editor shows new content). + * @event + */ + readonly onDidChangeModel: Event; + /** * Saves current view state of the editor in a serializable object. */ diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 9ca599671d4..74a24d46312 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -181,6 +181,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private readonly _onDidDispose: Emitter = this._register(new Emitter()); public readonly onDidDispose: Event = this._onDidDispose.event; + protected readonly _onDidChangeModel: Emitter = this._register(new Emitter()); + public readonly onDidChangeModel: Event = this._onDidChangeModel.event; + private readonly _onDidUpdateDiff: Emitter = this._register(new Emitter()); public readonly onDidUpdateDiff: Event = this._onDidUpdateDiff.event; @@ -830,6 +833,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } this._layoutOverviewViewport(); + + this._onDidChangeModel.fire(); } public getContainerDomNode(): HTMLElement { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5f5e30d1c3f..bd49c2c2cea 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5509,6 +5509,11 @@ declare namespace monaco.editor { * @event */ readonly onDidUpdateDiff: IEvent; + /** + * An event emitted when the diff model is changed (i.e. the diff editor shows new content). + * @event + */ + readonly onDidChangeModel: IEvent; /** * Saves current view state of the editor in a serializable object. */ diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 1348eb4557a..d2774c7642d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -6,11 +6,11 @@ import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { IActiveCodeEditor, ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution, registerDiffEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { IDiffEditorContribution, IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -93,30 +93,37 @@ class ToggleWordWrapAction extends EditorAction { writeTransientState(model, newState, codeEditorService); // if we are in a diff editor, update the other editor (if possible) - if (editor.getOption(EditorOption.inDiffEditor)) { - // this editor belongs to a diff editor - for (const diffEditor of codeEditorService.listDiffEditors()) { - const originalEditor = diffEditor.getOriginalEditor(); - const modifiedEditor = diffEditor.getModifiedEditor(); - if (originalEditor === editor) { - if (canToggleWordWrap(codeEditorService, modifiedEditor)) { - writeTransientState(modifiedEditor.getModel(), newState, codeEditorService); - diffEditor.updateOptions({}); - } - break; - } - if (modifiedEditor === editor) { - if (canToggleWordWrap(codeEditorService, originalEditor)) { - writeTransientState(originalEditor.getModel(), newState, codeEditorService); - diffEditor.updateOptions({}); - } - break; - } + const diffEditor = findDiffEditorContainingCodeEditor(editor, codeEditorService); + if (diffEditor) { + const originalEditor = diffEditor.getOriginalEditor(); + const modifiedEditor = diffEditor.getModifiedEditor(); + const otherEditor = (originalEditor === editor ? modifiedEditor : originalEditor); + if (canToggleWordWrap(codeEditorService, otherEditor)) { + writeTransientState(otherEditor.getModel(), newState, codeEditorService); + diffEditor.updateOptions({}); } } } } +/** + * If `editor` is the original or modified editor of a diff editor, it returns it. + * It returns null otherwise. + */ +function findDiffEditorContainingCodeEditor(editor: ICodeEditor, codeEditorService: ICodeEditorService): IDiffEditor | null { + if (!editor.getOption(EditorOption.inDiffEditor)) { + return null; + } + for (const diffEditor of codeEditorService.listDiffEditors()) { + const originalEditor = diffEditor.getOriginalEditor(); + const modifiedEditor = diffEditor.getModifiedEditor(); + if (originalEditor === editor || modifiedEditor === editor) { + return diffEditor; + } + } + return null; +} + class ToggleWordWrapController extends Disposable implements IEditorContribution { public static readonly ID = 'editor.contrib.toggleWordWrapController'; @@ -181,6 +188,45 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution } } +class DiffToggleWordWrapController extends Disposable implements IDiffEditorContribution { + + public static readonly ID = 'diffeditor.contrib.toggleWordWrapController'; + + constructor( + private readonly _diffEditor: IDiffEditor, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService + ) { + super(); + + this._register(this._diffEditor.onDidChangeModel(() => { + this._ensureSyncedWordWrapToggle(); + })); + } + + private _ensureSyncedWordWrapToggle(): void { + const originalEditor = this._diffEditor.getOriginalEditor(); + const modifiedEditor = this._diffEditor.getModifiedEditor(); + + if (!originalEditor.hasModel() || !modifiedEditor.hasModel()) { + return; + } + + const originalTransientState = readTransientState(originalEditor.getModel(), this._codeEditorService); + const modifiedTransientState = readTransientState(modifiedEditor.getModel(), this._codeEditorService); + + console.log(originalTransientState, modifiedTransientState); + + if (originalTransientState && !modifiedTransientState && canToggleWordWrap(this._codeEditorService, originalEditor)) { + writeTransientState(modifiedEditor.getModel(), originalTransientState, this._codeEditorService); + this._diffEditor.updateOptions({}); + } + if (!originalTransientState && modifiedTransientState && canToggleWordWrap(this._codeEditorService, modifiedEditor)) { + writeTransientState(originalEditor.getModel(), modifiedTransientState, this._codeEditorService); + this._diffEditor.updateOptions({}); + } + } +} + function canToggleWordWrap(codeEditorService: ICodeEditorService, editor: ICodeEditor | null): editor is IActiveCodeEditor { if (!editor) { return false; @@ -272,7 +318,7 @@ const workbenchRegistry = Registry.as(Extension workbenchRegistry.registerWorkbenchContribution(EditorWordWrapContextKeyTracker, LifecyclePhase.Ready); registerEditorContribution(ToggleWordWrapController.ID, ToggleWordWrapController); - +registerDiffEditorContribution(DiffToggleWordWrapController.ID, DiffToggleWordWrapController); registerEditorAction(ToggleWordWrapAction); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { From adefb9aae27c2a3ffbba2d6b3a70091f73fb3fba Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 11 Oct 2022 16:30:41 +0200 Subject: [PATCH 475/599] change the default log format (#163268) * change the default log format * also change in file log * fix compilation --- src/vs/platform/log/common/fileLog.ts | 4 ++-- src/vs/platform/log/node/spdlogLog.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/log/common/fileLog.ts b/src/vs/platform/log/common/fileLog.ts index 0be7b474679..dbb5c57cc98 100644 --- a/src/vs/platform/log/common/fileLog.ts +++ b/src/vs/platform/log/common/fileLog.ts @@ -21,7 +21,7 @@ export class FileLogger extends AbstractLogger implements ILogger { private backupIndex: number = 1; constructor( - private readonly name: string, + name: string, private readonly resource: URI, level: LogLevel, private readonly donotUseFormatters: boolean, @@ -101,7 +101,7 @@ export class FileLogger extends AbstractLogger implements ILogger { if (this.donotUseFormatters) { content += message; } else { - content += `[${this.getCurrentTimestamp()}] [${this.name}] [${this.stringifyLogLevel(level)}] ${message}\n`; + content += `${this.getCurrentTimestamp()} [${this.stringifyLogLevel(level)}] ${message}\n`; } await this.fileService.writeFile(this.resource, VSBuffer.fromString(content)); }); diff --git a/src/vs/platform/log/node/spdlogLog.ts b/src/vs/platform/log/node/spdlogLog.ts index af7a576df1c..b00a30a3dbf 100644 --- a/src/vs/platform/log/node/spdlogLog.ts +++ b/src/vs/platform/log/node/spdlogLog.ts @@ -15,6 +15,8 @@ async function createSpdLogLogger(name: string, logfilePath: string, filesize: n const logger = await _spdlog.createAsyncRotatingLogger(name, logfilePath, filesize, filecount); if (donotUseFormatters) { logger.clearFormatters(); + } else { + logger.setPattern('%Y-%m-%d %H:%M:%S.%e [%l] %v'); } return logger; } catch (e) { From f232fdac984e22fd38d711e1ac096be6b6562749 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 11 Oct 2022 17:00:17 +0200 Subject: [PATCH 476/599] Fixes #162111 (#163300) --- .../mergeEditor/browser/commands/commands.ts | 48 ++++++++++++++----- .../browser/mergeEditor.contribution.ts | 12 +++-- .../mergeEditor/browser/view/mergeEditor.ts | 15 +++++- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 4ab7188c7eb..0f8742e3189 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -261,12 +261,11 @@ export class ShowHideBase extends Action2 { menu: [ { id: MenuId.EditorTitle, - when: ctxIsMergeEditor, + when: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorLayout.isEqualTo('columns')), group: '2_merge', order: 9, }, - ], - precondition: ctxIsMergeEditor, + ] }); } @@ -278,31 +277,58 @@ export class ShowHideBase extends Action2 { } } -export class ShowHideAtTopBase extends Action2 { +export class ShowHideTopBase extends Action2 { constructor() { super({ - id: 'merge.showBaseAtTop', + id: 'merge.showBaseTop', title: { - value: localize('layout.showBaseAtTop', 'Show Base At Top'), - original: 'Show Base At Top', + value: localize('layout.showBaseTop', 'Show Base Top'), + original: 'Show Base Top', }, - toggled: ctxMergeEditorShowBaseAtTop.isEqualTo(true), + toggled: ContextKeyExpr.and(ctxMergeEditorShowBase, ctxMergeEditorShowBaseAtTop), menu: [ { id: MenuId.EditorTitle, - when: ctxIsMergeEditor, + when: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorLayout.isEqualTo('mixed')), group: '2_merge', order: 10, }, ], - precondition: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorShowBase, ctxMergeEditorLayout.isEqualTo('mixed')), }); } run(accessor: ServicesAccessor): void { const { activeEditorPane } = accessor.get(IEditorService); if (activeEditorPane instanceof MergeEditor) { - activeEditorPane.toggleShowBaseAtTop(); + activeEditorPane.toggleShowBaseTop(); + } + } +} + +export class ShowHideCenterBase extends Action2 { + constructor() { + super({ + id: 'merge.showBaseCenter', + title: { + value: localize('layout.showBaseCenter', 'Show Base Center'), + original: 'Show Base Center', + }, + toggled: ContextKeyExpr.and(ctxMergeEditorShowBase, ctxMergeEditorShowBaseAtTop.negate()), + menu: [ + { + id: MenuId.EditorTitle, + when: ContextKeyExpr.and(ctxIsMergeEditor, ctxMergeEditorLayout.isEqualTo('mixed')), + group: '2_merge', + order: 11, + }, + ], + }); + } + + run(accessor: ServicesAccessor): void { + const { activeEditorPane } = accessor.get(IEditorService); + if (activeEditorPane instanceof MergeEditor) { + activeEditorPane.toggleShowBaseCenter(); } } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index 4e3de4815a6..eb90cc8b867 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -11,7 +11,12 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; -import { AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideAtTopBase, ShowHideBase, ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; +import { + AcceptAllInput1, AcceptAllInput2, AcceptMerge, CompareInput1WithBaseCommand, + CompareInput2WithBaseCommand, GoToNextUnhandledConflict, GoToPreviousUnhandledConflict, OpenBaseFile, OpenMergeEditor, + OpenResultResource, ResetToBaseAndAutoMergeCommand, SetColumnLayout, SetMixedLayout, ShowHideTopBase, ShowHideCenterBase, ShowHideBase, + ShowNonConflictingChanges, ToggleActiveConflictInput1, ToggleActiveConflictInput2 +} from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; import { MergeEditorCopyContentsToJSON, MergeEditorLoadContentsFromFolder, MergeEditorSaveContentsToFolder } from 'vs/workbench/contrib/mergeEditor/browser/commands/devCommands'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor, MergeEditorOpenHandlerContribution, MergeEditorResolverContribution } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -51,11 +56,12 @@ Registry.as(Extensions.Configuration).registerConfigurat registerAction2(OpenResultResource); registerAction2(SetMixedLayout); registerAction2(SetColumnLayout); -registerAction2(ShowHideBase); -registerAction2(ShowHideAtTopBase); registerAction2(OpenMergeEditor); registerAction2(OpenBaseFile); registerAction2(ShowNonConflictingChanges); +registerAction2(ShowHideBase); +registerAction2(ShowHideTopBase); +registerAction2(ShowHideCenterBase); registerAction2(GoToNextUnhandledConflict); registerAction2(GoToPreviousUnhandledConflict); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 1fb8ca23bcb..bd4acc11980 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -607,10 +607,21 @@ export class MergeEditor extends AbstractTextEditor { }); } - public toggleShowBaseAtTop(): void { + public toggleShowBaseTop(): void { + const showBaseTop = this._layoutMode.value.showBase && this._layoutMode.value.showBaseAtTop; this.setLayout({ ...this._layoutMode.value, - showBaseAtTop: !this._layoutMode.value.showBaseAtTop, + showBaseAtTop: true, + showBase: !showBaseTop, + }); + } + + public toggleShowBaseCenter(): void { + const showBaseCenter = this._layoutMode.value.showBase && !this._layoutMode.value.showBaseAtTop; + this.setLayout({ + ...this._layoutMode.value, + showBaseAtTop: false, + showBase: !showBaseCenter, }); } From 597d485d3ffbaa0ad2deed2eac0a9a2013453875 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 11 Oct 2022 17:05:02 +0200 Subject: [PATCH 477/599] Exclude code lens contributions from result merge editor (#163301) --- .../browser/view/editors/resultCodeEditorView.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index a43d5ca319e..937564bb6e7 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -9,7 +9,9 @@ import { CompareResult } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; import { toDisposable } from 'vs/base/common/lifecycle'; import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; +import { IEditorContributionDescription, EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; +import { CodeLensContribution } from 'vs/editor/contrib/codelens/browser/codelensController'; import { localize } from 'vs/nls'; import { MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -202,4 +204,8 @@ export class ResultCodeEditorView extends CodeEditorView { } return result; }); + + protected override getEditorContributions(): IEditorContributionDescription[] | undefined { + return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); + } } From 4b48c2dac2a01520ef865aae4471b2055da69a7b Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 11 Oct 2022 17:06:54 +0200 Subject: [PATCH 478/599] Add support for transparency in `editorOverviewRuler.background` (#163302) Fixes #159843: Add support for transparency in `editorOverviewRuler.background` --- src/vs/base/common/color.ts | 10 +++++ .../overviewRuler/decorationsOverviewRuler.ts | 40 +++++++++++-------- .../editor/common/core/editorColorRegistry.ts | 2 +- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/vs/base/common/color.ts b/src/vs/base/common/color.ts index dcdc00dcee3..750cfe7dc71 100644 --- a/src/vs/base/common/color.ts +++ b/src/vs/base/common/color.ts @@ -259,6 +259,16 @@ export class Color { return Color.Format.CSS.parseHex(hex) || Color.red; } + static equals(a: Color | null, b: Color | null): boolean { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return a.equals(b); + } + readonly rgba: RGBA; private _hsla?: HSLA; get hsla(): HSLA { diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index 5c376b3e385..86db61f97e1 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -31,7 +31,7 @@ class Settings { public readonly cursorColor: string | null; public readonly themeType: 'light' | 'dark' | 'hcLight' | 'hcDark'; - public readonly backgroundColor: string | null; + public readonly backgroundColor: Color | null; public readonly top: number; public readonly right: number; @@ -64,18 +64,13 @@ class Settings { const minimapSide = minimapOpts.side; const themeColor = theme.getColor(editorOverviewRulerBackground); const defaultBackground = TokenizationRegistry.getDefaultBackground(); - let backgroundColor: Color | null = null; - if (themeColor !== undefined) { - backgroundColor = themeColor; - } else if (minimapEnabled) { - backgroundColor = defaultBackground; - } - - if (backgroundColor === null || minimapSide === 'left') { - this.backgroundColor = null; + if (themeColor) { + this.backgroundColor = themeColor; + } else if (minimapEnabled && minimapSide === 'right') { + this.backgroundColor = defaultBackground; } else { - this.backgroundColor = Color.Format.CSS.formatHex(backgroundColor); + this.backgroundColor = null; } const layoutInfo = options.get(EditorOption.layoutInfo); @@ -195,7 +190,7 @@ class Settings { && this.hideCursor === other.hideCursor && this.cursorColor === other.cursorColor && this.themeType === other.themeType - && this.backgroundColor === other.backgroundColor + && Color.equals(this.backgroundColor, other.backgroundColor) && this.top === other.top && this.right === other.right && this.domWidth === other.domWidth @@ -320,9 +315,10 @@ export class DecorationsOverviewRuler extends ViewPart { } private _render(): void { + const backgroundColor = this._settings.backgroundColor; if (this._settings.overviewRulerLanes === 0) { // overview ruler is off - this._domNode.setBackgroundColor(this._settings.backgroundColor ? this._settings.backgroundColor : ''); + this._domNode.setBackgroundColor(backgroundColor ? Color.Format.CSS.formatHexA(backgroundColor) : ''); this._domNode.setDisplay('none'); return; } @@ -339,11 +335,21 @@ export class DecorationsOverviewRuler extends ViewPart { const halfMinDecorationHeight = (minDecorationHeight / 2) | 0; const canvasCtx = this._domNode.domNode.getContext('2d')!; - if (this._settings.backgroundColor === null) { - canvasCtx.clearRect(0, 0, canvasWidth, canvasHeight); + if (backgroundColor) { + if (backgroundColor.isOpaque()) { + // We have a background color which is opaque, we can just paint the entire surface with it + canvasCtx.fillStyle = Color.Format.CSS.formatHexA(backgroundColor); + canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight); + } else { + // We have a background color which is transparent, we need to first clear the surface and + // then fill it + canvasCtx.clearRect(0, 0, canvasWidth, canvasHeight); + canvasCtx.fillStyle = Color.Format.CSS.formatHexA(backgroundColor); + canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight); + } } else { - canvasCtx.fillStyle = this._settings.backgroundColor; - canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight); + // We don't have a background color + canvasCtx.clearRect(0, 0, canvasWidth, canvasHeight); } const x = this._settings.x; diff --git a/src/vs/editor/common/core/editorColorRegistry.ts b/src/vs/editor/common/core/editorColorRegistry.ts index 5460cb16e56..17c865df766 100644 --- a/src/vs/editor/common/core/editorColorRegistry.ts +++ b/src/vs/editor/common/core/editorColorRegistry.ts @@ -37,7 +37,7 @@ export const editorBracketMatchBackground = registerColor('editorBracketMatch.ba export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes')); export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hcDark: '#7f7f7f4d', hcLight: '#666666' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.')); -export const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler. Only used when the minimap is enabled and placed on the right side of the editor.')); +export const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler.')); export const editorGutter = registerColor('editorGutter.background', { dark: editorBackground, light: editorBackground, hcDark: editorBackground, hcLight: editorBackground }, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.')); From b42f25b50bd16602c73c9dd81bb9e2251b191a62 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 11 Oct 2022 08:30:43 -0700 Subject: [PATCH 479/599] address pr comments --- .../cli/cli-compile-and-publish.yml | 6 ++--- build/azure-pipelines/cli/cli-darwin-sign.yml | 1 + .../cli/install-rust-posix.yml | 4 ++- .../cli/install-rust-win32.yml | 26 ++++++++++--------- .../azure-pipelines/linux/cli-build-linux.yml | 1 + build/azure-pipelines/product-build-pr.yml | 5 +--- .../win32/product-build-win32.yml | 1 + 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml index a97446c274b..e635f51df8c 100644 --- a/build/azure-pipelines/cli/cli-compile-and-publish.yml +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -24,9 +24,9 @@ steps: - ${{ if or(contains(parameters.VSCODE_CLI_TARGET, '-windows-'), contains(parameters.VSCODE_CLI_TARGET, '-darwin')) }}: - task: ArchiveFiles@2 inputs: - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-')}}: + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}: rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel.exe - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin')}}: + ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin') }}: rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel includeRootFolder: false archiveType: zip @@ -36,7 +36,7 @@ steps: artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }} displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact - - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-linux-') }}: + - ${{ else }}: - task: ArchiveFiles@2 inputs: rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel diff --git a/build/azure-pipelines/cli/cli-darwin-sign.yml b/build/azure-pipelines/cli/cli-darwin-sign.yml index 30d2bc3b566..b8f9e965133 100644 --- a/build/azure-pipelines/cli/cli-darwin-sign.yml +++ b/build/azure-pipelines/cli/cli-darwin-sign.yml @@ -30,6 +30,7 @@ steps: - ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}: - script: | + set -e ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//") mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/$ASSET_ID.zip echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" diff --git a/build/azure-pipelines/cli/install-rust-posix.yml b/build/azure-pipelines/cli/install-rust-posix.yml index 7dddfb5eb9b..e32a8eedadf 100644 --- a/build/azure-pipelines/cli/install-rust-posix.yml +++ b/build/azure-pipelines/cli/install-rust-posix.yml @@ -17,7 +17,8 @@ steps: RUSTUP_TOOLCHAIN: ${{ parameters.channel }} displayName: "Install Rust" - - bash: | + - script: | + set -e rustup default $RUSTUP_TOOLCHAIN rustup update $RUSTUP_TOOLCHAIN env: @@ -29,6 +30,7 @@ steps: displayName: "Adding Rust target '${{ target }}'" - script: | + set -e rustc --version cargo --version rustup --version diff --git a/build/azure-pipelines/cli/install-rust-win32.yml b/build/azure-pipelines/cli/install-rust-win32.yml index 0b345892ab2..fc23f40f1b6 100644 --- a/build/azure-pipelines/cli/install-rust-win32.yml +++ b/build/azure-pipelines/cli/install-rust-win32.yml @@ -9,18 +9,19 @@ parameters: # Todo: use 1ES pipeline once extension is installed in ADO steps: - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --profile minimal --default-toolchain %RUSTUP_TOOLCHAIN% --default-host x86_64-pc-windows-msvc - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { curl -sSf -o rustup-init.exe https://win.rustup.rs } + exec { rustup-init.exe -y --profile minimal --default-toolchain %RUSTUP_TOOLCHAIN% --default-host x86_64-pc-windows-msvc } + echo "##vso[task.prependpath]$env:USERPROFILE\.cargo\bin" env: RUSTUP_TOOLCHAIN: ${{ parameters.channel }} displayName: "Install Rust" - - bash: | - rustup default $RUSTUP_TOOLCHAIN - rustup update $RUSTUP_TOOLCHAIN + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { rustup default $RUSTUP_TOOLCHAIN } + exec { rustup update $RUSTUP_TOOLCHAIN } env: RUSTUP_TOOLCHAIN: ${{ parameters.channel }} displayName: "Set Rust version" @@ -29,8 +30,9 @@ steps: - script: rustup target add ${{ target }} displayName: "Adding Rust target '${{ target }}'" - - script: | - rustc --version - cargo --version - rustup --version + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + exec { rustc --version } + exec { cargo --version } + exec { rustup --version } displayName: "Check Rust versions" diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml index 2f6db518991..0bc62e28dad 100644 --- a/build/azure-pipelines/linux/cli-build-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -20,6 +20,7 @@ parameters: steps: # inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile - bash: | + set -e sudo apt-get update sudo apt-get install -yq build-essential cmake curl file git graphviz musl-dev musl-tools linux-libc-dev pkgconf unzip xutils-dev sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" || echo "link exists" diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index 9993d569d78..0ffcdcc00ca 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -102,10 +102,7 @@ jobs: - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - job: LinuxCLI displayName: Linux (CLI) - pool: - name: vscode-1es-vscode-linux-20.04 - demands: - - ImageVersionOverride -equals 40.0.0 + pool: vscode-1es-vscode-linux-20.04 timeoutInMinutes: 30 steps: - template: cli/test.yml diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 0c0bcf8b40b..7145cd689c1 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -196,6 +196,7 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" $ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName Expand-Archive -Path $ArtifactName -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" From 391a6825bdb698049a702b0e520b1ed54990a4b9 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 11 Oct 2022 17:42:03 +0200 Subject: [PATCH 480/599] Fixes #161993 (#163303) --- .../mergeEditor/browser/view/conflictActions.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index e382534f4fe..5e7cdcc2585 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -43,7 +43,6 @@ export class ConflictActionsFactory extends Disposable { } private _updateLensStyle(): void { - const { codeLensHeight, fontSize } = this._getLayoutInfo(); const fontFamily = this._editor.getOption(EditorOption.codeLensFontFamily); const editorFontInfo = this._editor.getOption(EditorOption.fontInfo); @@ -172,7 +171,9 @@ export class ConflictActionsFactory extends Disposable { return result; }); - return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, 16, this._styleClassName, items); + const layoutInfo = this._getLayoutInfo(); + + return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, layoutInfo.codeLensHeight + 2, this._styleClassName, items); } addContentWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IDisposable { @@ -259,7 +260,10 @@ export class ConflictActionsFactory extends Disposable { } return result; }); - return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, 16, this._styleClassName, items); + + const layoutInfo = this._getLayoutInfo(); + + return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, layoutInfo.codeLensHeight + 2, this._styleClassName, items); } } From 89f8e8b4de278f959196cc84a41298bdebdec106 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 11 Oct 2022 17:52:57 +0200 Subject: [PATCH 481/599] pause/resume suggest widget events when doing splice and select/focus (#163307) fixes https://github.com/microsoft/vscode/issues/163284 --- .../contrib/suggest/browser/suggestWidget.ts | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 08cf6fe22a0..f2df600f279 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -10,7 +10,7 @@ import { IListEvent, IListGestureEvent, IListMouseEvent } from 'vs/base/browser/ import { List } from 'vs/base/browser/ui/list/listWidget'; import { CancelablePromise, createCancelablePromise, disposableTimeout, TimeoutTimer } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; +import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; import * as strings from 'vs/base/common/strings'; @@ -130,8 +130,8 @@ export class SuggestWidget implements IDisposable { private readonly _disposables = new DisposableStore(); - private readonly _onDidSelect = new Emitter(); - private readonly _onDidFocus = new Emitter(); + private readonly _onDidSelect = new PauseableEmitter(); + private readonly _onDidFocus = new PauseableEmitter(); private readonly _onDidHide = new Emitter(); private readonly _onDidShow = new Emitter(); @@ -540,11 +540,23 @@ export class SuggestWidget implements IDisposable { } this._focusedItem = undefined; - this._list.splice(0, this._list.length, this._completionModel.items); - this._setState(isFrozen ? State.Frozen : State.Open); - if (selectionIndex >= 0) { - this._list.reveal(selectionIndex, 0); - this._list.setFocus([selectionIndex]); + + // calling list.splice triggers focus event which this widget forwards. That can lead to + // suggestions being cancelled and the widget being cleared (and hidden). All this happens + // before revealing and focusing is done which means revealing and focusing will fail when + // they get run. + this._onDidFocus.pause(); + this._onDidSelect.pause(); + try { + this._list.splice(0, this._list.length, this._completionModel.items); + this._setState(isFrozen ? State.Frozen : State.Open); + if (selectionIndex >= 0) { + this._list.reveal(selectionIndex, 0); + this._list.setFocus([selectionIndex]); + } + } finally { + this._onDidFocus.resume(); + this._onDidSelect.resume(); } this._layout(this.element.size); From 63351a794f00b0db351c906d8bd6c3cd770b393c Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Tue, 11 Oct 2022 09:18:53 -0700 Subject: [PATCH 482/599] Search Focus Cleanup (#162903) * aligned replace and remove in search focus * always refocus replace --- .../contrib/search/browser/searchActions.ts | 342 ++++++++---------- .../search/test/browser/mockSearchTree.ts | 6 + .../search/test/browser/searchActions.test.ts | 59 ++- 3 files changed, 184 insertions(+), 223 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index b93bb92007c..6d2be5c0d26 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -142,6 +142,7 @@ export interface IFindInFilesArgs { useExcludeSettingsAndIgnoreFiles?: boolean; onlyOpenEditors?: boolean; } + export const FindInFilesCommand: ICommandHandler = (accessor, args: IFindInFilesArgs = {}) => { const searchConfig = accessor.get(IConfigurationService).getValue().search; const mode = searchConfig.mode; @@ -341,67 +342,11 @@ export async function findOrReplaceInFiles(accessor: ServicesAccessor, expandSea }); } -export abstract class AbstractSearchAndReplaceAction extends Action { - - /** - * Returns element to focus after removing the given element - */ - getElementToFocusAfterRemoved(viewer: WorkbenchCompressibleObjectTree, elementToRemove: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { - const elementToFocus = this.getNextElementAfterRemoved(viewer, elementToRemove); - return elementToFocus || this.getPreviousElementAfterRemoved(viewer, elementToRemove, isTreeViewVisible); - } - - getNextElementAfterRemoved(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch): RenderableMatch { - const navigator: ITreeNavigator = viewer.navigate(element); - if (element instanceof FolderMatch) { - while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { } - } else if (element instanceof FileMatch) { - while (!!navigator.next() && !(navigator.current() instanceof FileMatch)) { } - } else { - while (navigator.next() && !(navigator.current() instanceof Match)) { - viewer.expand(navigator.current()); - } - } - return navigator.current(); - } - - getPreviousElementAfterRemoved(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch, isTreeViewVisible: boolean): RenderableMatch { - const navigator: ITreeNavigator = viewer.navigate(element); - let previousElement = navigator.previous(); - // Hence take the previous element. - const parent = getVisibleParent(element, isTreeViewVisible); - if (parent === previousElement) { - previousElement = navigator.previous(); - } - - if (parent instanceof FileMatch && getVisibleParent(parent, isTreeViewVisible) === previousElement) { - previousElement = navigator.previous(); - } - - // If the previous element is a File or Folder, expand it and go to its last child. - // Spell out the two cases, would be too easy to create an infinite loop, like by adding another level... - if (element instanceof Match && previousElement && previousElement instanceof FolderMatch) { - navigator.next(); - viewer.expand(previousElement); - previousElement = navigator.previous(); - } - - if (element instanceof Match && previousElement && previousElement instanceof FileMatch) { - navigator.next(); - viewer.expand(previousElement); - previousElement = navigator.previous(); - } - - return previousElement; - } -} class ReplaceActionRunner { constructor( private viewer: WorkbenchCompressibleObjectTree, private viewlet: SearchView | undefined, - private getElementToFocusAfterRemoved: (viewer: WorkbenchCompressibleObjectTree, lastElementToBeRemoved: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, - private getPreviousElementAfterRemoved: (viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch, isTreeViewVisible: boolean) => RenderableMatch, // Services @IReplaceService private readonly replaceService: IReplaceService, @IEditorService private readonly editorService: IEditorService, @@ -410,99 +355,55 @@ class ReplaceActionRunner { @IViewsService private readonly viewsService: IViewsService ) { } - async performReplace(element: FolderMatch | FileMatch | Match): Promise { + async performReplace(element: RenderableMatch): Promise { // since multiple elements can be selected, we need to check the type of the FolderMatch/FileMatch/Match before we perform the replace. const opInfo = getElementsToOperateOnInfo(this.viewer, element, this.configurationService.getValue('search')); const elementsToReplace = opInfo.elements; + let focusElement = this.viewer.getFocus()[0]; - const searchView = getSearchView(this.viewsService); - const searchResult = searchView?.searchResult; + if (!focusElement || (focusElement && !arrayContainsElementOrParent(focusElement, elementsToReplace)) || (focusElement instanceof SearchResult)) { + focusElement = element; + } + + if (elementsToReplace.length === 0) { + return; + } + let nextFocusElement; + if (focusElement) { + nextFocusElement = getElementToFocusAfterRemoved(this.viewer, focusElement, elementsToReplace); + } + + const searchResult = getSearchView(this.viewsService)?.searchResult; if (searchResult) { searchResult.batchReplace(elementsToReplace); } - const currentBottomFocusElement = elementsToReplace[elementsToReplace.length - 1]; - - if (currentBottomFocusElement instanceof Match) { - const elementToFocus = this.getElementToFocusAfterReplace(currentBottomFocusElement); - - if (elementToFocus) { - this.viewer.setFocus([elementToFocus], getSelectionKeyboardEvent()); - this.viewer.setSelection([elementToFocus], getSelectionKeyboardEvent()); + if (focusElement) { + if (!nextFocusElement) { + nextFocusElement = getLastNodeFromSameType(this.viewer, focusElement); } - const elementToShowReplacePreview = this.getElementToShowReplacePreview(elementToFocus, currentBottomFocusElement, searchView?.isTreeLayoutViewVisible ?? false); - - this.viewer.domFocus(); - - const useReplacePreview = this.configurationService.getValue().search.useReplacePreview; - if (!useReplacePreview || !elementToShowReplacePreview || this.hasToOpenFile(currentBottomFocusElement)) { - this.viewlet?.open(currentBottomFocusElement, true); - } else { - this.replaceService.openReplacePreview(elementToShowReplacePreview, true); - } - return; - } else { - const nextFocusElement = this.getElementToFocusAfterRemoved(this.viewer, currentBottomFocusElement, searchView?.isTreeLayoutViewVisible ?? false); if (nextFocusElement) { + this.viewer.reveal(nextFocusElement); this.viewer.setFocus([nextFocusElement], getSelectionKeyboardEvent()); this.viewer.setSelection([nextFocusElement], getSelectionKeyboardEvent()); - } - this.viewer.domFocus(); - - if (element instanceof FileMatch) { - this.viewlet?.open(element, true); - } - - return; - } - } - - private getElementToFocusAfterReplace(currElement: Match): RenderableMatch { - const navigator: ITreeNavigator = this.viewer.navigate(); - let fileMatched = false; - let elementToFocus: RenderableMatch | null = null; - do { - elementToFocus = navigator.current(); - if (elementToFocus instanceof Match) { - if (elementToFocus.parent().id() === currElement.parent().id()) { - fileMatched = true; - if (currElement.range().getStartPosition().isBeforeOrEqual(elementToFocus.range().getStartPosition())) { - // Closest next match in the same file - break; + if (nextFocusElement instanceof Match) { + const useReplacePreview = this.configurationService.getValue().search.useReplacePreview; + if (!useReplacePreview || this.hasToOpenFile(nextFocusElement)) { + this.viewlet?.open(nextFocusElement, true); + } else { + this.replaceService.openReplacePreview(nextFocusElement, true); } - } else if (fileMatched) { - // First match in the next file (if expanded) - break; - } - } else if (fileMatched) { - if (this.viewer.isCollapsed(elementToFocus)) { - // Next file match (if collapsed) - break; + } else if (nextFocusElement instanceof FileMatch) { + this.viewlet?.open(nextFocusElement, true); } } - } while (!!navigator.next()); - return elementToFocus!; - } - private getElementToShowReplacePreview(elementToFocus: RenderableMatch, currBottomElem: RenderableMatch, isTreeViewVisible: boolean): Match | null { - if (this.hasSameParent(elementToFocus, currBottomElem)) { - return elementToFocus; } - const previousElement = this.getPreviousElementAfterRemoved(this.viewer, elementToFocus, isTreeViewVisible); - if (this.hasSameParent(previousElement, currBottomElem)) { - return previousElement; - } - return null; - } - private hasSameParent(element: RenderableMatch, currBottomElem: RenderableMatch): boolean { - if (!(currBottomElem instanceof Match)) { - return false; - } - return element && element instanceof Match && this.uriIdentityService.extUri.isEqual(element.parent().resource, currBottomElem.parent().resource); + this.viewer.domFocus(); } private hasToOpenFile(currBottomElem: RenderableMatch): boolean { @@ -518,7 +419,7 @@ class ReplaceActionRunner { } } -export class RemoveAction extends AbstractSearchAndReplaceAction { +export class RemoveAction extends Action { static readonly LABEL = nls.localize('RemoveAction.label', "Dismiss"); @@ -535,75 +436,45 @@ export class RemoveAction extends AbstractSearchAndReplaceAction { override async run(): Promise { const opInfo = getElementsToOperateOnInfo(this.viewer, this.element, this.configurationService.getValue('search')); const elementsToRemove = opInfo.elements; - const searchView = getSearchView(this.viewsService); + let focusElement = this.viewer.getFocus()[0]; + if (elementsToRemove.length === 0) { return; } - if (opInfo.mustReselect) { - for (const currentElement of elementsToRemove) { - const nextFocusElement = !currentElement || currentElement instanceof SearchResult || arrayContainsElementOrParent(currentElement, elementsToRemove) ? - this.getElementToFocusAfterRemoved(this.viewer, currentElement, searchView?.isTreeLayoutViewVisible ?? false) : - null; - if (nextFocusElement && !arrayContainsElementOrParent(nextFocusElement, elementsToRemove)) { - this.viewer.reveal(nextFocusElement); - this.viewer.setFocus([nextFocusElement], getSelectionKeyboardEvent()); - this.viewer.setSelection([nextFocusElement], getSelectionKeyboardEvent()); - break; - } - } + if (!focusElement || (focusElement instanceof SearchResult)) { + focusElement = this.element; } - const searchResult = searchView?.searchResult; + let nextFocusElement; + if (opInfo.mustReselect && focusElement) { + nextFocusElement = getElementToFocusAfterRemoved(this.viewer, focusElement, elementsToRemove); + } + + const searchResult = getSearchView(this.viewsService)?.searchResult; if (searchResult) { searchResult.batchRemove(elementsToRemove); } + if (opInfo.mustReselect && focusElement) { + if (!nextFocusElement) { + nextFocusElement = getLastNodeFromSameType(this.viewer, focusElement); + } + + if (nextFocusElement && !arrayContainsElementOrParent(nextFocusElement, elementsToRemove)) { + this.viewer.reveal(nextFocusElement); + this.viewer.setFocus([nextFocusElement], getSelectionKeyboardEvent()); + this.viewer.setSelection([nextFocusElement], getSelectionKeyboardEvent()); + } + } + this.viewer.domFocus(); return; } } - -export class ReplaceAllAction extends AbstractSearchAndReplaceAction { - - static readonly LABEL = nls.localize('file.replaceAll.label', "Replace All"); - private replaceRunner: ReplaceActionRunner; - constructor( - viewlet: SearchView, - private fileMatch: FileMatch, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IKeybindingService keyBindingService: IKeybindingService, - ) { - super(Constants.ReplaceAllInFileActionId, appendKeyBindingLabel(ReplaceAllAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceAllInFileActionId), keyBindingService), ThemeIcon.asClassName(searchReplaceAllIcon)); - this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewlet.getControl(), viewlet, this.getElementToFocusAfterRemoved, this.getPreviousElementAfterRemoved); - } - - override async run(): Promise { - return this.replaceRunner.performReplace(this.fileMatch); - } -} - -export class ReplaceAllInFolderAction extends AbstractSearchAndReplaceAction { - - static readonly LABEL = nls.localize('file.replaceAll.label', "Replace All"); - private replaceRunner: ReplaceActionRunner; - - constructor(viewer: WorkbenchCompressibleObjectTree, private folderMatch: FolderMatch, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IKeybindingService keyBindingService: IKeybindingService - ) { - super(Constants.ReplaceAllInFolderActionId, appendKeyBindingLabel(ReplaceAllInFolderAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceAllInFolderActionId), keyBindingService), ThemeIcon.asClassName(searchReplaceAllIcon)); - this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewer, undefined, this.getElementToFocusAfterRemoved, this.getPreviousElementAfterRemoved); - } - - override run(): Promise { - return this.replaceRunner.performReplace(this.folderMatch); - } -} - -export class ReplaceAction extends AbstractSearchAndReplaceAction { +export class ReplaceAction extends Action { static readonly LABEL = nls.localize('match.replace.label', "Replace"); @@ -615,7 +486,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { @IKeybindingService keyBindingService: IKeybindingService, ) { super(Constants.ReplaceActionId, appendKeyBindingLabel(ReplaceAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceActionId), keyBindingService), ThemeIcon.asClassName(searchReplaceIcon)); - this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewer, viewlet, this.getElementToFocusAfterRemoved, this.getPreviousElementAfterRemoved); + this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewer, viewlet); } override async run(): Promise { @@ -623,6 +494,43 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } } +export class ReplaceAllAction extends Action { + + static readonly LABEL = nls.localize('file.replaceAll.label', "Replace All"); + private replaceRunner: ReplaceActionRunner; + constructor( + viewlet: SearchView, + private fileMatch: FileMatch, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IKeybindingService keyBindingService: IKeybindingService, + ) { + super(Constants.ReplaceAllInFileActionId, appendKeyBindingLabel(ReplaceAllAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceAllInFileActionId), keyBindingService), ThemeIcon.asClassName(searchReplaceAllIcon)); + this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewlet.getControl(), viewlet); + } + + override async run(): Promise { + return this.replaceRunner.performReplace(this.fileMatch); + } +} + +export class ReplaceAllInFolderAction extends Action { + + static readonly LABEL = nls.localize('file.replaceAll.label', "Replace All"); + private replaceRunner: ReplaceActionRunner; + + constructor(viewer: WorkbenchCompressibleObjectTree, private folderMatch: FolderMatch, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IKeybindingService keyBindingService: IKeybindingService + ) { + super(Constants.ReplaceAllInFolderActionId, appendKeyBindingLabel(ReplaceAllInFolderAction.LABEL, keyBindingService.lookupKeybinding(Constants.ReplaceAllInFolderActionId), keyBindingService), ThemeIcon.asClassName(searchReplaceAllIcon)); + this.replaceRunner = this.instantiationService.createInstance(ReplaceActionRunner, viewer, undefined); + } + + override run(): Promise { + return this.replaceRunner.performReplace(this.folderMatch); + } +} + export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatchWithResource | undefined) => { if (!fileMatch) { const selection = getSelectedRow(accessor); @@ -788,6 +696,70 @@ function getElementsToOperateOnInfo(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch, elementsToRemove: RenderableMatch[]): RenderableMatch | undefined { + const navigator: ITreeNavigator = viewer.navigate(element); + if (element instanceof FolderMatch) { + while (!!navigator.next() && (!(navigator.current() instanceof FolderMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) { } + } else if (element instanceof FileMatch) { + while (!!navigator.next() && (!(navigator.current() instanceof FileMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) { + viewer.expand(navigator.current()); + } + } else { + while (navigator.next() && (!(navigator.current() instanceof Match) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) { + viewer.expand(navigator.current()); + } + } + return navigator.current(); +} + +/*** + * Finds the last element in the tree with the same type as `element` + */ +export function getLastNodeFromSameType(viewer: WorkbenchCompressibleObjectTree, element: RenderableMatch): RenderableMatch | undefined { + let lastElem: RenderableMatch | null = viewer.lastVisibleElement ?? null; + + while (lastElem) { + const compareVal = compareLevels(element, lastElem); + if (compareVal === -1) { + viewer.expand(lastElem); + lastElem = viewer.lastVisibleElement; + } else if (compareVal === 1) { + lastElem = viewer.getParentElement(lastElem); + } else { + return lastElem; + } + } + + return undefined; } diff --git a/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts b/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts index 5717a23bfbe..681dae8164c 100644 --- a/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts +++ b/src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts @@ -6,6 +6,7 @@ import { ITreeNavigator } from 'vs/base/browser/ui/tree/tree'; import { Emitter } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { RenderableMatch } from 'vs/workbench/contrib/search/common/searchModel'; const someEvent = new Emitter().event; @@ -33,6 +34,7 @@ export class MockObjectTree implements IDisposable { get onDidChangeRenderNodeCount() { return someEvent; } get onDidDispose() { return someEvent; } + get lastVisibleElement() { return this.elements[this.elements.length - 1]; } constructor(private elements: any[]) { } @@ -53,6 +55,10 @@ export class MockObjectTree implements IDisposable { return new ArrayNavigator(this.elements, startIdx); } + getParentElement(elem: RenderableMatch) { + return elem.parent(); + } + dispose(): void { } } diff --git a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts index c76c3469563..d152f109924 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts @@ -15,7 +15,7 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { IFileMatch } from 'vs/workbench/services/search/common/search'; -import { ReplaceAction } from 'vs/workbench/contrib/search/browser/searchActions'; +import { getElementToFocusAfterRemoved, getLastNodeFromSameType } from 'vs/workbench/contrib/search/browser/searchActions'; import { FileMatch, FileMatchOrMatch, Match } from 'vs/workbench/contrib/search/common/searchModel'; import { MockObjectTree } from 'vs/workbench/contrib/search/test/browser/mockSearchTree'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -32,6 +32,7 @@ suite('Search Actions', () => { instantiationService.stub(IKeybindingService, {}); instantiationService.stub(IKeybindingService, 'resolveKeybinding', (keybinding: Keybinding) => [new USLayoutResolvedKeybinding(keybinding, OS)]); instantiationService.stub(IKeybindingService, 'lookupKeybinding', (id: string) => null); + instantiationService.stub(IKeybindingService, 'lookupKeybinding', (id: string) => null); counter = 0; }); @@ -41,44 +42,18 @@ suite('Search Actions', () => { const data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), aMatch(fileMatch2)]; const tree = aTree(data); const target = data[2]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); + const actual = getElementToFocusAfterRemoved(tree, target, [target]); assert.strictEqual(data[4], actual); }); - test('get next element to focus after removing a match when it does not have next sibling match', function () { - const fileMatch1 = aFileMatch(); - const fileMatch2 = aFileMatch(); - const data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), aMatch(fileMatch2)]; - const tree = aTree(data); - const target = data[5]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); - assert.strictEqual(data[4], actual); - }); - - test('get next element to focus after removing a match when it does not have next sibling match and previous match is file match', function () { - const fileMatch1 = aFileMatch(); - const fileMatch2 = aFileMatch(); - const data = [fileMatch1, aMatch(fileMatch1), aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2)]; - const tree = aTree(data); - const target = data[4]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); - assert.strictEqual(data[2], actual); - }); - test('get next element to focus after removing a match when it is the only match', function () { const fileMatch1 = aFileMatch(); const data = [fileMatch1, aMatch(fileMatch1)]; const tree = aTree(data); const target = data[1]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); + const actual = getElementToFocusAfterRemoved(tree, target, [target]); assert.strictEqual(undefined, actual); }); @@ -89,23 +64,31 @@ suite('Search Actions', () => { const data = [fileMatch1, aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), fileMatch3, aMatch(fileMatch3)]; const tree = aTree(data); const target = data[2]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); + const actual = getElementToFocusAfterRemoved(tree, target, []); assert.strictEqual(data[4], actual); }); - test('get next element to focus after removing a file match when it has no next sibling', function () { + test('Find last FileMatch in Tree', function () { const fileMatch1 = aFileMatch(); const fileMatch2 = aFileMatch(); const fileMatch3 = aFileMatch(); const data = [fileMatch1, aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), fileMatch3, aMatch(fileMatch3)]; const tree = aTree(data); - const target = data[4]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); - assert.strictEqual(data[3], actual); + const actual = getLastNodeFromSameType(tree, fileMatch1); + assert.strictEqual(fileMatch3, actual); + }); + + test('Find last Match in Tree', function () { + const fileMatch1 = aFileMatch(); + const fileMatch2 = aFileMatch(); + const fileMatch3 = aFileMatch(); + const data = [fileMatch1, aMatch(fileMatch1), fileMatch2, aMatch(fileMatch2), fileMatch3, aMatch(fileMatch3)]; + const tree = aTree(data); + + const actual = getLastNodeFromSameType(tree, aMatch(fileMatch1)); + assert.strictEqual(data[5], actual); }); test('get next element to focus after removing a file match when it is only match', function () { @@ -113,9 +96,9 @@ suite('Search Actions', () => { const data = [fileMatch1, aMatch(fileMatch1)]; const tree = aTree(data); const target = data[0]; - const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); + // const testObject: ReplaceAction = instantiationService.createInstance(ReplaceAction, tree, target, null); - const actual = testObject.getElementToFocusAfterRemoved(tree, target, false); + const actual = getElementToFocusAfterRemoved(tree, target, []); assert.strictEqual(undefined, actual); }); From 90054ae22fd6d01ef62f0120e17de358f70d9e00 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 09:35:32 -0700 Subject: [PATCH 483/599] Make returned editor contributions an iterable instead of an array (#163309) This lets us avoid having to call `.slice(0)` for the contributions --- src/vs/editor/browser/editorExtensions.ts | 17 +++++++++-------- .../editor/browser/widget/codeEditorWidget.ts | 9 ++------- .../editor/browser/widget/diffEditorWidget.ts | 4 ++-- .../browser/view/editors/baseCodeEditorView.ts | 5 +++-- .../browser/view/editors/codeEditorView.ts | 2 +- .../browser/view/editors/inputCodeEditorView.ts | 5 +++-- .../view/editors/resultCodeEditorView.ts | 2 +- .../contrib/notebook/browser/notebookBrowser.ts | 4 ++-- .../notebook/browser/notebookEditorWidget.ts | 12 ++++-------- .../searchEditor/browser/searchEditor.ts | 5 +++-- 10 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index f61142282d3..d5645730c37 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -24,6 +24,7 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ILogService } from 'vs/platform/log/common/log'; +import { Iterable } from 'vs/base/common/iterator'; export type ServicesAccessor = InstantiationServicesAccessor; @@ -490,15 +491,15 @@ export namespace EditorExtensionsRegistry { return EditorContributionRegistry.INSTANCE.getEditorActions(); } - export function getEditorContributions(): IEditorContributionDescription[] { + export function getEditorContributions(): Iterable { return EditorContributionRegistry.INSTANCE.getEditorContributions(); } - export function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] { - return EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0); + export function getSomeEditorContributions(ids: string[]): Iterable { + return Iterable.filter(EditorContributionRegistry.INSTANCE.getEditorContributions(), c => ids.indexOf(c.id) >= 0); } - export function getDiffEditorContributions(): IDiffEditorContributionDescription[] { + export function getDiffEditorContributions(): Iterable { return EditorContributionRegistry.INSTANCE.getDiffEditorContributions(); } } @@ -528,16 +529,16 @@ class EditorContributionRegistry { this.editorContributions.push({ id, ctor: ctor as IEditorContributionCtor }); } - public getEditorContributions(): IEditorContributionDescription[] { - return this.editorContributions.slice(0); + public getEditorContributions(): Iterable { + return this.editorContributions; } public registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void { this.diffEditorContributions.push({ id, ctor: ctor as IDiffEditorContributionCtor }); } - public getDiffEditorContributions(): IDiffEditorContributionDescription[] { - return this.diffEditorContributions.slice(0); + public getDiffEditorContributions(): Iterable { + return this.diffEditorContributions; } public registerEditorAction(action: EditorAction) { diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 8a49db0edb7..403b5e61c2f 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -74,7 +74,7 @@ export interface ICodeEditorWidgetOptions { * Contributions to instantiate. * Defaults to EditorExtensionsRegistry.getEditorContributions(). */ - contributions?: IEditorContributionDescription[]; + contributions?: Iterable; /** * Telemetry data associated with this CodeEditorWidget. @@ -329,12 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._contentWidgets = {}; this._overlayWidgets = {}; - let contributions: IEditorContributionDescription[]; - if (Array.isArray(codeEditorWidgetOptions.contributions)) { - contributions = codeEditorWidgetOptions.contributions; - } else { - contributions = EditorExtensionsRegistry.getEditorContributions(); - } + const contributions = codeEditorWidgetOptions.contributions ?? EditorExtensionsRegistry.getEditorContributions(); for (const desc of contributions) { if (this._contributions[desc.id]) { onUnexpectedError(new Error(`Cannot have two contributions with the same id ${desc.id}`)); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 74a24d46312..7a63e5427f3 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -42,7 +42,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { Constants } from 'vs/base/common/uint'; -import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; @@ -366,7 +366,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._options.renderSideBySide); })); - const contributions: IDiffEditorContributionDescription[] = EditorExtensionsRegistry.getDiffEditorContributions(); + const contributions = EditorExtensionsRegistry.getDiffEditorContributions(); for (const desc of contributions) { try { this._register(instantiationService.createInstance(desc.ctor, this)); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts index 368dfff698e..b4084701ac3 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts @@ -6,6 +6,7 @@ import { reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { BugIndicatingError } from 'vs/base/common/errors'; +import { Iterable } from 'vs/base/common/iterator'; import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; @@ -115,7 +116,7 @@ export class BaseCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): IEditorContributionDescription[] | undefined { - return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): Iterable | undefined { + return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index 7d53075c364..df40fc8e55c 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -103,7 +103,7 @@ export abstract class CodeEditorView extends Disposable { } - protected getEditorContributions(): IEditorContributionDescription[] | undefined { + protected getEditorContributions(): Iterable | undefined { return undefined; } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index dbebe6d026e..dfb5b90a382 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -8,6 +8,7 @@ import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { Codicon } from 'vs/base/common/codicons'; +import { Iterable } from 'vs/base/common/iterator'; import { Disposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; import { autorun, autorunWithStore, derived, IObservable, ISettableObservable, ITransaction, observableValue, transaction } from 'vs/base/common/observable'; @@ -204,8 +205,8 @@ export class InputCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): IEditorContributionDescription[] | undefined { - return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): Iterable | undefined { + return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index 937564bb6e7..6d4006e97ba 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -206,6 +206,6 @@ export class ResultCodeEditorView extends CodeEditorView { }); protected override getEditorContributions(): IEditorContributionDescription[] | undefined { - return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); + return Array.from(EditorExtensionsRegistry.getEditorContributions()).filter(c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 9befc5ed2c3..fc1315f3426 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -323,8 +323,8 @@ export interface INotebookEditorContributionDescription { export interface INotebookEditorCreationOptions { readonly isEmbedded?: boolean; readonly isReadOnly?: boolean; - readonly contributions?: INotebookEditorContributionDescription[]; - readonly cellEditorContributions?: IEditorContributionDescription[]; + readonly contributions?: Iterable; + readonly cellEditorContributions?: Iterable; readonly menuIds: { notebookToolbar: MenuId; cellTitleToolbar: MenuId; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 21474118da4..892021f8529 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -46,7 +46,7 @@ import { contrastBorder, diffInserted, diffRemoved, editorBackground, errorForeg import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { EDITOR_PANE_BACKGROUND, PANEL_BORDER, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, CellRevealType, 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 { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, CellRevealType, IActiveNotebookEditorDelegate, IBaseCellEditorOptions, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IInsetRenderOutput, IModelDecorationsChangeAccessor, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, 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/services/notebookEditorService'; import { notebookDebug } from 'vs/workbench/contrib/notebook/browser/notebookLogger'; @@ -85,13 +85,14 @@ import { NotebookPerfMarks } from 'vs/workbench/contrib/notebook/common/notebook import { BaseCellEditorOptions } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEditorOptions'; import { ILogService } from 'vs/platform/log/common/log'; import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor'; +import { Iterable } from 'vs/base/common/iterator'; const $ = DOM.$; export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOptions { // We inlined the id to avoid loading comment contrib in tests const skipContributions = ['editor.contrib.review', FloatingClickMenu.ID]; - const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); + const contributions = Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => skipContributions.indexOf(c.id) === -1); return { menuIds: { @@ -349,12 +350,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD this._editorEditable.set(!creationOptions.isReadOnly); - let contributions: INotebookEditorContributionDescription[]; - if (Array.isArray(this.creationOptions.contributions)) { - contributions = this.creationOptions.contributions; - } else { - contributions = NotebookEditorExtensionsRegistry.getEditorContributions(); - } + const contributions = this.creationOptions.contributions ?? NotebookEditorExtensionsRegistry.getEditorContributions(); for (const desc of contributions) { let contribution: INotebookEditorContribution | undefined; try { diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts index 54be4156b6e..e1a91b5d71f 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts @@ -61,6 +61,7 @@ import { renderSearchMessage } from 'vs/workbench/contrib/search/browser/searchM import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { UnusualLineTerminatorsDetector } from 'vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators'; import { isHighContrast } from 'vs/platform/theme/common/theme'; +import { Iterable } from 'vs/base/common/iterator'; const RESULT_LINE_REGEX = /^(\s+)(\d+)(: | )(\s*)(.*)$/; const FILE_LINE_REGEX = /^(\S.*):$/; @@ -225,9 +226,9 @@ export class SearchEditor extends AbstractTextCodeEditor } } - private _getContributions(): IEditorContributionDescription[] { + private _getContributions(): Iterable { const skipContributions = [UnusualLineTerminatorsDetector.ID]; - return EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); + return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => skipContributions.indexOf(c.id) === -1); } protected override getCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { From 661382f5e4eff6f9c8aa0d76e5a711ef3c6304ca Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Tue, 11 Oct 2022 09:55:41 -0700 Subject: [PATCH 484/599] fix memory leak and switch to use disposableStore (#163022) fix memory leak at switch to use disposableStore --- .../search/browser/searchResultsView.ts | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index 5ddcc2e1134..da7f41befc9 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -10,7 +10,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { IAction } from 'vs/base/common/actions'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as paths from 'vs/base/common/path'; import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -33,7 +33,8 @@ interface IFolderMatchTemplate { label: IResourceLabel; badge: CountBadge; actions: ActionBar; - disposables: IDisposable[]; + disposables: DisposableStore; + disposableActions: DisposableStore; } interface IFileMatchTemplate { @@ -41,7 +42,7 @@ interface IFileMatchTemplate { label: IResourceLabel; badge: CountBadge; actions: ActionBar; - disposables: IDisposable[]; + disposables: DisposableStore; } interface IMatchTemplate { @@ -114,22 +115,26 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree } renderTemplate(container: HTMLElement): IFolderMatchTemplate { - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); const folderMatchElement = DOM.append(container, DOM.$('.foldermatch')); const label = this.labels.create(folderMatchElement, { supportDescriptionHighlights: true, supportHighlights: true }); - disposables.push(label); + disposables.add(label); const badge = new CountBadge(DOM.append(folderMatchElement, DOM.$('.badge'))); - disposables.push(attachBadgeStyler(badge, this.themeService)); + disposables.add(attachBadgeStyler(badge, this.themeService)); const actionBarContainer = DOM.append(folderMatchElement, DOM.$('.actionBarContainer')); const actions = new ActionBar(actionBarContainer, { animated: false }); - disposables.push(actions); + disposables.add(actions); + + const disposableElements = new DisposableStore(); + disposables.add(disposableElements); return { label, badge, actions, - disposables + disposables, + disposableActions: disposableElements }; } @@ -151,10 +156,15 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree } disposeElement(element: ITreeNode, index: number, templateData: IFolderMatchTemplate): void { + templateData.disposableActions.clear(); + } + + disposeCompressedElements(node: ITreeNode, any>, index: number, templateData: IFolderMatchTemplate, height: number | undefined): void { + templateData.disposableActions.clear(); } disposeTemplate(templateData: IFolderMatchTemplate): void { - dispose(templateData.disposables); + templateData.disposables.dispose(); } private renderFolderDetails(folder: FolderMatch, templateData: IFolderMatchTemplate) { @@ -164,10 +174,14 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree const actions: IAction[] = []; if (this.searchModel.isReplaceActive() && count > 0) { - actions.push(this.instantiationService.createInstance(ReplaceAllInFolderAction, this.searchView.getControl(), folder)); + const replaceAction = this.instantiationService.createInstance(ReplaceAllInFolderAction, this.searchView.getControl(), folder); + actions.push(replaceAction); + templateData.disposableActions.add(replaceAction); } + const removeAction = this.instantiationService.createInstance(RemoveAction, this.searchView.getControl(), folder); + actions.push(removeAction); + templateData.disposableActions.add(removeAction); - actions.push(this.instantiationService.createInstance(RemoveAction, this.searchView.getControl(), folder)); templateData.actions.push(actions, { icon: true, label: false }); } } @@ -194,15 +208,15 @@ export class FileMatchRenderer extends Disposable implements ICompressibleTreeRe } renderTemplate(container: HTMLElement): IFileMatchTemplate { - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); const fileMatchElement = DOM.append(container, DOM.$('.filematch')); const label = this.labels.create(fileMatchElement); - disposables.push(label); + disposables.add(label); const badge = new CountBadge(DOM.append(fileMatchElement, DOM.$('.badge'))); - disposables.push(attachBadgeStyler(badge, this.themeService)); + disposables.add(attachBadgeStyler(badge, this.themeService)); const actionBarContainer = DOM.append(fileMatchElement, DOM.$('.actionBarContainer')); const actions = new ActionBar(actionBarContainer, { animated: false }); - disposables.push(actions); + disposables.add(actions); return { el: fileMatchElement, @@ -237,7 +251,7 @@ export class FileMatchRenderer extends Disposable implements ICompressibleTreeRe } disposeTemplate(templateData: IFileMatchTemplate): void { - dispose(templateData.disposables); + templateData.disposables.dispose(); } } From 9cc932ee6bb1b6b9a8ed0cc4500fb33dae1d1db6 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 11 Oct 2022 10:12:08 -0700 Subject: [PATCH 485/599] update custom menubar to show toggle title info (#163315) --- src/vs/workbench/browser/parts/titlebar/menubarControl.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 7930effaae7..df4e45e65f7 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -40,6 +40,7 @@ import { IsMacNativeContext, IsWebContext } from 'vs/platform/contextkey/common/ import { ICommandService } from 'vs/platform/commands/common/commands'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions'; +import { isICommandActionToggleInfo } from 'vs/platform/action/common/action'; export type IOpenRecentAction = IAction & { uri: URI; remoteAuthority?: string }; @@ -701,7 +702,7 @@ export class CustomMenubarControl extends MenubarControl { this.insertActionsBefore(action, target); // use mnemonicTitle whenever possible - const title = typeof action.item.title === 'string' + let title = typeof action.item.title === 'string' ? action.item.title : action.item.title.mnemonicTitle ?? action.item.title.value; @@ -727,6 +728,10 @@ export class CustomMenubarControl extends MenubarControl { target.push(new SubmenuAction(action.id, mnemonicMenuLabel(title), submenuActions)); } } else { + if (isICommandActionToggleInfo(action.item.toggled)) { + title = action.item.toggled.mnemonicTitle ?? action.item.toggled.title ?? title; + } + const newAction = new Action(action.id, mnemonicMenuLabel(title), action.class, action.enabled, () => this.commandService.executeCommand(action.id)); newAction.tooltip = action.tooltip; newAction.checked = action.checked; From dace01386edf4e9314bc689faf167822352d9137 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 11 Oct 2022 19:18:14 +0200 Subject: [PATCH 486/599] fix #163317 (#163319) --- src/vs/workbench/browser/parts/activitybar/activitybarPart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 6e51d7a9257..a0151834ec9 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -939,7 +939,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart state.push({ id: compositeItem.id, name: viewContainerModel.title, - icon: URI.isUri(viewContainerModel.icon) && this.environmentService.remoteAuthority && isNative ? undefined : viewContainerModel.icon, /* Donot cache uri icons in desktop with remote connection */ + icon: URI.isUri(viewContainerModel.icon) && this.environmentService.remoteAuthority ? undefined : viewContainerModel.icon, /* Donot cache uri icons with remote connection */ views, pinned: compositeItem.pinned, order: compositeItem.order, From 01de02ba72e54201b1b5be66814bc32027ca01d1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 10:22:38 -0700 Subject: [PATCH 487/599] Also make getEditorActions return an iterable instead of an array (#163320) This lets us avoid an extra `.slice(0)` when returning the actions --- src/vs/editor/browser/editorExtensions.ts | 6 +++--- src/vs/editor/browser/widget/codeEditorWidget.ts | 6 +++--- .../contrib/comments/browser/simpleCommentEditor.ts | 2 +- .../browser/view/editors/resultCodeEditorView.ts | 5 +++-- .../contrib/preferences/browser/keybindingsEditor.ts | 4 +++- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index d5645730c37..2676bb009b2 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -487,7 +487,7 @@ export namespace EditorExtensionsRegistry { return EditorContributionRegistry.INSTANCE.getEditorCommand(commandId); } - export function getEditorActions(): EditorAction[] { + export function getEditorActions(): Iterable { return EditorContributionRegistry.INSTANCE.getEditorActions(); } @@ -546,8 +546,8 @@ class EditorContributionRegistry { this.editorActions.push(action); } - public getEditorActions(): EditorAction[] { - return this.editorActions.slice(0); + public getEditorActions(): Iterable { + return this.editorActions; } public registerEditorCommand(editorCommand: EditorCommand) { diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 403b5e61c2f..2872e6be0f0 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -343,10 +343,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } } - EditorExtensionsRegistry.getEditorActions().forEach((action) => { + for (const action of EditorExtensionsRegistry.getEditorActions()) { if (this._actions[action.id]) { onUnexpectedError(new Error(`Cannot have two actions with the same id ${action.id}`)); - return; + continue; } const internalAction = new InternalEditorAction( action.id, @@ -361,7 +361,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._contextKeyService ); this._actions[internalAction.id] = internalAction; - }); + } const isDropIntoEnabled = () => { return !this._configuration.options.get(EditorOption.readOnly) diff --git a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts index c4ec1bbf5e3..c94bdc405fa 100644 --- a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts +++ b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts @@ -76,7 +76,7 @@ export class SimpleCommentEditor extends CodeEditorWidget { return this._parentThread; } - protected _getActions(): EditorAction[] { + protected _getActions(): Iterable { return EditorExtensionsRegistry.getEditorActions(); } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index 6d4006e97ba..af9124ee5a0 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -7,6 +7,7 @@ import { reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { CompareResult } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; +import { Iterable } from 'vs/base/common/iterator'; import { toDisposable } from 'vs/base/common/lifecycle'; import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; import { IEditorContributionDescription, EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; @@ -205,7 +206,7 @@ export class ResultCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): IEditorContributionDescription[] | undefined { - return Array.from(EditorExtensionsRegistry.getEditorContributions()).filter(c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): Iterable | undefined { + return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index c6312374488..1b9edd9c0d4 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -519,7 +519,9 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP private getActionsLabels(): Map { const actionsLabels: Map = new Map(); - EditorExtensionsRegistry.getEditorActions().forEach(editorAction => actionsLabels.set(editorAction.id, editorAction.label)); + for (const editorAction of EditorExtensionsRegistry.getEditorActions()) { + actionsLabels.set(editorAction.id, editorAction.label); + } for (const menuItem of MenuRegistry.getMenuItems(MenuId.CommandPalette)) { if (isIMenuItem(menuItem)) { const title = typeof menuItem.command.title === 'string' ? menuItem.command.title : menuItem.command.title.value; From d2cff714d5410c570043e259fd72c75bbf387b7a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 10:42:05 -0700 Subject: [PATCH 488/599] Add allow list of valid notebook command uris (#163322) This restricts notebooks to run three command uris. These 3 commands should all be safe to run, even with untrusted inputs --- .../view/renderers/backLayerWebView.ts | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 15ba313df2c..a32ebc7dc1a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -557,24 +557,8 @@ var requirejs = (function() { return; } - if (matchesScheme(link, Schemas.command)) { - const ret = /command\:workbench\.action\.openLargeOutput\?(.*)/.exec(link); - if (ret && ret.length === 2) { - const outputId = ret[1]; - this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); - return; - } - console.warn('Command links are deprecated and will be removed, use message passing instead: https://github.com/microsoft/vscode/issues/123601'); - } - - if (matchesScheme(link, Schemas.command)) { - if (this.workspaceTrustManagementService.isWorkspaceTrusted()) { - this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: true }); - } else { - console.warn('Command links are disabled in untrusted workspaces'); - } - } else if (matchesSomeScheme(link, Schemas.vscodeNotebookCell, Schemas.http, Schemas.https, Schemas.mailto)) { - this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: true }); + if (matchesSomeScheme(link, Schemas.vscodeNotebookCell, Schemas.http, Schemas.https, Schemas.mailto)) { + this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: false }); } })); @@ -693,23 +677,35 @@ var requirejs = (function() { } case 'clicked-link': { let linkToOpen: URI | string | undefined; + if (matchesScheme(data.href, Schemas.command)) { - const ret = /command\:workbench\.action\.openLargeOutput\?(.*)/.exec(data.href); - if (ret && ret.length === 2) { - const outputId = ret[1]; - const group = this.editorGroupService.activeGroup; - - if (group) { - if (group.activeEditor) { - group.pinEditor(group.activeEditor); + // We allow a very limited set of commands + const uri = URI.parse(data.href); + switch (uri.path) { + case 'workbench.action.openLargeOutput': { + const outputId = uri.query; + const group = this.editorGroupService.activeGroup; + if (group) { + if (group.activeEditor) { + group.pinEditor(group.activeEditor); + } } - } - this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); - return; + this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); + return; + } + case 'github-issues.authNow': + case 'workbench.extensions.search': + case 'workbench.action.openSettings': { + this.openerService.open(data.href, { fromUserGesture: true, allowCommands: true, fromWorkspace: true }); + return; + } } + + return; } - if (matchesSomeScheme(data.href, Schemas.http, Schemas.https, Schemas.mailto, Schemas.command, Schemas.vscodeNotebookCell, Schemas.vscodeNotebook)) { + + if (matchesSomeScheme(data.href, Schemas.http, Schemas.https, Schemas.mailto, Schemas.vscodeNotebookCell, Schemas.vscodeNotebook)) { linkToOpen = data.href; } else if (!/^[\w\-]+:/.test(data.href)) { const fragmentStartIndex = data.href.lastIndexOf('#'); @@ -740,7 +736,7 @@ var requirejs = (function() { } if (linkToOpen) { - this.openerService.open(linkToOpen, { fromUserGesture: true, allowCommands: true, fromWorkspace: true }); + this.openerService.open(linkToOpen, { fromUserGesture: true, allowCommands: false, fromWorkspace: true }); } break; } From 7666d7acd4cb7382c6e4749166f713d1226ccd99 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 11 Oct 2022 10:53:07 -0700 Subject: [PATCH 489/599] Avoid * activating ipynb extension (#163325) --- extensions/ipynb/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/ipynb/package.json b/extensions/ipynb/package.json index 2d10494e412..9facfaa3322 100644 --- a/extensions/ipynb/package.json +++ b/extensions/ipynb/package.json @@ -13,7 +13,8 @@ "diffContentOptions" ], "activationEvents": [ - "*" + "onNotebook:jupyter-notebook", + "onCommand:ipynb.newUntitledIpynb" ], "extensionKind": [ "workspace", From fad9089781c40e7b35e43076ca2951085aa8264d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 11:00:31 -0700 Subject: [PATCH 490/599] Normalize resources when checking valid roots (#163327) Fix MSCR 74267 Fix https://github.com/microsoft/vscode-internalbacklog/issues/3140 Remove extra indexOf check This could cause failures for files such as `img..png` --- src/vs/workbench/contrib/webview/browser/resourceLoading.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/resourceLoading.ts b/src/vs/workbench/contrib/webview/browser/resourceLoading.ts index cdff87cccd0..602e3610c1b 100644 --- a/src/vs/workbench/contrib/webview/browser/resourceLoading.ts +++ b/src/vs/workbench/contrib/webview/browser/resourceLoading.ts @@ -7,7 +7,7 @@ import { VSBufferReadableStream } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { isUNC } from 'vs/base/common/extpath'; import { Schemas } from 'vs/base/common/network'; -import { sep } from 'vs/base/common/path'; +import { normalize, sep } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { ILogService } from 'vs/platform/log/common/log'; @@ -103,8 +103,8 @@ function containsResource(root: URI, resource: URI): boolean { return false; } - let rootPath = root.fsPath + (root.fsPath.endsWith(sep) ? '' : sep); - let resourceFsPath = resource.fsPath; + let resourceFsPath = normalize(resource.fsPath); + let rootPath = normalize(root.fsPath + (root.fsPath.endsWith(sep) ? '' : sep)); if (isUNC(root.fsPath) && isUNC(resource.fsPath)) { rootPath = rootPath.toLowerCase(); From 3305ea470af1f47ebfa4ec5ae7ab33b070be2e9f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 11 Oct 2022 11:54:16 -0700 Subject: [PATCH 491/599] Start optimizing DebugService creation (#162879) * Debug editor contribs should not force DebugService to be created immediately Fix #159886 * Do slow registration of debug fs provider later * Small optimization to context keys in DebugService --- .../browser/breakpointEditorContribution.ts | 90 +++++++++------ .../browser/callStackEditorContribution.ts | 52 ++++++--- .../debug/browser/debug.contribution.ts | 103 +++++++++--------- .../debug/browser/debugAdapterManager.ts | 11 +- .../debug/browser/debugEditorContribution.ts | 29 ++++- .../contrib/debug/browser/debugService.ts | 14 ++- .../workbench/contrib/debug/common/debug.ts | 2 +- 7 files changed, 190 insertions(+), 111 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index b900d70c0d9..e1eb88b7dfe 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -3,41 +3,41 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as env from 'vs/base/common/platform'; +import { isSafari } from 'vs/base/browser/browser'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; import * as dom from 'vs/base/browser/dom'; -import { URI } from 'vs/base/common/uri'; -import severity from 'vs/base/common/severity'; -import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions'; -import { Range } from 'vs/editor/common/core/range'; -import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; -import { IModelDecorationOptions, TrackedRangeStickiness, ITextModel, OverviewRulerLane, IModelDecorationOverviewRulerOptions } from 'vs/editor/common/model'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, IBreakpointEditorContribution, IBreakpointUpdateData, IDebugConfiguration, State, IDebugSession, DebuggerString } from 'vs/workbench/contrib/debug/common/debug'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget'; -import { IDisposable, dispose, disposeIfDisposable } from 'vs/base/common/lifecycle'; -import { MarkdownString } from 'vs/base/common/htmlContent'; -import { getBreakpointMessageAndIcon } from 'vs/workbench/contrib/debug/browser/breakpointsView'; -import { generateUuid } from 'vs/base/common/uuid'; -import { memoize } from 'vs/base/common/decorators'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions'; import { distinct } from 'vs/base/common/arrays'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { BrowserFeatures } from 'vs/base/browser/canIUse'; -import { isSafari } from 'vs/base/browser/browser'; -import { registerThemingParticipant, themeColorFromId, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { registerColor } from 'vs/platform/theme/common/colorRegistry'; -import { ILabelService } from 'vs/platform/label/common/label'; -import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; +import { memoize } from 'vs/base/common/decorators'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { Disposable, dispose, disposeIfDisposable, IDisposable } from 'vs/base/common/lifecycle'; +import * as env from 'vs/base/common/platform'; +import severity from 'vs/base/common/severity'; import { noBreakWhitespace } from 'vs/base/common/strings'; -import { ILanguageService } from 'vs/editor/common/languages/language'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Range } from 'vs/editor/common/core/range'; +import { ILanguageService } from 'vs/editor/common/languages/language'; +import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, ITextModel, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; +import * as nls from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { registerColor } from 'vs/platform/theme/common/colorRegistry'; +import { registerThemingParticipant, themeColorFromId, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { getBreakpointMessageAndIcon } from 'vs/workbench/contrib/debug/browser/breakpointsView'; +import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget'; +import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; +import { BreakpointWidgetContext, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DebuggerString, IBreakpoint, IBreakpointEditorContribution, IBreakpointUpdateData, IDebugConfiguration, IDebugService, IDebugSession, State } from 'vs/workbench/contrib/debug/common/debug'; const $ = dom.$; @@ -188,17 +188,43 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio return result; } -export class BreakpointEditorContribution implements IBreakpointEditorContribution { +export class LazyBreakpointEditorContribution extends Disposable implements IBreakpointEditorContribution { + private _contrib: IBreakpointEditorContribution | undefined; + + constructor(editor: ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) { + super(); + + const listener = editor.onDidChangeModel(() => { + if (editor.hasModel()) { + listener.dispose(); + this._contrib = this._register(instantiationService.createInstance(BreakpointEditorContribution, editor)); + } + }); + } + showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext | undefined): void { + this._contrib?.showBreakpointWidget(lineNumber, column, context); + } + + closeBreakpointWidget(): void { + this._contrib?.closeBreakpointWidget(); + } + + getContextMenuActionsAtPosition(lineNumber: number, model: ITextModel): IAction[] { + return this._contrib?.getContextMenuActionsAtPosition(lineNumber, model) ?? []; + } +} + +class BreakpointEditorContribution implements IBreakpointEditorContribution { private breakpointHintDecoration: string | null = null; private breakpointWidget: BreakpointWidget | undefined; - private breakpointWidgetVisible: IContextKey; + private breakpointWidgetVisible!: IContextKey; private toDispose: IDisposable[] = []; private ignoreDecorationsChangedEvent = false; private ignoreBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; private candidateDecorations: { decorationId: string; inlineWidget: InlineBreakpointWidget }[] = []; - private setDecorationsScheduler: RunOnceScheduler; + private setDecorationsScheduler!: RunOnceScheduler; constructor( private readonly editor: ICodeEditor, @@ -212,8 +238,8 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi ) { this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); this.setDecorationsScheduler = new RunOnceScheduler(() => this.setDecorations(), 30); - this.registerListeners(); this.setDecorationsScheduler.schedule(); + this.registerListeners(); } /** diff --git a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts index b09f8c1157c..79cc37f580f 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts @@ -3,21 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Constants } from 'vs/base/common/uint'; -import { Range } from 'vs/editor/common/core/range'; -import { TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions, OverviewRulerLane } from 'vs/editor/common/model'; -import { IDebugService, IStackFrame } from 'vs/workbench/contrib/debug/common/debug'; -import { registerThemingParticipant, themeColorFromId, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { registerColor } from 'vs/platform/theme/common/colorRegistry'; -import { localize } from 'vs/nls'; -import { Event } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { distinct } from 'vs/base/common/arrays'; +import { Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Constants } from 'vs/base/common/uint'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { Range } from 'vs/editor/common/core/range'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { IModelDecorationOptions, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { localize } from 'vs/nls'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; +import { registerColor } from 'vs/platform/theme/common/colorRegistry'; +import { registerThemingParticipant, themeColorFromId, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { debugStackframe, debugStackframeFocused } from 'vs/workbench/contrib/debug/browser/debugIcons'; -import { ILogService } from 'vs/platform/log/common/log'; +import { IDebugService, IStackFrame } from 'vs/workbench/contrib/debug/common/debug'; export const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hcDark: '#ffff0033', hcLight: '#ffff6673' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.')); export const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hcDark: '#7abd7a4d', hcLight: '#cee7ce73' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.')); @@ -107,8 +108,20 @@ export function createDecorationsForStackFrame(stackFrame: IStackFrame, isFocuse return result; } -export class CallStackEditorContribution implements IEditorContribution { - private toDispose: IDisposable[] = []; +export class LazyCallStackEditorContribution extends Disposable { + constructor(editor: ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) { + super(); + + const listener = editor.onDidChangeModel(() => { + if (editor.hasModel()) { + listener.dispose(); + this._register(instantiationService.createInstance(CallStackEditorContribution, editor)); + } + }); + } +} + +class CallStackEditorContribution extends Disposable implements IEditorContribution { private decorations = this.editor.createDecorationsCollection(); constructor( @@ -117,15 +130,18 @@ export class CallStackEditorContribution implements IEditorContribution { @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @ILogService private readonly logService: ILogService, ) { + super(); + const setDecorations = () => this.decorations.set(this.createCallStackDecorations()); - this.toDispose.push(Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getModel().onDidChangeCallStack)(() => { + this._register(Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getModel().onDidChangeCallStack)(() => { setDecorations(); })); - this.toDispose.push(this.editor.onDidChangeModel(e => { + this._register(this.editor.onDidChangeModel(e => { if (e.newModelUrl) { setDecorations(); } })); + setDecorations(); } private createCallStackDecorations(): IModelDeltaDecoration[] { @@ -169,9 +185,9 @@ export class CallStackEditorContribution implements IEditorContribution { return distinct(decorations, d => `${d.options.className} ${d.options.glyphMarginClassName} ${d.range.startLineNumber} ${d.range.startColumn}`); } - dispose(): void { + override dispose(): void { + super.dispose(); this.decorations.clear(); - this.toDispose = dispose(this.toDispose); } } diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index cc89778fd07..c78252dcbd7 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -3,61 +3,58 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { FileAccess } from 'vs/base/common/network'; +import { isMacintosh, isWeb } from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/debug.contribution'; import 'vs/css!./media/debugHover'; -import * as nls from 'vs/nls'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { BreakpointsView } from 'vs/workbench/contrib/debug/browser/breakpointsView'; -import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'; -import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { - IDebugService, VIEWLET_ID, DEBUG_PANEL_ID, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA, - CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX, BREAKPOINT_EDITOR_CONTRIBUTION_ID, REPL_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, EDITOR_CONTRIBUTION_ID, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, getStateLabel, State, CONTEXT_WATCH_ITEM_TYPE, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, DISASSEMBLY_VIEW_ID, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_CAN_VIEW_MEMORY, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, -} from 'vs/workbench/contrib/debug/common/debug'; -import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; -import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; -import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID, CALLSTACK_TOP_ID, CALLSTACK_TOP_LABEL, CALLSTACK_BOTTOM_LABEL, CALLSTACK_UP_LABEL, CALLSTACK_BOTTOM_ID, CALLSTACK_UP_ID, CALLSTACK_DOWN_ID, CALLSTACK_DOWN_LABEL, DEBUG_COMMAND_CATEGORY, SELECT_DEBUG_SESSION_ID, SELECT_DEBUG_SESSION_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; -import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; -import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; -import { isMacintosh, isWeb } from 'vs/base/common/platform'; -import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; -import { URI } from 'vs/base/common/uri'; -import { DebugStatusContribution } from 'vs/workbench/contrib/debug/browser/debugStatus'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; -import { LoadedScriptsView } from 'vs/workbench/contrib/debug/browser/loadedScriptsView'; -import { RunToCursorAction, SelectionToReplAction, SelectionToWatchExpressionsAction } from 'vs/workbench/contrib/debug/browser/debugEditorActions'; -import { WatchExpressionsView, ADD_WATCH_LABEL, REMOVE_WATCH_EXPRESSIONS_COMMAND_ID, REMOVE_WATCH_EXPRESSIONS_LABEL, ADD_WATCH_ID } from 'vs/workbench/contrib/debug/browser/watchExpressionsView'; -import { VariablesView, SET_VARIABLE_ID, COPY_VALUE_ID, BREAK_WHEN_VALUE_CHANGES_ID, COPY_EVALUATE_PATH_ID, ADD_TO_WATCH_ID, BREAK_WHEN_VALUE_IS_ACCESSED_ID, BREAK_WHEN_VALUE_IS_READ_ID, VIEW_MEMORY_ID } from 'vs/workbench/contrib/debug/browser/variablesView'; -import { Repl } from 'vs/workbench/contrib/debug/browser/repl'; -import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider'; -import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView'; -import { DebugViewPaneContainer } from 'vs/workbench/contrib/debug/browser/debugViewlet'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { CallStackEditorContribution } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution'; -import { BreakpointEditorContribution } from 'vs/workbench/contrib/debug/browser/breakpointEditorContribution'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; -import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess'; -import { StartDebugQuickAccessProvider } from 'vs/workbench/contrib/debug/browser/debugQuickAccess'; -import { DebugProgressContribution } from 'vs/workbench/contrib/debug/browser/debugProgress'; -import { DebugTitleContribution } from 'vs/workbench/contrib/debug/browser/debugTitle'; -import { registerColors } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { DebugEditorContribution } from 'vs/workbench/contrib/debug/browser/debugEditorContribution'; -import { FileAccess } from 'vs/base/common/network'; -import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; -import { EditorExtensions } from 'vs/workbench/common/editor'; -import { DisassemblyView, DisassemblyViewContribution } from 'vs/workbench/contrib/debug/browser/disassemblyView'; -import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; -import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; -import { DebugLifecycle } from 'vs/workbench/contrib/debug/common/debugLifecycle'; -import { ICommandActionTitle, Icon } from 'vs/platform/action/common/action'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import * as nls from 'vs/nls'; +import { ICommandActionTitle, Icon } from 'vs/platform/action/common/action'; +import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Extensions as QuickAccessExtensions, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; +import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { EditorExtensions } from 'vs/workbench/common/editor'; +import { Extensions as ViewExtensions, IViewContainersRegistry, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views'; +import { LazyBreakpointEditorContribution } from 'vs/workbench/contrib/debug/browser/breakpointEditorContribution'; +import { BreakpointsView } from 'vs/workbench/contrib/debug/browser/breakpointsView'; +import { LazyCallStackEditorContribution } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution'; +import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'; +import { registerColors } from 'vs/workbench/contrib/debug/browser/debugColors'; +import { ADD_CONFIGURATION_ID, CALLSTACK_BOTTOM_ID, CALLSTACK_BOTTOM_LABEL, CALLSTACK_DOWN_ID, CALLSTACK_DOWN_LABEL, CALLSTACK_TOP_ID, CALLSTACK_TOP_LABEL, CALLSTACK_UP_ID, CALLSTACK_UP_LABEL, CONTINUE_ID, CONTINUE_LABEL, COPY_STACK_TRACE_ID, DEBUG_COMMAND_CATEGORY, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, EDIT_EXPRESSION_COMMAND_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, PAUSE_ID, PAUSE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, REMOVE_EXPRESSION_COMMAND_ID, RESTART_FRAME_ID, RESTART_LABEL, RESTART_SESSION_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, SELECT_DEBUG_SESSION_ID, SELECT_DEBUG_SESSION_LABEL, SET_EXPRESSION_COMMAND_ID, SHOW_LOADED_SCRIPTS_ID, STEP_INTO_ID, STEP_INTO_LABEL, STEP_INTO_TARGET_ID, STEP_INTO_TARGET_LABEL, STEP_OUT_ID, STEP_OUT_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STOP_ID, STOP_LABEL, TERMINATE_THREAD_ID, TOGGLE_INLINE_BREAKPOINT_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { DebugConsoleQuickAccess } from 'vs/workbench/contrib/debug/browser/debugConsoleQuickAccess'; +import { RunToCursorAction, SelectionToReplAction, SelectionToWatchExpressionsAction } from 'vs/workbench/contrib/debug/browser/debugEditorActions'; +import { LazyDebugEditorContribution } from 'vs/workbench/contrib/debug/browser/debugEditorContribution'; +import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; +import { DebugProgressContribution } from 'vs/workbench/contrib/debug/browser/debugProgress'; +import { StartDebugQuickAccessProvider } from 'vs/workbench/contrib/debug/browser/debugQuickAccess'; +import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; +import { DebugStatusContribution } from 'vs/workbench/contrib/debug/browser/debugStatus'; +import { DebugTitleContribution } from 'vs/workbench/contrib/debug/browser/debugTitle'; +import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; +import { DebugViewPaneContainer } from 'vs/workbench/contrib/debug/browser/debugViewlet'; +import { DisassemblyView, DisassemblyViewContribution } from 'vs/workbench/contrib/debug/browser/disassemblyView'; +import { LoadedScriptsView } from 'vs/workbench/contrib/debug/browser/loadedScriptsView'; +import { Repl } from 'vs/workbench/contrib/debug/browser/repl'; +import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; +import { ADD_TO_WATCH_ID, BREAK_WHEN_VALUE_CHANGES_ID, BREAK_WHEN_VALUE_IS_ACCESSED_ID, BREAK_WHEN_VALUE_IS_READ_ID, COPY_EVALUATE_PATH_ID, COPY_VALUE_ID, SET_VARIABLE_ID, VariablesView, VIEW_MEMORY_ID } from 'vs/workbench/contrib/debug/browser/variablesView'; +import { ADD_WATCH_ID, ADD_WATCH_LABEL, REMOVE_WATCH_EXPRESSIONS_COMMAND_ID, REMOVE_WATCH_EXPRESSIONS_LABEL, WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchExpressionsView'; +import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView'; +import { BREAKPOINTS_VIEW_ID, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CALLSTACK_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_CAN_VIEW_MEMORY, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DEBUG_UX, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_IN_DEBUG_MODE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_WATCH_ITEM_TYPE, DEBUG_PANEL_ID, DISASSEMBLY_VIEW_ID, EDITOR_CONTRIBUTION_ID, getStateLabel, IDebugService, INTERNAL_CONSOLE_OPTIONS_SCHEMA, LOADED_SCRIPTS_VIEW_ID, REPL_VIEW_ID, State, VARIABLES_VIEW_ID, VIEWLET_ID, WATCH_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug'; +import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider'; +import { DebugLifecycle } from 'vs/workbench/contrib/debug/common/debugLifecycle'; +import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; +import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; const debugCategory = nls.localize('debugCategory', "Debug"); registerColors(); @@ -93,9 +90,9 @@ Registry.as(QuickAccessExtensions.Quickaccess).registerQui helpEntries: [{ description: nls.localize('tasksQuickAccessHelp', "Show All Debug Consoles"), commandId: SELECT_DEBUG_CONSOLE_ID }] }); -registerEditorContribution('editor.contrib.callStack', CallStackEditorContribution); -registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointEditorContribution); -registerEditorContribution(EDITOR_CONTRIBUTION_ID, DebugEditorContribution); +registerEditorContribution('editor.contrib.callStack', LazyCallStackEditorContribution); +registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, LazyBreakpointEditorContribution); +registerEditorContribution(EDITOR_CONTRIBUTION_ID, LazyDebugEditorContribution); const registerDebugCommandPaletteItem = (id: string, title: ICommandActionTitle, when?: ContextKeyExpression, precondition?: ContextKeyExpression) => { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { diff --git a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts index 7f08c57a578..8754713b3b1 100644 --- a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts @@ -43,8 +43,8 @@ export class AdapterManager extends Disposable implements IAdapterManager { private debuggers: Debugger[]; private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[]; private debugAdapterFactories = new Map(); - private debuggersAvailable: IContextKey; - private debugExtensionsAvailable: IContextKey; + private debuggersAvailable!: IContextKey; + private debugExtensionsAvailable!: IContextKey; private readonly _onDidRegisterDebugger = new Emitter(); private readonly _onDidDebuggersExtPointRead = new Emitter(); private breakpointContributions: Breakpoints[] = []; @@ -72,15 +72,16 @@ export class AdapterManager extends Disposable implements IAdapterManager { this.adapterDescriptorFactories = []; this.debuggers = []; this.registerListeners(); - this.debuggersAvailable = CONTEXT_DEBUGGERS_AVAILABLE.bindTo(contextKeyService); + this.contextKeyService.bufferChangeEvents(() => { + this.debuggersAvailable = CONTEXT_DEBUGGERS_AVAILABLE.bindTo(contextKeyService); + this.debugExtensionsAvailable = CONTEXT_DEBUG_EXTENSION_AVAILABLE.bindTo(contextKeyService); + }); this._register(this.contextKeyService.onDidChangeContext(e => { if (e.affectsSome(this.debuggerWhenKeys)) { this.debuggersAvailable.set(this.hasEnabledDebuggers()); this.updateDebugAdapterSchema(); } })); - this.debugExtensionsAvailable = CONTEXT_DEBUG_EXTENSION_AVAILABLE.bindTo(contextKeyService); - this.debugExtensionsAvailable.set(true); // Avoid a flash of the default message before extensions load. this._register(this.onDidDebuggersExtPointRead(() => { this.debugExtensionsAvailable.set(this.debuggers.length > 0); })); diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 249252a170f..2aaa13d034a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -32,7 +32,7 @@ import { memoize } from 'vs/base/common/decorators'; import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover'; import { IModelDeltaDecoration, InjectedTextCursorStops, ITextModel } from 'vs/editor/common/model'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { basename } from 'vs/base/common/path'; import { ModesHoverController } from 'vs/editor/contrib/hover/browser/hover'; @@ -209,6 +209,33 @@ function getWordToLineNumbersMap(model: ITextModel | null): Map { + if (editor.hasModel()) { + listener.dispose(); + this._contrib = this._register(instantiationService.createInstance(DebugEditorContribution, editor)); + } + }); + } + + showHover(range: Range, focus: boolean): Promise { + return this._contrib ? this._contrib.showHover(range, focus) : Promise.resolve(); + } + + addLaunchConfiguration(): Promise { + return this._contrib ? this._contrib.addLaunchConfiguration() : Promise.resolve(); + } + + closeExceptionWidget(): void { + this._contrib?.closeExceptionWidget(); + } +} + export class DebugEditorContribution implements IDebugEditorContribution { private toDispose: IDisposable[]; diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 5d6622a3b7f..7e86b539725 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -84,6 +84,7 @@ export class DebugService implements IDebugService { private sessionCancellationTokens = new Map(); private activity: IDisposable | undefined; private chosenEnvironments: { [key: string]: string }; + private haveDoneLazySetup = false; constructor( @IEditorService private readonly editorService: IEditorService, @@ -140,7 +141,6 @@ export class DebugService implements IDebugService { this.viewModel = new ViewModel(contextKeyService); this.taskRunner = this.instantiationService.createInstance(DebugTaskRunner); - this.disposables.add(this.fileService.registerProvider(DEBUG_MEMORY_SCHEME, new DebugMemoryFileSystemProvider(this))); this.disposables.add(this.fileService.onDidFilesChange(e => this.onFileChanges(e))); this.disposables.add(this.lifecycleService.onWillShutdown(this.dispose, this)); @@ -304,6 +304,15 @@ export class DebugService implements IDebugService { return this._onDidEndSession.event; } + private lazySetup() { + if (!this.haveDoneLazySetup) { + // Registering fs providers is slow + // https://github.com/microsoft/vscode/issues/159886 + this.disposables.add(this.fileService.registerProvider(DEBUG_MEMORY_SCHEME, new DebugMemoryFileSystemProvider(this))); + this.haveDoneLazySetup = true; + } + } + //---- life cycle management /** @@ -316,6 +325,9 @@ export class DebugService implements IDebugService { if (!trust) { return false; } + + this.lazySetup(); + this.startInitializingState(options); try { // make sure to save all files and that the configuration is up to date diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index d8feb192429..1c800a672ce 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -73,7 +73,7 @@ export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey('jump export const CONTEXT_STEP_INTO_TARGETS_SUPPORTED = new RawContextKey('stepIntoTargetsSupported', false, { type: 'boolean', description: nls.localize('stepIntoTargetsSupported', "True when the focused session supports 'stepIntoTargets' request.") }); export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey('breakpointsExist', false, { type: 'boolean', description: nls.localize('breakpointsExist', "True when at least one breakpoint exists.") }); export const CONTEXT_DEBUGGERS_AVAILABLE = new RawContextKey('debuggersAvailable', false, { type: 'boolean', description: nls.localize('debuggersAvailable', "True when there is at least one debug extensions active.") }); -export const CONTEXT_DEBUG_EXTENSION_AVAILABLE = new RawContextKey('debugExtensionAvailable', false, { type: 'boolean', description: nls.localize('debugExtensionsAvailable', "True when there is at least one debug extension installed and enabled.") }); +export const CONTEXT_DEBUG_EXTENSION_AVAILABLE = new RawContextKey('debugExtensionAvailable', true, { type: 'boolean', description: nls.localize('debugExtensionsAvailable', "True when there is at least one debug extension installed and enabled.") }); export const CONTEXT_DEBUG_PROTOCOL_VARIABLE_MENU_CONTEXT = new RawContextKey('debugProtocolVariableMenuContext', undefined, { type: 'string', description: nls.localize('debugProtocolVariableMenuContext', "Represents the context the debug adapter sets on the focused variable in the VARIABLES view.") }); export const CONTEXT_SET_VARIABLE_SUPPORTED = new RawContextKey('debugSetVariableSupported', false, { type: 'boolean', description: nls.localize('debugSetVariableSupported', "True when the focused session supports 'setVariable' request.") }); export const CONTEXT_SET_EXPRESSION_SUPPORTED = new RawContextKey('debugSetExpressionSupported', false, { type: 'boolean', description: nls.localize('debugSetExpressionSupported', "True when the focused session supports 'setExpression' request.") }); From f27886d7d4cba641d8c527a73c4ef16e02049131 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 11:57:58 -0700 Subject: [PATCH 492/599] Document webview view service (#163341) --- .../webviewView/browser/webviewViewService.ts | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewViewService.ts b/src/vs/workbench/contrib/webviewView/browser/webviewViewService.ts index c4ebff8bfee..8d0cb5929d0 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewViewService.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewViewService.ts @@ -10,35 +10,84 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IViewBadge } from 'vs/workbench/common/views'; import { IOverlayWebview } from 'vs/workbench/contrib/webview/browser/webview'; -export const IWebviewViewService = createDecorator('webviewViewService'); - +/** + * A webview shown in a view pane. + */ export interface WebviewView { + /** + * The text displayed in the view's title. + */ title?: string; + + /** + * Additional text shown for this view. + */ description?: string; + + /** + * The badge shown for this view. + */ badge?: IViewBadge; + /** + * The webview associated with this webview view. + */ readonly webview: IOverlayWebview; + /** + * Fired when the visibility of the webview view changes. + * + * This can happen when the view itself is hidden, when the view is collapsed, or when the user switches away from + * the view. + */ readonly onDidChangeVisibility: Event; + + /** + * Fired when the webview view has been disposed of. + */ readonly onDispose: Event; + /** + * Dispose of the webview view and clean up any associated resources. + */ dispose(): void; + /** + * Force the webview view to show. + */ show(preserveFocus: boolean): void; } +/** + * Fill in the contents of a newly created webview view. + */ export interface IWebviewViewResolver { + /** + * Fill in the contents of a webview view. + */ resolve(webviewView: WebviewView, cancellation: CancellationToken): Promise; } +export const IWebviewViewService = createDecorator('webviewViewService'); + export interface IWebviewViewService { readonly _serviceBrand: undefined; + /** + * Fired when a resolver has been registered + */ readonly onNewResolverRegistered: Event<{ readonly viewType: string }>; - register(type: string, resolver: IWebviewViewResolver): IDisposable; + /** + * Register a new {@link IWebviewViewResolver webview view resolver}. + */ + register(viewType: string, resolver: IWebviewViewResolver): IDisposable; + /** + * Try to resolve a webview view. The promise will not resolve until a resolver for the webview has been registered + * and run + */ resolve(viewType: string, webview: WebviewView, cancellation: CancellationToken): Promise; } @@ -48,7 +97,7 @@ export class WebviewViewService extends Disposable implements IWebviewViewServic private readonly _resolvers = new Map(); - private readonly _awaitingRevival = new Map void }>(); + private readonly _awaitingRevival = new Map void }>(); private readonly _onNewResolverRegistered = this._register(new Emitter<{ readonly viewType: string }>()); public readonly onNewResolverRegistered = this._onNewResolverRegistered.event; @@ -90,4 +139,3 @@ export class WebviewViewService extends Disposable implements IWebviewViewServic return resolver.resolve(webview, cancellation); } } - From 34b0554228d7e774fd7c444a74800b6683284563 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 11:58:12 -0700 Subject: [PATCH 493/599] Use `map` instead of objects for storing contributions and actions (#163342) This fixes a typing error where `getAction` could return null, but our types weren't catching this --- src/vs/editor/browser/editorBrowser.ts | 2 +- .../editor/browser/widget/codeEditorWidget.ts | 52 ++++++------------- .../editor/contrib/find/browser/findWidget.ts | 5 +- .../browser/standaloneCodeEditor.ts | 4 +- src/vs/editor/test/browser/testCodeEditor.ts | 2 +- src/vs/monaco.d.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 14 ++--- 7 files changed, 30 insertions(+), 51 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 8acb399f7ce..9f21950587b 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -801,7 +801,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * @id Unique identifier of the contribution. * @return The action or null if action not found. */ - getAction(id: string): editorCommon.IEditorAction; + getAction(id: string): editorCommon.IEditorAction | null; /** * Execute a command on the editor. diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 2872e6be0f0..b851a0e6bd6 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -14,7 +14,7 @@ import { Color } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, EmitterOptions, Event, EventDeliveryQueue } from 'vs/base/common/event'; import { hash } from 'vs/base/common/hash'; -import { Disposable, IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, DisposableStore, DisposableMap } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { EditorConfiguration, IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; @@ -241,8 +241,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _id: number; private readonly _configuration: IEditorConfiguration; - protected _contributions: { [key: string]: editorCommon.IEditorContribution }; - protected _actions: { [key: string]: editorCommon.IEditorAction }; + protected readonly _contributions = new DisposableMap(); + protected readonly _actions = new Map(); // --- Members logically associated to a model protected _modelData: ModelData | null; @@ -318,9 +318,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._modelData = null; - this._contributions = {}; - this._actions = {}; - this._focusTracker = new CodeEditorWidgetFocusTracker(domElement); this._register(this._focusTracker.onChange(() => { this._editorWidgetFocus.setValue(this._focusTracker.hasFocus()); @@ -331,20 +328,20 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const contributions = codeEditorWidgetOptions.contributions ?? EditorExtensionsRegistry.getEditorContributions(); for (const desc of contributions) { - if (this._contributions[desc.id]) { + if (this._contributions.has(desc.id)) { onUnexpectedError(new Error(`Cannot have two contributions with the same id ${desc.id}`)); continue; } try { const contribution = this._instantiationService.createInstance(desc.ctor, this); - this._contributions[desc.id] = contribution; + this._contributions.set(desc.id, contribution); } catch (err) { onUnexpectedError(err); } } for (const action of EditorExtensionsRegistry.getEditorActions()) { - if (this._actions[action.id]) { + if (this._actions.has(action.id)) { onUnexpectedError(new Error(`Cannot have two actions with the same id ${action.id}`)); continue; } @@ -360,7 +357,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE }, this._contextKeyService ); - this._actions[internalAction.id] = internalAction; + this._actions.set(internalAction.id, internalAction); } const isDropIntoEnabled = () => { @@ -424,14 +421,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._codeEditorService.removeCodeEditor(this); this._focusTracker.dispose(); - - const keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - const contributionId = keys[i]; - this._contributions[contributionId].dispose(); - } - this._contributions = {}; - this._actions = {}; + this._contributions.dispose(); + this._actions.clear(); this._contentWidgets = {}; this._overlayWidgets = {}; @@ -996,9 +987,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } const contributionsState: { [key: string]: any } = {}; - const keys = Object.keys(this._contributions); - for (const id of keys) { - const contribution = this._contributions[id]; + for (const [id, contribution] of this._contributions) { if (typeof contribution.saveViewState === 'function') { contributionsState[id] = contribution.saveViewState(); } @@ -1030,10 +1019,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } const contributionsState = codeEditorState.contributionsState || {}; - const keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - const id = keys[i]; - const contribution = this._contributions[id]; + for (const [id, contribution] of this._contributions) { if (typeof contribution.restoreViewState === 'function') { contribution.restoreViewState(contributionsState[id]); } @@ -1054,19 +1040,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public getContribution(id: string): T | null { - return (this._contributions[id] || null); + return (this._contributions.get(id) || null); } public getActions(): editorCommon.IEditorAction[] { - const result: editorCommon.IEditorAction[] = []; - - const keys = Object.keys(this._actions); - for (let i = 0, len = keys.length; i < len; i++) { - const id = keys[i]; - result.push(this._actions[id]); - } - - return result; + return Array.from(this._actions.values()); } public getSupportedActions(): editorCommon.IEditorAction[] { @@ -1077,8 +1055,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return result; } - public getAction(id: string): editorCommon.IEditorAction { - return this._actions[id] || null; + public getAction(id: string): editorCommon.IEditorAction | null { + return this._actions.get(id) || null; } public trigger(source: string | null | undefined, handlerId: string, payload: any): void { diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index 9bb69442edc..72b7ad349e8 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -40,6 +40,7 @@ import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatch import { registerIcon, widgetClose } from 'vs/platform/theme/common/iconRegistry'; import { IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { isHighContrast } from 'vs/platform/theme/common/theme'; +import { assertIsDefined } from 'vs/base/common/types'; const findSelectionIcon = registerIcon('find-selection', Codicon.selection, nls.localize('findSelectionIcon', 'Icon for \'Find in Selection\' in the editor find widget.')); const findCollapsedIcon = registerIcon('find-collapsed', Codicon.chevronRight, nls.localize('findCollapsedIcon', 'Icon to indicate that the editor find widget is collapsed.')); @@ -1033,7 +1034,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction), icon: findPreviousMatchIcon, onTrigger: () => { - this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError); + assertIsDefined(this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction)).run().then(undefined, onUnexpectedError); } })); @@ -1042,7 +1043,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction), icon: findNextMatchIcon, onTrigger: () => { - this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError); + assertIsDefined(this._codeEditor.getAction(FIND_IDS.NextMatchFindAction)).run().then(undefined, onUnexpectedError); } })); diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 614714310e0..8e9a237c5b3 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -372,9 +372,9 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon ); // Store it under the original id, such that trigger with the original id will work - this._actions[id] = internalAction; + this._actions.set(id, internalAction); toDispose.add(toDisposable(() => { - delete this._actions[id]; + this._actions.delete(id); })); return toDispose; diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index bdcc66b5f1e..9fb9e854b35 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -86,7 +86,7 @@ export class TestCodeEditor extends CodeEditorWidget implements ICodeEditor { } public registerAndInstantiateContribution(id: string, ctor: new (editor: ICodeEditor, ...services: BrandedService[]) => T): T { const r: T = this._instantiationService.createInstance(ctor, this); - this._contributions[id] = r; + this._contributions.set(id, r); return r; } public registerDisposable(disposable: IDisposable): void { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index bd49c2c2cea..555ee5b0659 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5347,7 +5347,7 @@ declare namespace monaco.editor { * @id Unique identifier of the contribution. * @return The action or null if action not found. */ - getAction(id: string): IEditorAction; + getAction(id: string): IEditorAction | null; /** * Execute a command on the editor. * The edits will land on the undo-redo stack, but no "undo stop" will be pushed. diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index a1d39f06c68..4e255db9e5f 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { format, compare, splitLines } from 'vs/base/common/strings'; import { extname, basename, isEqual } from 'vs/base/common/resources'; -import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { areFunctions, assertIsDefined, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; import { Language } from 'vs/base/common/platform'; @@ -379,12 +379,12 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const picks: QuickPickInput[] = [ - activeTextEditorControl.getAction(IndentUsingSpaces.ID), - activeTextEditorControl.getAction(IndentUsingTabs.ID), - activeTextEditorControl.getAction(DetectIndentation.ID), - activeTextEditorControl.getAction(IndentationToSpacesAction.ID), - activeTextEditorControl.getAction(IndentationToTabsAction.ID), - activeTextEditorControl.getAction(TrimTrailingWhitespaceAction.ID) + assertIsDefined(activeTextEditorControl.getAction(IndentUsingSpaces.ID)), + assertIsDefined(activeTextEditorControl.getAction(IndentUsingTabs.ID)), + assertIsDefined(activeTextEditorControl.getAction(DetectIndentation.ID)), + assertIsDefined(activeTextEditorControl.getAction(IndentationToSpacesAction.ID)), + assertIsDefined(activeTextEditorControl.getAction(IndentationToTabsAction.ID)), + assertIsDefined(activeTextEditorControl.getAction(TrimTrailingWhitespaceAction.ID)) ].map((a: IEditorAction) => { return { id: a.id, From 864b8b2b6c86b89b444807c00b4084ae743dbd69 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 11 Oct 2022 21:03:05 +0200 Subject: [PATCH 494/599] Fix #163005 (#163339) --- .../extensionManagementServerService.ts | 13 +--- .../remoteExtensionManagementService.ts | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts index 198844be7de..c56e6177daf 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagementServerService, IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { Schemas } from 'vs/base/common/network'; -import { Event } from 'vs/base/common/event'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -15,7 +14,7 @@ import { isWeb } from 'vs/base/common/platform'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WebExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/webExtensionManagementService'; import { IExtension } from 'vs/platform/extensions/common/extensions'; -import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { RemoteExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/remoteExtensionManagementService'; export class ExtensionManagementServerService implements IExtensionManagementServerService { @@ -32,13 +31,7 @@ export class ExtensionManagementServerService implements IExtensionManagementSer ) { const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { - const extensionManagementService = new class extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { - get onProfileAwareInstallExtension() { return super.onInstallExtension; } - get onProfileAwareDidInstallExtensions() { return super.onDidInstallExtensions; } - get onProfileAwareUninstallExtension() { return super.onUninstallExtension; } - get onProfileAwareDidUninstallExtension() { return super.onDidUninstallExtension; } - readonly onDidChangeProfile = Event.None; - }(remoteAgentConnection.getChannel('extensions')); + const extensionManagementService = instantiationService.createInstance(RemoteExtensionManagementService, remoteAgentConnection.getChannel('extensions')); this.remoteExtensionManagementServer = { id: 'remote', extensionManagementService, diff --git a/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts new file mode 100644 index 00000000000..0eb60966707 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { ILocalExtension, IGalleryExtension, InstallOptions, InstallVSIXOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { URI } from 'vs/base/common/uri'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; + +export class RemoteExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { + + readonly onDidChangeProfile = Event.None; + get onProfileAwareInstallExtension() { return super.onInstallExtension; } + get onProfileAwareDidInstallExtensions() { return super.onDidInstallExtensions; } + get onProfileAwareUninstallExtension() { return super.onUninstallExtension; } + get onProfileAwareDidUninstallExtension() { return super.onDidUninstallExtension; } + + constructor( + channel: IChannel, + @IUserDataProfilesService private readonly userDataProfileService: IUserDataProfilesService, + @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, + ) { + super(channel); + } + + override getInstalled(type: ExtensionType | null = null, profileLocation?: URI): Promise { + this.validateProfileLocation({ profileLocation }); + return super.getInstalled(type); + } + + override uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise { + options = this.validateProfileLocation(options); + return super.uninstall(extension, options); + } + + override async install(vsix: URI, options?: InstallVSIXOptions): Promise { + options = this.validateProfileLocation(options); + return super.install(vsix, options); + } + + override async installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise { + options = this.validateProfileLocation(options); + return super.installFromGallery(extension, options); + } + + private validateProfileLocation(options?: T): T | undefined { + if (options?.profileLocation) { + if (!this.uriIdentityService.extUri.isEqual(options?.profileLocation, this.userDataProfileService.defaultProfile.extensionsResource)) { + throw new Error('This opertaion is not supported in remote scenario'); + } + options = { ...options, profileLocation: undefined }; + } + return options; + } + +} From 53785ee45d2a28edae6fa9e777e53bfee3d19947 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 11 Oct 2022 12:39:39 -0700 Subject: [PATCH 495/599] Finalize localization API (#163344) --- .../workbench/api/common/extHost.api.impl.ts | 10 +-- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLocalizationService.ts | 2 +- .../common/extensionsApiProposals.ts | 1 - src/vscode-dts/vscode.d.ts | 72 +++++++++++++++++ .../vscode.proposed.localization.d.ts | 78 ------------------- 6 files changed, 77 insertions(+), 88 deletions(-) delete mode 100644 src/vscode-dts/vscode.proposed.localization.d.ts diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index f03c90350d7..e9ad6e515fd 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1171,14 +1171,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // namespace: l10n const l10n: typeof vscode.l10n = { - t(...params: [message: string, ...args: Array] | [message: string, args: Record] | [{ message: string; args?: Array | Record; comment: string[] }]): string { - checkProposedApiEnabled(extension, 'localization'); - + t(...params: [message: string, ...args: Array] | [message: string, args: Record] | [{ message: string; args?: Array | Record; comment: string | string[] }]): string { if (typeof params[0] === 'string') { const key = params.shift() as string; - // We have either rest args which are Array or an array with a single Record. This ensures we get a - // Record which will be formatted correctly. + // We have either rest args which are Array or an array with a single Record. + // This ensures we get a Record which will be formatted correctly. const argsFormatted = !params || typeof params[0] !== 'object' ? params : params[0]; return extHostLocalization.getMessage(extension.identifier.value, { message: key, args: argsFormatted as Record | undefined }); } @@ -1186,11 +1184,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostLocalization.getMessage(extension.identifier.value, params[0]); }, get bundle() { - checkProposedApiEnabled(extension, 'localization'); return extHostLocalization.getBundle(extension.identifier.value); }, get uri() { - checkProposedApiEnabled(extension, 'localization'); return extHostLocalization.getBundleUri(extension.identifier.value); } }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 21c9fb67dbe..198f8abe670 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2209,7 +2209,7 @@ export interface ExtHostLocalizationShape { export interface IStringDetails { message: string; args?: Record; - comment?: string[]; + comment?: string | string[]; } export interface ITestControllerPatch { diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index 57d41228c5e..e2671689ca6 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -40,7 +40,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { let key = message; if (comment && comment.length > 0) { - key += `/${comment.join()}`; + key += `/${Array.isArray(comment) ? comment.join() : comment}`; } const str = this.bundleCache.get(extensionId)?.contents[key]; if (!str) { diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index d9a2af80b2c..ced11dc2f12 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -38,7 +38,6 @@ export const allApiProposals = Object.freeze({ inlineCompletionsNew: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletionsNew.d.ts', interactiveWindow: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.interactiveWindow.d.ts', ipc: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.ipc.d.ts', - localization: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.localization.d.ts', notebookCellExecutionState: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookCellExecutionState.d.ts', notebookContentProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookContentProvider.d.ts', notebookControllerAffinityHidden: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookControllerAffinityHidden.d.ts', diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index c250e81aa67..8de4fa1ee08 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -15598,6 +15598,78 @@ declare module 'vscode' { export function registerAuthenticationProvider(id: string, label: string, provider: AuthenticationProvider, options?: AuthenticationProviderOptions): Disposable; } + /** + * Namespace for localization-related functionality in the extension API. To use this properly, + * you must have `l10n` defined in your `package.json` and have bundle.l10n..json files. + * For more information on how to generate bundle.l10n..json files, check out the + * [vscode-l10n repo](https://github.com/microsoft/vscode-l10n). + */ + export namespace l10n { + /** + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected {@link args} values for any templated values). + * @param message - The message to localize. Supports index templating where strings like `{0}` and `{1}` are + * replaced by the item at that index in the {@link args} array. + * @param args - The arguments to be used in the localized string. The index of the argument is used to + * match the template placeholder in the localized string. + * @returns localized string with injected arguments. + * @example `l10n.localize('hello', 'Hello {0}!', 'World');` + */ + export function t(message: string, ...args: Array): string; + + /** + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected {@link args} values for any templated values). + * @param message The message to localize. Supports named templating where strings like `{foo}` and `{bar}` are + * replaced by the value in the Record for that key (foo, bar, etc). + * @param args The arguments to be used in the localized string. The name of the key in the record is used to + * match the template placeholder in the localized string. + * @returns localized string with injected arguments. + * @example `l10n.t('Hello {name}', { name: 'Erich' });` + */ + export function t(message: string, args: Record): string; + /** + * Marks a string for localization. If a localized bundle is available for the language specified by + * {@link env.language} and the bundle has a localized value for this message, then that localized + * value will be returned (with injected args values for any templated values). + * @param options The options to use when localizing the message. + * @returns localized string with injected arguments. + */ + export function t(options: { + /** + * The message to localize. If {@link args} is an array, this message supports index templating where strings like + * `{0}` and `{1}` are replaced by the item at that index in the {@link args} array. If `args` is a `Record`, + * this supports named templating where strings like `{foo}` and `{bar}` are replaced by the value in + * the Record for that key (foo, bar, etc). + */ + message: string; + /** + * The arguments to be used in the localized string. As an array, the index of the argument is used to + * match the template placeholder in the localized string. As a Record, the key is used to match the template + * placeholder in the localized string. + */ + args?: Array | Record; + /** + * A comment to help translators understand the context of the message. + */ + comment: string | string[]; + }): string; + /** + * The bundle of localized strings that have been loaded for the extension. + * It's undefined if no bundle has been loaded. The bundle is typically not loaded if + * there was no bundle found or when we are running with the default language. + */ + export const bundle: { [key: string]: string } | undefined; + /** + * The URI of the localization bundle that has been loaded for the extension. + * It's undefined if no bundle has been loaded. The bundle is typically not loaded if + * there was no bundle found or when we are running with the default language. + */ + export const uri: Uri | undefined; + } + /** * Namespace for testing functionality. Tests are published by registering * {@link TestController} instances, then adding {@link TestItem TestItems}. diff --git a/src/vscode-dts/vscode.proposed.localization.d.ts b/src/vscode-dts/vscode.proposed.localization.d.ts deleted file mode 100644 index 5bae5d5b35f..00000000000 --- a/src/vscode-dts/vscode.proposed.localization.d.ts +++ /dev/null @@ -1,78 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - /** - * The namespace for localization-related functionality in the extension API. To use this properly, - * you must have `l10n` defined in your `package.json` and have bundle.l10n..json files. - * For more information on how to generate bundle.l10n..json files, check out the - * [vscode-l10n repo](https://github.com/microsoft/vscode-l10n). - */ - export namespace l10n { - /** - * Marks a string for localization. If a localized bundle is available for the language specified by - * {@link env.language} and the bundle has a localized value for this message, then that localized - * value will be returned (with injected {@link args} values for any templated values). - * @param message The message to localize. Supports index templating where strings like {0} and {1} are - * replaced by the item at that index in the {@link args} array. - * @param args The arguments to be used in the localized string. The index of the argument is used to - * match the template placeholder in the localized string. - * @returns localized string with injected arguments. - * @example l10n.localize('hello', 'Hello {0}!', 'World'); - */ - export function t(message: string, ...args: Array): string; - - /** - * Marks a string for localization. If a localized bundle is available for the language specified by - * {@link env.language} and the bundle has a localized value for this message, then that localized - * value will be returned (with injected {@link args} values for any templated values). - * @param message The message to localize. Supports named templating where strings like {foo} and {bar} are - * replaced by the value in the Record for that key (foo, bar, etc). - * @param args The arguments to be used in the localized string. The name of the key in the record is used to - * match the template placeholder in the localized string. - * @returns localized string with injected arguments. - * @example l10n.t('Hello {name}', { name: 'Erich' }); - */ - export function t(message: string, args: Record): string; - /** - * Marks a string for localization. If a localized bundle is available for the language specified by - * {@link env.language} and the bundle has a localized value for this message, then that localized - * value will be returned (with injected args values for any templated values). - * @param options The options to use when localizing the message. - * @returns localized string with injected arguments. - */ - export function t(options: { - /** - * The message to localize. If {@link args} is an array, this message supports index templating where strings like - * {0} and {1} are replaced by the item at that index in the {@link args} array. If args is a Record, - * this supports named templating where strings like {foo} and {bar} are replaced by the value in - * the Record for that key (foo, bar, etc). - */ - message: string; - /** - * The arguments to be used in the localized string. As an array, the index of the argument is used to - * match the template placeholder in the localized string. As a Record, the key is used to match the template - * placeholder in the localized string. - */ - args?: Array | Record; - /** - * A comment to help translators understand the context of the message. - */ - comment: string[]; - }): string; - /** - * The bundle of localized strings that have been loaded for the extension. - * It's undefined if no bundle has been loaded. The bundle is typically not loaded if - * there was no bundle found or when we are running with the default language. - */ - export const bundle: { [key: string]: string } | undefined; - /** - * The URI of the localization bundle that has been loaded for the extension. - * It's undefined if no bundle has been loaded. The bundle is typically not loaded if - * there was no bundle found or when we are running with the default language. - */ - export const uri: Uri | undefined; - } -} From e814cb5c6557f3d1246d8c79d1c5a0d7bbf9d7dc Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Tue, 11 Oct 2022 15:44:18 -0400 Subject: [PATCH 496/599] Telemetry API (#160902) * First run of scaffolding out a telemetry API * Make telemetry config up to date * Further work on telemetry API * Implement telemetry logging extension host * Add logging to exthost logger * Extract telemetry cleaning * Add data cleaning * Update email regex --- .../environment/common/environment.ts | 1 - .../environment/common/environmentService.ts | 1 - .../telemetry/common/telemetryService.ts | 93 +--------- .../telemetry/common/telemetryUtils.ts | 110 +++++++++++- .../api/browser/mainThreadTelemetry.ts | 18 -- .../workbench/api/common/extHost.api.impl.ts | 15 +- .../api/common/extHost.common.services.ts | 2 - .../workbench/api/common/extHost.protocol.ts | 1 - .../workbench/api/common/extHostTelemetry.ts | 163 +++++++++++++++++- .../api/common/extHostTelemetryLogService.ts | 34 ---- .../contrib/logs/common/logs.contribution.ts | 2 +- .../environment/browser/environmentService.ts | 5 + .../environment/common/environmentService.ts | 1 + .../electron-sandbox/environmentService.ts | 6 + .../browser/webWorkerExtensionHost.ts | 1 + .../common/extensionHostProtocol.ts | 1 + .../common/extensionsApiProposals.ts | 2 +- .../extensions/common/remoteExtensionHost.ts | 1 + .../localProcessExtensionHost.ts | 1 + .../vscode.proposed.telemetryLog.d.ts | 19 -- .../vscode.proposed.telemetryLogger.d.ts | 81 +++++++++ 21 files changed, 375 insertions(+), 183 deletions(-) delete mode 100644 src/vs/workbench/api/common/extHostTelemetryLogService.ts delete mode 100644 src/vscode-dts/vscode.proposed.telemetryLog.d.ts create mode 100644 src/vscode-dts/vscode.proposed.telemetryLogger.d.ts diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 38045ace24e..8ecac574e85 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -87,7 +87,6 @@ export interface IEnvironmentService { // --- telemetry disableTelemetry: boolean; telemetryLogResource: URI; - extensionTelemetryLogResource: URI; serviceMachineIdResource: URI; // --- Policy diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index 82b280f08d3..8ff58181a62 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -226,7 +226,6 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron @memoize get telemetryLogResource(): URI { return URI.file(join(this.logsPath, 'telemetry.log')); } - get extensionTelemetryLogResource(): URI { return URI.file(join(this.logsPath, 'extensionTelemetry.log')); } get disableTelemetry(): boolean { return !!this.args['disable-telemetry']; } @memoize diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 3a9107bead0..a2c2152f7b8 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { DisposableStore } from 'vs/base/common/lifecycle'; -import { cloneAndChange, mixin } from 'vs/base/common/objects'; +import { mixin } from 'vs/base/common/objects'; import { MutableObservableValue } from 'vs/base/common/observableValue'; import { isWeb } from 'vs/base/common/platform'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; @@ -16,7 +16,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { Registry } from 'vs/platform/registry/common/platform'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SECTION_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; -import { getTelemetryLevel, ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils'; +import { cleanData, getTelemetryLevel, ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils'; export interface ITelemetryServiceConfig { appenders: ITelemetryAppender[]; @@ -117,12 +117,7 @@ export class TelemetryService implements ITelemetryService { data = mixin(data, this._experimentProperties); // (last) remove all PII from data - data = cloneAndChange(data, value => { - if (typeof value === 'string') { - return this._cleanupInfo(value, anonymizeFilePaths); - } - return undefined; - }); + data = cleanData(data as Record, this._cleanupPatterns); // Log to the appenders of sufficient level this._appenders.forEach(a => a.log(eventName, data)); @@ -153,88 +148,6 @@ export class TelemetryService implements ITelemetryService { publicLogError2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): Promise { return this.publicLogError(eventName, data as ITelemetryData); } - - private _anonymizeFilePaths(stack: string): string { - let updatedStack = stack; - - const cleanUpIndexes: [number, number][] = []; - for (const regexp of this._cleanupPatterns) { - while (true) { - const result = regexp.exec(stack); - if (!result) { - break; - } - cleanUpIndexes.push([result.index, regexp.lastIndex]); - } - } - - const nodeModulesRegex = /^[\\\/]?(node_modules|node_modules\.asar)[\\\/]/; - const fileRegex = /(file:\/\/)?([a-zA-Z]:(\\\\|\\|\/)|(\\\\|\\|\/))?([\w-\._]+(\\\\|\\|\/))+[\w-\._]*/g; - let lastIndex = 0; - updatedStack = ''; - - while (true) { - const result = fileRegex.exec(stack); - if (!result) { - break; - } - // Anoynimize user file paths that do not need to be retained or cleaned up. - if (!nodeModulesRegex.test(result[0]) && cleanUpIndexes.every(([x, y]) => result.index < x || result.index >= y)) { - updatedStack += stack.substring(lastIndex, result.index) + ''; - lastIndex = fileRegex.lastIndex; - } - } - if (lastIndex < stack.length) { - updatedStack += stack.substr(lastIndex); - } - - return updatedStack; - } - - private _removePropertiesWithPossibleUserInfo(property: string): string { - // If for some reason it is undefined we skip it (this shouldn't be possible); - if (!property) { - return property; - } - - const value = property.toLowerCase(); - - const userDataRegexes = [ - { label: 'Google API Key', regex: /AIza[A-Za-z0-9_\\\-]{35}/ }, - { label: 'Slack Token', regex: /xox[pbar]\-[A-Za-z0-9]/ }, - { label: 'Generic Secret', regex: /(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]/ }, - { label: 'Email', regex: /@[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+/ } // Regex which matches *@*.site - ]; - - // Check for common user data in the telemetry events - for (const secretRegex of userDataRegexes) { - if (secretRegex.regex.test(value)) { - return ``; - } - } - - return property; - } - - - private _cleanupInfo(property: string, anonymizeFilePaths?: boolean): string { - let updatedProperty = property; - - // anonymize file paths - if (anonymizeFilePaths) { - updatedProperty = this._anonymizeFilePaths(updatedProperty); - } - - // sanitize with configured cleanup patterns - for (const regexp of this._cleanupPatterns) { - updatedProperty = updatedProperty.replace(regexp, ''); - } - - // remove possible user info - updatedProperty = this._removePropertiesWithPossibleUserInfo(updatedProperty); - - return updatedProperty; - } } function getTelemetryLevelSettingDescription(): string { diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index fd8e1a4f972..1f2044b947e 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable } from 'vs/base/common/lifecycle'; -import { safeStringify } from 'vs/base/common/objects'; +import { cloneAndChange, safeStringify } from 'vs/base/common/objects'; import { staticObservableValue } from 'vs/base/common/observableValue'; import { isObject } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -191,7 +191,7 @@ export function validateTelemetryData(data?: any): { properties: Properties; mea }; } -const telemetryAllowedAuthorities: readonly string[] = ['ssh-remote', 'dev-container', 'attached-container', 'wsl', 'tunneling']; +const telemetryAllowedAuthorities: readonly string[] = ['ssh-remote', 'dev-container', 'attached-container', 'wsl', 'tunneling', 'codespaces']; export function cleanRemoteAuthority(remoteAuthority?: string): string { if (!remoteAuthority) { @@ -276,3 +276,109 @@ interface IPathEnvironment { export function getPiiPathsFromEnvironment(paths: IPathEnvironment): string[] { return [paths.appRoot, paths.extensionsPath, paths.userHome.fsPath, paths.tmpDir.fsPath, paths.userDataPath]; } + +//#region Telemetry Cleaning + +/** + * Cleans a given stack of possible paths + * @param stack The stack to sanitize + * @param cleanupPatterns Cleanup patterns to remove from the stack + * @returns The cleaned stack + */ +function anonymizeFilePaths(stack: string, cleanupPatterns: RegExp[]): string { + let updatedStack = stack; + + const cleanUpIndexes: [number, number][] = []; + for (const regexp of cleanupPatterns) { + while (true) { + const result = regexp.exec(stack); + if (!result) { + break; + } + cleanUpIndexes.push([result.index, regexp.lastIndex]); + } + } + + const nodeModulesRegex = /^[\\\/]?(node_modules|node_modules\.asar)[\\\/]/; + const fileRegex = /(file:\/\/)?([a-zA-Z]:(\\\\|\\|\/)|(\\\\|\\|\/))?([\w-\._]+(\\\\|\\|\/))+[\w-\._]*/g; + let lastIndex = 0; + updatedStack = ''; + + while (true) { + const result = fileRegex.exec(stack); + if (!result) { + break; + } + // Anoynimize user file paths that do not need to be retained or cleaned up. + if (!nodeModulesRegex.test(result[0]) && cleanUpIndexes.every(([x, y]) => result.index < x || result.index >= y)) { + updatedStack += stack.substring(lastIndex, result.index) + ''; + lastIndex = fileRegex.lastIndex; + } + } + if (lastIndex < stack.length) { + updatedStack += stack.substr(lastIndex); + } + + return updatedStack; +} + +/** + * Attempts to remove commonly leaked PII + * @param property The property which will be removed if it contains user data + * @returns The new value for the property + */ +function removePropertiesWithPossibleUserInfo(property: string): string { + // If for some reason it is undefined we skip it (this shouldn't be possible); + if (!property) { + return property; + } + + const value = property.toLowerCase(); + + const userDataRegexes = [ + { label: 'Google API Key', regex: /AIza[A-Za-z0-9_\\\-]{35}/ }, + { label: 'Slack Token', regex: /xox[pbar]\-[A-Za-z0-9]/ }, + { label: 'Generic Secret', regex: /(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]/ }, + { label: 'Email', regex: /@[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+/ } // Regex which matches @*.site + ]; + + // Check for common user data in the telemetry events + for (const secretRegex of userDataRegexes) { + if (secretRegex.regex.test(value)) { + return ``; + } + } + + return property; +} + + +/** + * Does a best possible effort to clean a data object from any possible PII. + * @param data The data object to clean + * @param paths Any additional patterns that should be removed from the data set + * @returns A new object with the PII removed + */ +export function cleanData(data: Record, cleanUpPatterns: RegExp[]): Record { + return cloneAndChange(data, value => { + // We only know how to clean strings + if (typeof value === 'string') { + let updatedProperty = value; + // First we anonymize any possible file paths + updatedProperty = anonymizeFilePaths(updatedProperty, cleanUpPatterns); + + // Then we do a simple regex replace with the defined patterns + for (const regexp of cleanUpPatterns) { + updatedProperty = updatedProperty.replace(regexp, ''); + } + + // Lastly, remove commonly leaked PII + updatedProperty = removePropertiesWithPossibleUserInfo(updatedProperty); + + return updatedProperty; + } + return undefined; + }); +} + +//#endregion diff --git a/src/vs/workbench/api/browser/mainThreadTelemetry.ts b/src/vs/workbench/api/browser/mainThreadTelemetry.ts index acb2067b0c8..1d5ba159d83 100644 --- a/src/vs/workbench/api/browser/mainThreadTelemetry.ts +++ b/src/vs/workbench/api/browser/mainThreadTelemetry.ts @@ -5,7 +5,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; @@ -19,26 +18,14 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet private static readonly _name = 'pluginHostTelemetry'; - private readonly _extensionTelemetryLog: ILogger; - constructor( extHostContext: IExtHostContext, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @IProductService private readonly _productService: IProductService, - @ILoggerService loggerService: ILoggerService, ) { super(); - const logger = loggerService.getLogger(this._environmentService.extensionTelemetryLogResource); - if (logger) { - this._extensionTelemetryLog = this._register(logger); - } else { - this._extensionTelemetryLog = this._register(loggerService.createLogger(this._environmentService.extensionTelemetryLogResource)); - this._extensionTelemetryLog.info('Below are logs for extension telemetry events sent to the telemetry output channel API once the log level is set to trace.'); - this._extensionTelemetryLog.info('==========================================================='); - } - this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTelemetry); if (supportsTelemetry(this._productService, this._environmentService)) { @@ -67,11 +54,6 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet $publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void { this.$publicLog(eventName, data as any); } - - $logTelemetryToOutputChannel(eventName: string, data: Record) { - this._extensionTelemetryLog.trace(eventName, data); - this._extensionTelemetryLog.flush(); - } } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index e9ad6e515fd..d11207c6384 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -80,7 +80,7 @@ import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting'; import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener'; import { IExtHostSecretState } from 'vs/workbench/api/common/extHostSecretState'; import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; -import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; +import { IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry'; import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes'; import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers'; @@ -92,7 +92,6 @@ import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive'; import { combinedDisposable } from 'vs/base/common/lifecycle'; import { checkProposedApiEnabled, ExtensionIdentifierSet, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug'; -import { IExtHostTelemetryLogService } from 'vs/workbench/api/common/extHostTelemetryLogService'; import { IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService'; export interface IExtensionRegistries { @@ -124,7 +123,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostLoggerService = accessor.get(ILoggerService); const extHostLogService = accessor.get(ILogService); const extHostTunnelService = accessor.get(IExtHostTunnelService); - const extHostTelemetryLogService = accessor.get(IExtHostTelemetryLogService); const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService); const extHostWindow = accessor.get(IExtHostWindow); const extHostSecretState = accessor.get(IExtHostSecretState); @@ -330,8 +328,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostTelemetry.onDidChangeTelemetryConfiguration; }, get isNewAppInstall() { - const installAge = Date.now() - new Date(initData.telemetryInfo.firstSessionDate).getTime(); - return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // install age is less than a day + return isNewAppInstall(initData.telemetryInfo.firstSessionDate); + }, + createTelemetryLogger(appender: vscode.TelemetryAppender): vscode.TelemetryLogger { + checkProposedApiEnabled(extension, 'telemetry'); + return extHostTelemetry.instantiateLogger(extension, appender); }, openExternal(uri: URI, options?: { allowContributedOpeners?: boolean | string }) { return extHostWindow.openUri(uri, { @@ -796,10 +797,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, get tabGroups(): vscode.TabGroups { return extHostEditorTabs.tabGroups; - }, - logTelemetryToOutputChannel(eventName: string, data: Record): void { - checkProposedApiEnabled(extension, 'telemetryLog'); - extHostTelemetryLogService.logToTelemetryOutputChannel(extension, eventName, data); } }; diff --git a/src/vs/workbench/api/common/extHost.common.services.ts b/src/vs/workbench/api/common/extHost.common.services.ts index f00aebebc47..f5e48cd8854 100644 --- a/src/vs/workbench/api/common/extHost.common.services.ts +++ b/src/vs/workbench/api/common/extHost.common.services.ts @@ -27,7 +27,6 @@ import { ExtHostLoggerService } from 'vs/workbench/api/common/extHostLoggerServi import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService'; import { ExtHostVariableResolverProviderService, IExtHostVariableResolverProvider } from 'vs/workbench/api/common/extHostVariableResolverService'; -import { ExtHostTelemetryLogService, IExtHostTelemetryLogService } from 'vs/workbench/api/common/extHostTelemetryLogService'; import { ExtHostLocalizationService, IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService'; registerSingleton(IExtHostLocalizationService, ExtHostLocalizationService, InstantiationType.Delayed); @@ -51,6 +50,5 @@ registerSingleton(IExtHostWindow, ExtHostWindow, false); registerSingleton(IExtHostWorkspace, ExtHostWorkspace, false); registerSingleton(IExtHostSecretState, ExtHostSecretState, false); registerSingleton(IExtHostTelemetry, ExtHostTelemetry, false); -registerSingleton(IExtHostTelemetryLogService, ExtHostTelemetryLogService, false); registerSingleton(IExtHostEditorTabs, ExtHostEditorTabs, false); registerSingleton(IExtHostVariableResolverProvider, ExtHostVariableResolverProviderService, false); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 198f8abe670..86f58713afb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -598,7 +598,6 @@ export interface MainThreadStorageShape extends IDisposable { export interface MainThreadTelemetryShape extends IDisposable { $publicLog(eventName: string, data?: any): void; $publicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void; - $logTelemetryToOutputChannel(eventName: string, data: Record): void; } export interface MainThreadEditorInsetsShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index d27d0a9047d..47940f571d5 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -3,28 +3,48 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import type * as vscode from 'vscode'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { ExtHostTelemetryShape } from 'vs/workbench/api/common/extHost.protocol'; import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; -import type { TelemetryConfiguration } from 'vscode'; +import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; +import { cleanData, cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; +import { mixin } from 'vs/base/common/objects'; +import { URI } from 'vs/base/common/uri'; export class ExtHostTelemetry implements ExtHostTelemetryShape { private readonly _onDidChangeTelemetryEnabled = new Emitter(); readonly onDidChangeTelemetryEnabled: Event = this._onDidChangeTelemetryEnabled.event; - private readonly _onDidChangeTelemetryConfiguration = new Emitter(); - readonly onDidChangeTelemetryConfiguration: Event = this._onDidChangeTelemetryConfiguration.event; + private readonly _onDidChangeTelemetryConfiguration = new Emitter(); + readonly onDidChangeTelemetryConfiguration: Event = this._onDidChangeTelemetryConfiguration.event; private _productConfig: { usage: boolean; error: boolean } = { usage: true, error: true }; private _level: TelemetryLevel = TelemetryLevel.NONE; private _oldTelemetryEnablement: boolean | undefined; + private readonly _outputLogger: ILogger; + private readonly _telemetryLoggers = new Map(); + + constructor( + @IExtHostInitDataService private readonly initData: IExtHostInitDataService, + @ILoggerService loggerService: ILoggerService, + ) { + console.log(this.initData.environment.extensionTelemetryLogResource); + this._outputLogger = loggerService.createLogger(URI.revive(this.initData.environment.extensionTelemetryLogResource)); + this._outputLogger.info('Below are logs for extension telemetry events sent to the telemetry output channel API once the log level is set to trace.'); + this._outputLogger.info('==========================================================='); + } getTelemetryConfiguration(): boolean { return this._level === TelemetryLevel.USAGE; } - getTelemetryDetails(): TelemetryConfiguration { + getTelemetryDetails(): vscode.TelemetryConfiguration { return { isCrashEnabled: this._level >= TelemetryLevel.CRASH, isErrorsEnabled: this._productConfig.error ? this._level >= TelemetryLevel.ERROR : false, @@ -32,14 +52,56 @@ export class ExtHostTelemetry implements ExtHostTelemetryShape { }; } + instantiateLogger(extension: IExtensionDescription, appender: vscode.TelemetryAppender) { + const telemetryDetails = this.getTelemetryDetails(); + const logger = new ExtHostTelemetryLogger(appender, extension, this._outputLogger, this.getBuiltInCommonProperties(extension), { isUsageEnabled: telemetryDetails.isUsageEnabled, isErrorsEnabled: telemetryDetails.isErrorsEnabled }); + this._telemetryLoggers.set(extension.identifier.value, logger); + return logger.apiTelemetryLogger; + } + $initializeTelemetryLevel(level: TelemetryLevel, productConfig?: { usage: boolean; error: boolean }): void { this._level = level; this._productConfig = productConfig || { usage: true, error: true }; } + getBuiltInCommonProperties(extension: IExtensionDescription): Record { + const commonProperties: Record = {}; + // TODO @lramos15, does os info like node arch, platform version, etc exist here. + // Or will first party extensions just mix this in + commonProperties['common.extname'] = extension.name; + commonProperties['common.extversion'] = extension.version; + commonProperties['common.vscodemachineid'] = this.initData.telemetryInfo.machineId; + commonProperties['common.vscodesessionid'] = this.initData.telemetryInfo.sessionId; + commonProperties['common.vscodeversion'] = this.initData.version; + commonProperties['common.isnewappinstall'] = isNewAppInstall(this.initData.telemetryInfo.firstSessionDate); + commonProperties['common.product'] = this.initData.environment.appHost; + + switch (this.initData.uiKind) { + case UIKind.Web: + commonProperties['common.uikind'] = 'web'; + break; + case UIKind.Desktop: + commonProperties['common.uikind'] = 'desktop'; + break; + default: + commonProperties['common.uikind'] = 'unknown'; + } + + commonProperties['common.remotename'] = getRemoteName(cleanRemoteAuthority(this.initData.remote.authority)); + + return commonProperties; + } + $onDidChangeTelemetryLevel(level: TelemetryLevel): void { this._oldTelemetryEnablement = this.getTelemetryConfiguration(); this._level = level; + const telemetryDetails = this.getTelemetryDetails(); + + // Loop through all loggers and update their level + this._telemetryLoggers.forEach(logger => { + logger.updateTelemetryEnablements(telemetryDetails.isUsageEnabled, telemetryDetails.isErrorsEnabled); + }); + if (this._oldTelemetryEnablement !== this.getTelemetryConfiguration()) { this._onDidChangeTelemetryEnabled.fire(this.getTelemetryConfiguration()); } @@ -47,5 +109,98 @@ export class ExtHostTelemetry implements ExtHostTelemetryShape { } } +export class ExtHostTelemetryLogger { + private _appender: vscode.TelemetryAppender; + private readonly _onDidChangeEnableStates = new Emitter(); + private _telemetryEnablements: { isUsageEnabled: boolean; isErrorsEnabled: boolean }; + private _apiObject: vscode.TelemetryLogger | undefined; + constructor( + appender: vscode.TelemetryAppender, + private readonly _extension: IExtensionDescription, + private readonly _logger: ILogger, + private readonly _commonProperties: Record, + telemetryEnablements: { isUsageEnabled: boolean; isErrorsEnabled: boolean }) { + this._appender = appender; + this._telemetryEnablements = { isUsageEnabled: telemetryEnablements.isUsageEnabled, isErrorsEnabled: telemetryEnablements.isErrorsEnabled }; + } + + updateTelemetryEnablements(isUsageEnabled: boolean, isErrorsEnabled: boolean): void { + if (this._apiObject) { + this._telemetryEnablements = { isUsageEnabled, isErrorsEnabled }; + this._onDidChangeEnableStates.fire(this._apiObject); + } + } + + mixInCommonPropsAndCleanData(data: Record): Record { + if (!this._appender.ignoreBuiltInCommonProperties) { + data = mixin(data, this._commonProperties); + } + if (this._appender.additionalCommonProperties) { + data = mixin(data, this._appender.additionalCommonProperties); + } + + data = cleanData(data, []); + + return data; + } + + private logEvent(eventName: string, data?: Record): void { + eventName = this._extension.identifier.value + '/' + eventName; + data = this.mixInCommonPropsAndCleanData(data || {}); + this._appender.logEvent(eventName, data); + this._logger.trace(eventName, data); + } + + logUsage(eventName: string, data?: Record): void { + if (!this._telemetryEnablements.isUsageEnabled) { + return; + } + this.logEvent(eventName, data); + } + + logError(eventNameOrException: Error | string, data?: Record): void { + if (!this._telemetryEnablements.isErrorsEnabled) { + return; + } + if (typeof eventNameOrException === 'string') { + this.logEvent(eventNameOrException, data); + } else { + // TODO @lramos15, implement cleaning for and logging for this case + this._appender.logException(eventNameOrException, data); + } + } + + get apiTelemetryLogger(): vscode.TelemetryLogger { + if (!this._apiObject) { + const that = this; + const obj: vscode.TelemetryLogger = { + logUsage: that.logUsage, + get isUsageEnabled() { + return that._telemetryEnablements.isUsageEnabled; + }, + get isErrorsEnabled() { + return that._telemetryEnablements.isErrorsEnabled; + }, + logError: that.logError, + dispose: that.dispose, + onDidChangeEnableStates: that._onDidChangeEnableStates.event + }; + this._apiObject = Object.freeze(obj); + } + return this._apiObject; + } + + dispose(): void { + if (this._appender?.flush) { + this._appender.flush(); + } + } +} + +export function isNewAppInstall(firstSessionDate: string): boolean { + const installAge = Date.now() - new Date(firstSessionDate).getTime(); + return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // install age is less than a day +} + export const IExtHostTelemetry = createDecorator('IExtHostTelemetry'); export interface IExtHostTelemetry extends ExtHostTelemetry, ExtHostTelemetryShape { } diff --git a/src/vs/workbench/api/common/extHostTelemetryLogService.ts b/src/vs/workbench/api/common/extHostTelemetryLogService.ts deleted file mode 100644 index e55fcb27b4c..00000000000 --- a/src/vs/workbench/api/common/extHostTelemetryLogService.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; - -export interface IExtHostTelemetryLogService { - readonly _serviceBrand: undefined; - - logToTelemetryOutputChannel(extension: IExtensionDescription, eventName: string, data: Record): void; -} - -export const IExtHostTelemetryLogService = createDecorator('IExtHostTelemetryLogService'); - -export class ExtHostTelemetryLogService implements IExtHostTelemetryLogService { - - declare readonly _serviceBrand: undefined; - - private readonly _telemetryShape: extHostProtocol.MainThreadTelemetryShape; - - constructor( - @IExtHostRpcService rpc: IExtHostRpcService, - ) { - this._telemetryShape = rpc.getProxy(extHostProtocol.MainContext.MainThreadTelemetry); - } - - public logToTelemetryOutputChannel(extension: IExtensionDescription, eventName: string, data: Record): void { - this._telemetryShape.$logTelemetryToOutputChannel(`${extension.identifier.value}/${eventName}`, data); - } -} diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 3cd2ad0dd85..ee34e86d564 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -55,7 +55,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { const registerTelemetryChannel = () => { if (supportsTelemetry(this.productService, this.environmentService) && this.logService.getLevel() === LogLevel.Trace) { this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), this.environmentService.telemetryLogResource); - this.registerLogChannel(Constants.extensionTelemetryLogChannelId, nls.localize('extensionTelemetryLog', "Extension Telemetry"), this.environmentService.extensionTelemetryLogResource); + this.registerLogChannel(Constants.extensionTelemetryLogChannelId, nls.localize('extensionTelemetryLog', "Extension Telemetry"), this.environmentService.extHostTelemetryLogFile); return true; } return false; diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 372ac7bb167..b4babc0fae6 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -101,6 +101,11 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi @memoize get extHostLogsPath(): URI { return joinPath(this.logsHome, 'exthost'); } + @memoize + get extHostTelemetryLogFile(): URI { + return joinPath(this.extHostLogsPath, 'telemetry.log'); + } + private extensionHostDebugEnvironment: IExtensionHostDebugEnvironment | undefined = undefined; @memoize diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index de37a985f17..c922bb63859 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -25,6 +25,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService { // --- Paths readonly logFile: URI; readonly extHostLogsPath: URI; + readonly extHostTelemetryLogFile: URI; // --- Extensions readonly extensionEnabledProposedApi?: string[]; diff --git a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts index a18fa598d41..1d1498d1c4a 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts @@ -14,6 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { join } from 'vs/base/common/path'; import { IProductService } from 'vs/platform/product/common/productService'; +import { joinPath } from 'vs/base/common/resources'; export const INativeWorkbenchEnvironmentService = refineServiceDecorator(IEnvironmentService); @@ -90,6 +91,11 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment @memoize get extHostLogsPath(): URI { return URI.file(join(this.logsPath, `exthost${this.configuration.windowId}`)); } + @memoize + get extHostTelemetryLogFile(): URI { + return joinPath(this.extHostLogsPath, 'telemetry.log'); + } + @memoize get webviewExternalEndpoint(): string { return `${Schemas.vscodeWebview}://{{uuid}}`; } diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 2c35ebcfaa6..0b6d5e5e3d1 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -293,6 +293,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost appHost: this._productService.embedderIdentifier ?? (platform.isWeb ? 'web' : 'desktop'), appUriScheme: this._productService.urlProtocol, appLanguage: platform.language, + extensionTelemetryLogResource: this._environmentService.extHostTelemetryLogFile, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._userDataProfilesService.defaultProfile.globalStorageHome, diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index 0f5865d1100..1e854a7f16a 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -46,6 +46,7 @@ export interface IEnvironment { appHost: string; appRoot?: URI; appLanguage: string; + extensionTelemetryLogResource: URI; appUriScheme: string; extensionDevelopmentLocationURI?: URI[]; extensionTestsLocationURI?: URI; diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index ced11dc2f12..b0c572aeeea 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -58,7 +58,7 @@ export const allApiProposals = Object.freeze({ tabInputTextMerge: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts', taskPresentationGroup: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts', telemetry: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts', - telemetryLog: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetryLog.d.ts', + telemetryLogger: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts', terminalDataWriteEvent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts', terminalDimensions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDimensions.d.ts', testCoverage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testCoverage.d.ts', diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 62eea683c18..ae69e5945ea 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -221,6 +221,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { appName: this._productService.nameLong, appHost: this._productService.embedderIdentifier || 'desktop', appUriScheme: this._productService.urlProtocol, + extensionTelemetryLogResource: this._environmentService.extHostTelemetryLogFile, appLanguage: platform.language, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index 8d240be7670..b5df3055356 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -444,6 +444,7 @@ export class SandboxLocalProcessExtensionHost implements IExtensionHost { appName: this._productService.nameLong, appHost: this._productService.embedderIdentifier || 'desktop', appUriScheme: this._productService.urlProtocol, + extensionTelemetryLogResource: this._environmentService.extHostTelemetryLogFile, appLanguage: platform.language, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, diff --git a/src/vscode-dts/vscode.proposed.telemetryLog.d.ts b/src/vscode-dts/vscode.proposed.telemetryLog.d.ts deleted file mode 100644 index 962016a02d8..00000000000 --- a/src/vscode-dts/vscode.proposed.telemetryLog.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - export namespace window { - /** - * Logs a telemetry event to a shared extension output channel when the log level is set to trace. - * This is similar in function to cores' telemetry output channel that can be seen when log level is set to trace. - * Extension authors should only log to the output channel when sending telemetry. - * - * @param eventName The name of the telemetry event - * @param data The data associated with the telemetry event - */ - export function logTelemetryToOutputChannel(eventName: string, data: Record): void; - } -} diff --git a/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts b/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts new file mode 100644 index 00000000000..dfd38a77dd8 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + export interface TelemetryLogger { + //TODO feels weird having this on all loggers + readonly onDidChangeEnableStates: Event; + readonly isUsageEnabled: boolean; + readonly isErrorsEnabled: boolean; + + /** + * After completing cleaning, telemetry setting checks, and data mix-in calls `TelemetryAppender.logEvent` to log the event. + * Automatically supports echoing to extension telemetry output channel. + * @param eventName The event name to log + * @param data The data to log + */ + logUsage(eventName: string, data?: Record): void; + + /** + * After completing cleaning, telemetry setting checks, and data mix-in calls `TelemetryAppender.logEvent` to log the event. Differs from `logUsage` in that it will log the event if the telemetry setting is Error+. + * Automatically supports echoing to extension telemetry output channel. + * @param eventName The event name to log + * @param data The data to log + */ + logError(eventName: string, data?: Record): void; + + /** + * Calls `TelemetryAppender.logException`. Does cleaning, telemetry checks, and data mix-in. + * Automatically supports echoing to extension telemetry output channel. + * Will also automatically log any exceptions thrown within the extension host process. + * @param exception The error object which contains the stack trace cleaned of PII + * @param data Additional data to log alongside the stack trace + */ + logError(exception: Error, data?: Record): void; + + dispose(): void; + } + + export interface TelemetryAppender { + /** + * Whether or not you want to avoid having the built-in common properties such as os, extension name, etc injected into the data object. + */ + readonly ignoreBuiltInCommonProperties: boolean; + + /** + * Any additional common properties which should be injected into the data object. + */ + readonly additionalCommonProperties: Record; + + /** + * User-defined function which logs an event, used within the TelemetryLogger + * @param eventName The name of the event which you are logging + * @param data A serializable key value pair that is being logged + */ + logEvent(eventName: string, data?: Record): void; + + /** + * User-defined function which logs an error, used within the TelemetryLogger + * @param exception The exception being logged + * @param data Any additional data to be collected with the exception + */ + logException(exception: Error, data?: Record): void; + + /** + * Optional flush function which will give your appender one last chance to send any remaining events as the TelemetryLogger is being disposed + */ + flush?(): void | Thenable; + } + + export namespace env { + /** + * A wrapper around a TelemetryAppender which provides built-in setting checks, common properties, data cleaning, output channel logging, and internal ext host process exception catching. + * @param appender The core piece which we call when it is time to log telemetry. It is highly recommended that you don't call the methods within the appender directly as the logger provides extra guards and cleaning. + * @returns An instantiated telemetry logger which you can use for recording telemetry + */ + export function createTelemetryLogger(appender: TelemetryAppender): TelemetryLogger; + } +} From f5047cb4f00ad7f6f3910f294b6d0a7680cb3a08 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 11 Oct 2022 12:55:49 -0700 Subject: [PATCH 497/599] Fix build (#163347) --- .../contrib/debug/browser/debugEditorContribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 2aaa13d034a..423a4d430e6 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -223,8 +223,8 @@ export class LazyDebugEditorContribution extends Disposable implements IDebugEdi }); } - showHover(range: Range, focus: boolean): Promise { - return this._contrib ? this._contrib.showHover(range, focus) : Promise.resolve(); + showHover(position: Position, focus: boolean): Promise { + return this._contrib ? this._contrib.showHover(position, focus) : Promise.resolve(); } addLaunchConfiguration(): Promise { From 4322170fd89b442f9d24d3b43e8e1ec48707a4b4 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 11 Oct 2022 13:39:12 -0700 Subject: [PATCH 498/599] comment is an array (#163348) --- .../typescript-language-features/package.nls.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 49291d123ba..89e7a9216ac 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -86,29 +86,29 @@ "inlayHints.parameterNames.all": "Enable parameter name hints for literal and non-literal arguments.", "configuration.inlayHints.parameterNames.enabled": { "message": "Enable/disable inlay hints for parameter names:\n```typescript\n\nparseInt(/* str: */ '123', /* radix: */ 8)\n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "configuration.inlayHints.parameterNames.suppressWhenArgumentMatchesName": "Suppress parameter name hints on arguments whose text is identical to the parameter name.", "configuration.inlayHints.parameterTypes.enabled": { "message": "Enable/disable inlay hints for implicit parameter types:\n```typescript\n\nel.addEventListener('click', e /* :MouseEvent */ => ...)\n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "configuration.inlayHints.variableTypes.enabled": { "message": "Enable/disable inlay hints for implicit variable types:\n```typescript\n\nconst foo /* :number */ = Date.now();\n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "configuration.inlayHints.variableTypes.suppressWhenTypeMatchesName": "Suppress type hints on variables whose name is identical to the type name. Requires using TypeScript 4.8+ in the workspace.", "configuration.inlayHints.propertyDeclarationTypes.enabled": { "message": "Enable/disable inlay hints for implicit types on property declarations:\n```typescript\n\nclass Foo {\n\tprop /* :number */ = Date.now();\n}\n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "configuration.inlayHints.functionLikeReturnTypes.enabled": { "message": "Enable/disable inlay hints for implicit return types on function signatures:\n```typescript\n\nfunction foo() /* :number */ {\n\treturn Date.now();\n} \n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "configuration.inlayHints.enumMemberValues.enabled": { "message": "Enable/disable inlay hints for member values in enum declarations:\n```typescript\n\nenum MyValue {\n\tA /* = 0 */;\n\tB /* = 1 */;\n}\n \n```\nRequires using TypeScript 4.4+ in the workspace.", - "comment": "The text inside the ``` block is code and should not be localized." + "comment": ["The text inside the ``` block is code and should not be localized."] }, "taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.", "javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.", From 43957ccfe1d7f387def153528812e5b513c7f11c Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 12 Oct 2022 08:43:46 +1100 Subject: [PATCH 499/599] Compress streams in notebook outputs (#160946) * Revert "Compress notebook output streams before rendering (#160667)" This reverts commit 4230c22a08a0438af4809d33e4cfd561f714b127. * Compress stream output items * Minor perf improvements * Misc * Comments * Added tests * Merge issue * More merge issues * Misc * Address code review comments --- extensions/ipynb/src/serializers.ts | 27 +++-- extensions/ipynb/src/streamCompressor.ts | 63 ----------- .../api/common/extHostNotebookDocument.ts | 26 +++++ .../api/test/browser/extHostNotebook.test.ts | 75 ++++++++++++- .../view/renderers/backLayerWebView.ts | 9 +- .../view/renderers/stdOutErrorPreProcessor.ts | 56 --------- .../common/model/notebookCellTextModel.ts | 27 ++++- .../contrib/notebook/common/notebookCommon.ts | 93 ++++++++++++++- .../test/browser/notebookTextModel.test.ts | 106 ++++++++++++++++++ 9 files changed, 341 insertions(+), 141 deletions(-) delete mode 100644 extensions/ipynb/src/streamCompressor.ts delete mode 100644 src/vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor.ts diff --git a/extensions/ipynb/src/serializers.ts b/extensions/ipynb/src/serializers.ts index f075737b4d8..96da8f2c617 100644 --- a/extensions/ipynb/src/serializers.ts +++ b/extensions/ipynb/src/serializers.ts @@ -7,7 +7,6 @@ import type * as nbformat from '@jupyterlab/nbformat'; import { NotebookCell, NotebookCellData, NotebookCellKind, NotebookCellOutput } from 'vscode'; import { CellOutputMetadata } from './common'; import { textMimeTypes } from './deserializers'; -import { compressOutputItemStreams } from './streamCompressor'; const textDecoder = new TextDecoder(); @@ -277,17 +276,21 @@ type JupyterOutput = function convertStreamOutput(output: NotebookCellOutput): JupyterOutput { const outputs: string[] = []; - const compressedStream = output.items.length ? new TextDecoder().decode(compressOutputItemStreams(output.items[0].mime, output.items)) : ''; - // Ensure each line is a separate entry in an array (ending with \n). - const lines = compressedStream.split('\n'); - // If the last item in `outputs` is not empty and the first item in `lines` is not empty, then concate them. - // As they are part of the same line. - if (outputs.length && lines.length && lines[0].length > 0) { - outputs[outputs.length - 1] = `${outputs[outputs.length - 1]}${lines.shift()!}`; - } - for (const line of lines) { - outputs.push(line); - } + output.items + .filter((opit) => opit.mime === CellOutputMimeTypes.stderr || opit.mime === CellOutputMimeTypes.stdout) + .map((opit) => textDecoder.decode(opit.data)) + .forEach(value => { + // Ensure each line is a separate entry in an array (ending with \n). + const lines = value.split('\n'); + // If the last item in `outputs` is not empty and the first item in `lines` is not empty, then concate them. + // As they are part of the same line. + if (outputs.length && lines.length && lines[0].length > 0) { + outputs[outputs.length - 1] = `${outputs[outputs.length - 1]}${lines.shift()!}`; + } + for (const line of lines) { + outputs.push(line); + } + }); for (let index = 0; index < (outputs.length - 1); index++) { outputs[index] = `${outputs[index]}\n`; diff --git a/extensions/ipynb/src/streamCompressor.ts b/extensions/ipynb/src/streamCompressor.ts deleted file mode 100644 index cea3184e16c..00000000000 --- a/extensions/ipynb/src/streamCompressor.ts +++ /dev/null @@ -1,63 +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 type { NotebookCellOutputItem } from 'vscode'; - - -/** - * Given a stream of individual stdout outputs, this function will return the compressed lines, escaping some of the common terminal escape codes. - * E.g. some terminal escape codes would result in the previous line getting cleared, such if we had 3 lines and - * last line contained such a code, then the result string would be just the first two lines. - */ -export function compressOutputItemStreams(mimeType: string, outputs: NotebookCellOutputItem[]) { - // return outputs.find(op => op.mime === mimeType)!.data.buffer; - - const buffers: Uint8Array[] = []; - let startAppending = false; - // Pick the first set of outputs with the same mime type. - for (const output of outputs) { - if (output.mime === mimeType) { - if ((buffers.length === 0 || startAppending)) { - buffers.push(output.data); - startAppending = true; - } - } else if (startAppending) { - startAppending = false; - } - } - compressStreamBuffer(buffers); - const totalBytes = buffers.reduce((p, c) => p + c.byteLength, 0); - const combinedBuffer = new Uint8Array(totalBytes); - let offset = 0; - for (const buffer of buffers) { - combinedBuffer.set(buffer, offset); - offset = offset + buffer.byteLength; - } - return combinedBuffer; -} -const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`; -const MOVE_CURSOR_1_LINE_COMMAND_BYTES = MOVE_CURSOR_1_LINE_COMMAND.split('').map(c => c.charCodeAt(0)); -const LINE_FEED = 10; -function compressStreamBuffer(streams: Uint8Array[]) { - streams.forEach((stream, index) => { - if (index === 0 || stream.length < MOVE_CURSOR_1_LINE_COMMAND.length) { - return; - } - - const previousStream = streams[index - 1]; - - // Remove the previous line if required. - const command = stream.subarray(0, MOVE_CURSOR_1_LINE_COMMAND.length); - if (command[0] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[0] && command[1] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[1] && command[2] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[2]) { - const lastIndexOfLineFeed = previousStream.lastIndexOf(LINE_FEED); - if (lastIndexOfLineFeed === -1) { - return; - } - streams[index - 1] = previousStream.subarray(0, lastIndexOfLineFeed); - streams[index] = stream.subarray(MOVE_CURSOR_1_LINE_COMMAND.length); - } - }); - return streams; -} diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index c3ebc53b3d6..38437605cec 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -110,6 +110,32 @@ export class ExtHostCell { output.items.length = 0; } output.items.push(...newItems); + + if (output.items.length > 1 && output.items.every(item => notebookCommon.isTextStreamMime(item.mime))) { + // Look for the mimes in the items, and keep track of their order. + // Merge the streams into one output item, per mime type. + const mimeOutputs = new Map(); + const mimeTypes: string[] = []; + output.items.forEach(item => { + let items: Uint8Array[]; + if (mimeOutputs.has(item.mime)) { + items = mimeOutputs.get(item.mime)!; + } else { + items = []; + mimeOutputs.set(item.mime, items); + mimeTypes.push(item.mime); + } + items.push(item.data); + }); + output.items.length = 0; + mimeTypes.forEach(mime => { + const compressed = notebookCommon.compressOutputItemStreams(mimeOutputs.get(mime)!); + output.items.push({ + mime, + data: compressed.buffer + }); + }); + } } } diff --git a/src/vs/workbench/api/test/browser/extHostNotebook.test.ts b/src/vs/workbench/api/test/browser/extHostNotebook.test.ts index 09e785c307b..60f453ec1f3 100644 --- a/src/vs/workbench/api/test/browser/extHostNotebook.test.ts +++ b/src/vs/workbench/api/test/browser/extHostNotebook.test.ts @@ -10,7 +10,7 @@ import { TestRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { NullLogService } from 'vs/platform/log/common/log'; import { mock } from 'vs/base/test/common/mock'; -import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; +import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape, NotebookCellsChangedEventDto, NotebookOutputItemDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -542,4 +542,77 @@ suite('NotebookCell#Document', function () { assert.ok(cellChange.metadata === undefined); assert.ok(cellChange.outputs === undefined); }); + + async function replaceOutputs(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) { + const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument); + extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ + versionId: notebook.apiNotebook.version + 1, + rawEvents: [{ + kind: NotebookCellsChangeType.Output, + index: cellIndex, + outputs: [{ outputId, items: outputItems }] + }] + }), false); + await changeEvent; + } + async function appendOutputItem(cellIndex: number, outputId: string, outputItems: NotebookOutputItemDto[]) { + const changeEvent = Event.toPromise(extHostNotebookDocuments.onDidChangeNotebookDocument); + extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({ + versionId: notebook.apiNotebook.version + 1, + rawEvents: [{ + kind: NotebookCellsChangeType.OutputItem, + index: cellIndex, + append: true, + outputId, + outputItems + }] + }), false); + await changeEvent; + } + test('Append multiple text/plain output items', async function () { + await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]); + await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('bar') }]); + await appendOutputItem(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('baz') }]); + + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foo'); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'text/plain'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[1].data).toString(), 'bar'); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'text/plain'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[2].data).toString(), 'baz'); + }); + test('Append multiple stdout stream output items to an output with another mime', async function () { + await replaceOutputs(1, '1', [{ mime: 'text/plain', valueBytes: VSBuffer.fromString('foo') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]); + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 3); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'text/plain'); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[1].mime, 'application/vnd.code.notebook.stdout'); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[2].mime, 'application/vnd.code.notebook.stdout'); + }); + test('Compress multiple stdout stream output items', async function () { + await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('bar') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('baz') }]); + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz'); + }); + test('Compress multiple stderr stream output items', async function () { + await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('foo') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('bar') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('baz') }]); + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stderr'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz'); + }); }); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index a32ebc7dc1a..f01090a0561 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -35,7 +35,7 @@ import { NOTEBOOK_WEBVIEW_BOUNDARY } from 'vs/workbench/contrib/notebook/browser import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; -import { CellUri, INotebookRendererInfo, isTextStreamMime, NotebookSetting, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellUri, INotebookRendererInfo, NotebookSetting, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { IScopedRendererMessaging } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -44,7 +44,6 @@ import { WebviewWindowDragMonitor } from 'vs/workbench/contrib/webview/browser/w import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { FromWebviewMessage, IAckOutputHeight, IClickedDataUrlMessage, ICodeBlockHighlightRequest, IContentWidgetTopRequest, IControllerPreload, ICreationContent, ICreationRequestMessage, IFindMatch, IMarkupCellInitialization, RendererMetadata, ToWebviewMessage } from './webviewMessages'; -import { compressOutputItemStreams } from 'vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor'; import { DeferredPromise } from 'vs/base/common/async'; export interface ICachedInset { @@ -1277,14 +1276,12 @@ var requirejs = (function() { let updatedContent: ICreationContent | undefined = undefined; if (content.type === RenderOutputType.Extension) { const output = content.source.model; - const firstBuffer = isTextStreamMime(content.mimeType) ? - compressOutputItemStreams(content.mimeType, output.outputs) : - output.outputs.find(op => op.mime === content.mimeType)!.data.buffer; + const firstBuffer = output.outputs.find(op => op.mime === content.mimeType)!.data; updatedContent = { type: RenderOutputType.Extension, outputId: outputCache.outputId, mimeType: content.mimeType, - valueBytes: firstBuffer, + valueBytes: firstBuffer.buffer, metadata: output.metadata, }; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor.ts deleted file mode 100644 index 7f20c6316fc..00000000000 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/stdOutErrorPreProcessor.ts +++ /dev/null @@ -1,56 +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 { VSBuffer } from 'vs/base/common/buffer'; -import type { IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; - - -/** - * Given a stream of individual stdout outputs, this function will return the compressed lines, escaping some of the common terminal escape codes. - * E.g. some terminal escape codes would result in the previous line getting cleared, such if we had 3 lines and - * last line contained such a code, then the result string would be just the first two lines. - */ -export function compressOutputItemStreams(mimeType: string, outputs: IOutputItemDto[]) { - const buffers: Uint8Array[] = []; - let startAppending = false; - - // Pick the first set of outputs with the same mime type. - for (const output of outputs) { - if (output.mime === mimeType) { - if ((buffers.length === 0 || startAppending)) { - buffers.push(output.data.buffer); - startAppending = true; - } - } else if (startAppending) { - startAppending = false; - } - } - compressStreamBuffer(buffers); - return VSBuffer.concat(buffers.map(buffer => VSBuffer.wrap(buffer))).buffer; -} -const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`; -const MOVE_CURSOR_1_LINE_COMMAND_BYTES = MOVE_CURSOR_1_LINE_COMMAND.split('').map(c => c.charCodeAt(0)); -const LINE_FEED = 10; -function compressStreamBuffer(streams: Uint8Array[]) { - streams.forEach((stream, index) => { - if (index === 0 || stream.length < MOVE_CURSOR_1_LINE_COMMAND.length) { - return; - } - - const previousStream = streams[index - 1]; - - // Remove the previous line if required. - const command = stream.subarray(0, MOVE_CURSOR_1_LINE_COMMAND.length); - if (command[0] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[0] && command[1] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[1] && command[2] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[2]) { - const lastIndexOfLineFeed = previousStream.lastIndexOf(LINE_FEED); - if (lastIndexOfLineFeed === -1) { - return; - } - streams[index - 1] = previousStream.subarray(0, lastIndexOfLineFeed); - streams[index] = stream.subarray(MOVE_CURSOR_1_LINE_COMMAND.length); - } - }); - return streams; -} diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts index 7890d272892..e8576c8234a 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts @@ -16,7 +16,7 @@ import { TextModel } from 'vs/editor/common/model/textModel'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel'; -import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellDto2, ICellOutput, IOutputDto, IOutputItemDto, NotebookCellCollapseState, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellInternalMetadataChangedEvent, CellKind, compressOutputItemStreams, ICell, ICellDto2, ICellOutput, IOutputDto, IOutputItemDto, isTextStreamMime, NotebookCellCollapseState, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export class NotebookCellTextModel extends Disposable implements ICell { private readonly _onDidChangeOutputs = this._register(new Emitter()); @@ -297,6 +297,31 @@ export class NotebookCellTextModel extends Disposable implements ICell { } else { output.replaceData(items); } + if (output.outputs.length > 1 && output.outputs.every(item => isTextStreamMime(item.mime))) { + // Look for the mimes in the items, and keep track of their order. + // Merge the streams into one output item, per mime type. + const mimeOutputs = new Map(); + const mimeTypes: string[] = []; + output.outputs.forEach(item => { + let items: Uint8Array[]; + if (mimeOutputs.has(item.mime)) { + items = mimeOutputs.get(item.mime)!; + } else { + items = []; + mimeOutputs.set(item.mime, items); + mimeTypes.push(item.mime); + } + items.push(item.data.buffer); + }); + output.outputs.length = 0; + mimeTypes.forEach(mime => { + const compressed = compressOutputItemStreams(mimeOutputs.get(mime)!); + output.outputs.push({ + mime, + data: compressed + }); + }); + } this._onDidChangeOutputItems.fire(); return true; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index ab73eaf88b9..0e2f1fe9ea6 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -951,9 +951,98 @@ export interface NotebookExtensionDescription { } /** - * Whether the provided mime type is a text streamn like `stdout`, `stderr`. + * Whether the provided mime type is a text stream like `stdout`, `stderr`. */ export function isTextStreamMime(mimeType: string) { - return ['application/vnd.code.notebook.stdout', 'application/x.notebook.stdout', 'application/x.notebook.stream', 'application/vnd.code.notebook.stderr', 'application/x.notebook.stderr'].includes(mimeType); + return ['application/vnd.code.notebook.stdout', 'application/vnd.code.notebook.stderr'].includes(mimeType); } + +const textDecoder = new TextDecoder(); + +/** + * Given a stream of individual stdout outputs, this function will return the compressed lines, escaping some of the common terminal escape codes. + * E.g. some terminal escape codes would result in the previous line getting cleared, such if we had 3 lines and + * last line contained such a code, then the result string would be just the first two lines. + */ +export function compressOutputItemStreams(outputs: Uint8Array[]) { + const buffers: Uint8Array[] = []; + let startAppending = false; + + // Pick the first set of outputs with the same mime type. + for (const output of outputs) { + if ((buffers.length === 0 || startAppending)) { + buffers.push(output); + startAppending = true; + } + } + compressStreamBuffer(buffers); + return formatStreamText(VSBuffer.concat(buffers.map(buffer => VSBuffer.wrap(buffer)))); +} +const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`; +const MOVE_CURSOR_1_LINE_COMMAND_BYTES = MOVE_CURSOR_1_LINE_COMMAND.split('').map(c => c.charCodeAt(0)); +const LINE_FEED = 10; +function compressStreamBuffer(streams: Uint8Array[]) { + streams.forEach((stream, index) => { + if (index === 0 || stream.length < MOVE_CURSOR_1_LINE_COMMAND.length) { + return; + } + + const previousStream = streams[index - 1]; + + // Remove the previous line if required. + const command = stream.subarray(0, MOVE_CURSOR_1_LINE_COMMAND.length); + if (command[0] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[0] && command[1] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[1] && command[2] === MOVE_CURSOR_1_LINE_COMMAND_BYTES[2]) { + const lastIndexOfLineFeed = previousStream.lastIndexOf(LINE_FEED); + if (lastIndexOfLineFeed === -1) { + return; + } + streams[index - 1] = previousStream.subarray(0, lastIndexOfLineFeed); + streams[index] = stream.subarray(MOVE_CURSOR_1_LINE_COMMAND.length); + } + }); +} + + + +/** + * Took this from jupyter/notebook + * https://github.com/jupyter/notebook/blob/b8b66332e2023e83d2ee04f83d8814f567e01a4e/notebook/static/base/js/utils.js + * Remove characters that are overridden by backspace characters + */ +function fixBackspace(txt: string) { + let tmp = txt; + do { + txt = tmp; + // Cancel out anything-but-newline followed by backspace + tmp = txt.replace(/[^\n]\x08/gm, ''); + } while (tmp.length < txt.length); + return txt; +} + +/** + * Remove chunks that should be overridden by the effect of carriage return characters + * From https://github.com/jupyter/notebook/blob/master/notebook/static/base/js/utils.js + */ +function fixCarriageReturn(txt: string) { + txt = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline + while (txt.search(/\r[^$]/g) > -1) { + const base = txt.match(/^(.*)\r+/m)![1]; + let insert = txt.match(/\r+(.*)$/m)![1]; + insert = insert + base.slice(insert.length, base.length); + txt = txt.replace(/\r+.*$/m, '\r').replace(/^.*\r/m, insert); + } + return txt; +} + +const BACKSPACE_CHARACTER = '\b'.charCodeAt(0); +const CARRIAGE_RETURN_CHARACTER = '\r'.charCodeAt(0); +function formatStreamText(buffer: VSBuffer): VSBuffer { + // We have special handling for backspace and carriage return characters. + // Don't unnecessary decode the bytes if we don't need to perform any processing. + if (!buffer.buffer.includes(BACKSPACE_CHARACTER) && !buffer.buffer.includes(CARRIAGE_RETURN_CHARACTER)) { + return buffer; + } + // Do the same thing jupyter is doing + return VSBuffer.fromString(fixCarriageReturn(fixBackspace(textDecoder.decode(buffer.buffer)))); +} diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookTextModel.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookTextModel.test.ts index 455d706b637..4da03a9f248 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookTextModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookTextModel.test.ts @@ -1043,4 +1043,110 @@ suite('NotebookTextModel', () => { assert.equal(model.cells[0].outputs[0].outputs[0].data.toString(), '_World_'); }); }); + test('Append multiple text/plain output items', async function () { + await withTestNotebook([ + ['var a = 1;', 'javascript', CellKind.Code, [{ + outputId: '1', + outputs: [{ mime: 'text/plain', data: valueBytesFromString('foo') }] + }], {}] + ], (editor) => { + const model = editor.textModel; + const edits: ICellEditOperation[] = [ + { + editType: CellEditType.OutputItems, + outputId: '1', + append: true, + items: [{ mime: 'text/plain', data: VSBuffer.fromString('bar') }, { mime: 'text/plain', data: VSBuffer.fromString('baz') }] + } + ]; + model.applyEdits(edits, true, undefined, () => undefined, undefined, true); + assert.equal(model.cells.length, 1); + assert.equal(model.cells[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs.length, 3); + assert.equal(model.cells[0].outputs[0].outputs[0].mime, 'text/plain'); + assert.equal(model.cells[0].outputs[0].outputs[0].data.toString(), 'foo'); + assert.equal(model.cells[0].outputs[0].outputs[1].mime, 'text/plain'); + assert.equal(model.cells[0].outputs[0].outputs[1].data.toString(), 'bar'); + assert.equal(model.cells[0].outputs[0].outputs[2].mime, 'text/plain'); + assert.equal(model.cells[0].outputs[0].outputs[2].data.toString(), 'baz'); + }); + }); + test('Append multiple stdout stream output items to an output with another mime', async function () { + await withTestNotebook([ + ['var a = 1;', 'javascript', CellKind.Code, [{ + outputId: '1', + outputs: [{ mime: 'text/plain', data: valueBytesFromString('foo') }] + }], {}] + ], (editor) => { + const model = editor.textModel; + const edits: ICellEditOperation[] = [ + { + editType: CellEditType.OutputItems, + outputId: '1', + append: true, + items: [{ mime: 'application/vnd.code.notebook.stdout', data: VSBuffer.fromString('bar') }, { mime: 'application/vnd.code.notebook.stdout', data: VSBuffer.fromString('baz') }] + } + ]; + model.applyEdits(edits, true, undefined, () => undefined, undefined, true); + assert.equal(model.cells.length, 1); + assert.equal(model.cells[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs.length, 3); + assert.equal(model.cells[0].outputs[0].outputs[0].mime, 'text/plain'); + assert.equal(model.cells[0].outputs[0].outputs[0].data.toString(), 'foo'); + assert.equal(model.cells[0].outputs[0].outputs[1].mime, 'application/vnd.code.notebook.stdout'); + assert.equal(model.cells[0].outputs[0].outputs[1].data.toString(), 'bar'); + assert.equal(model.cells[0].outputs[0].outputs[2].mime, 'application/vnd.code.notebook.stdout'); + assert.equal(model.cells[0].outputs[0].outputs[2].data.toString(), 'baz'); + }); + }); + test('Compress multiple stdout stream output items', async function () { + await withTestNotebook([ + ['var a = 1;', 'javascript', CellKind.Code, [{ + outputId: '1', + outputs: [{ mime: 'application/vnd.code.notebook.stdout', data: valueBytesFromString('foo') }] + }], {}] + ], (editor) => { + const model = editor.textModel; + const edits: ICellEditOperation[] = [ + { + editType: CellEditType.OutputItems, + outputId: '1', + append: true, + items: [{ mime: 'application/vnd.code.notebook.stdout', data: VSBuffer.fromString('bar') }, { mime: 'application/vnd.code.notebook.stdout', data: VSBuffer.fromString('baz') }] + } + ]; + model.applyEdits(edits, true, undefined, () => undefined, undefined, true); + assert.equal(model.cells.length, 1); + assert.equal(model.cells[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs[0].mime, 'application/vnd.code.notebook.stdout'); + assert.equal(model.cells[0].outputs[0].outputs[0].data.toString(), 'foobarbaz'); + }); + + }); + test('Compress multiple stderr stream output items', async function () { + await withTestNotebook([ + ['var a = 1;', 'javascript', CellKind.Code, [{ + outputId: '1', + outputs: [{ mime: 'application/vnd.code.notebook.stderr', data: valueBytesFromString('foo') }] + }], {}] + ], (editor) => { + const model = editor.textModel; + const edits: ICellEditOperation[] = [ + { + editType: CellEditType.OutputItems, + outputId: '1', + append: true, + items: [{ mime: 'application/vnd.code.notebook.stderr', data: VSBuffer.fromString('bar') }, { mime: 'application/vnd.code.notebook.stderr', data: VSBuffer.fromString('baz') }] + } + ]; + model.applyEdits(edits, true, undefined, () => undefined, undefined, true); + assert.equal(model.cells.length, 1); + assert.equal(model.cells[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs.length, 1); + assert.equal(model.cells[0].outputs[0].outputs[0].mime, 'application/vnd.code.notebook.stderr'); + assert.equal(model.cells[0].outputs[0].outputs[0].data.toString(), 'foobarbaz'); + }); + + }); }); From baa2dedb949c5012d9dd1633c2164a8ede537fff Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 11 Oct 2022 15:02:17 -0700 Subject: [PATCH 500/599] Make notebook singletons lazy (#162758) * Address #159178 for notebooks * Add method to list editor decorations so they can be initialized in the lazy instantiated NotebookService --- src/vs/editor/browser/services/abstractCodeEditorService.ts | 4 ++++ src/vs/editor/browser/services/codeEditorService.ts | 1 + .../contrib/interactive/browser/interactive.contribution.ts | 6 +++--- .../contrib/notebook/browser/notebook.contribution.ts | 4 ++-- .../notebook/browser/services/notebookServiceImpl.ts | 6 ++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index aaa31ee4ce4..61b1a394a06 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -156,6 +156,10 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC provider.refCount++; } + public listDecorationTypes(): string[] { + return Array.from(this._decorationOptionProviders.keys()); + } + public removeDecorationType(key: string): void { const provider = this._decorationOptionProviders.get(key); if (provider) { diff --git a/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts index 40d7947efcd..9de2e964a03 100644 --- a/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -41,6 +41,7 @@ export interface ICodeEditorService { getFocusedCodeEditor(): ICodeEditor | null; registerDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; + listDecorationTypes(): string[]; removeDecorationType(key: string): void; resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions; resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null; diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index 10682d94745..d380e002f7a 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -32,7 +32,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { EditorActivation, IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ILogService } from 'vs/platform/log/common/log'; @@ -317,8 +317,8 @@ Registry.as(EditorExtensions.EditorFactory) InteractiveEditorSerializer.ID, InteractiveEditorSerializer); -registerSingleton(IInteractiveHistoryService, InteractiveHistoryService, false); -registerSingleton(IInteractiveDocumentService, InteractiveDocumentService, false); +registerSingleton(IInteractiveHistoryService, InteractiveHistoryService, InstantiationType.Delayed); +registerSingleton(IInteractiveDocumentService, InteractiveDocumentService, InstantiationType.Delayed); registerAction2(class extends Action2 { constructor() { diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 3ce47b6f33f..566129e3fcf 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -697,8 +697,8 @@ workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSel workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); workbenchContributionsRegistry.registerWorkbenchContribution(ComplexNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); -registerSingleton(INotebookService, NotebookService, false); -registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, false); +registerSingleton(INotebookService, NotebookService, InstantiationType.Delayed); +registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, InstantiationType.Delayed); registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServiceImpl, InstantiationType.Delayed); registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, InstantiationType.Delayed); registerSingleton(INotebookEditorService, NotebookEditorWidgetService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts index 5fc81948747..66d21da2abb 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts @@ -513,7 +513,7 @@ export class NotebookService extends Disposable implements INotebookService { let decorationTriggeredAdjustment = false; const decorationCheckSet = new Set(); - this._register(this._codeEditorService.onDecorationTypeRegistered(e => { + const onDidAddDecorationType = (e: string) => { if (decorationTriggeredAdjustment) { return; } @@ -544,7 +544,9 @@ export class NotebookService extends Disposable implements INotebookService { } decorationCheckSet.add(e); - })); + }; + this._register(this._codeEditorService.onDecorationTypeRegistered(onDidAddDecorationType)); + this._codeEditorService.listDecorationTypes().forEach(onDidAddDecorationType); } From 84e5fd623d6ee58691a8aca42ab2c90220365eb4 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 15:12:05 -0700 Subject: [PATCH 501/599] Remove unused method (#163361) --- .../contrib/webview/browser/pre/service-worker.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js index 65a7313aa79..f4257b4d972 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -46,15 +46,6 @@ class RequestStore { this.requestPool = 0; } - /** - * @param {number} requestId - * @return {Promise | undefined} - */ - get(requestId) { - const entry = this.map.get(requestId); - return entry && entry.promise; - } - /** * @returns {{ requestId: number, promise: Promise }} */ From d9166909b62967e00ea6075abff9de98e250aed9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 15:36:48 -0700 Subject: [PATCH 502/599] Small clean up to mainthread and exthost custom editor code (#163350) - Align property names - Move private method to function - Formatting --- .../api/browser/mainThreadCustomEditors.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 4 +- .../api/common/extHostCustomEditors.ts | 51 ++++++++----------- 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 7e4f01b78f4..b549d50c217 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -188,8 +188,8 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc try { await this._proxyCustomEditors.$resolveWebviewEditor(resource, handle, viewType, { title: webviewInput.getTitle(), - webviewOptions: webviewInput.webview.contentOptions, - panelOptions: webviewInput.webview.options, + contentOptions: webviewInput.webview.contentOptions, + options: webviewInput.webview.options, }, editorGroupToColumn(this._editorGroupService, webviewInput.group || 0), cancellation); } catch (error) { onUnexpectedError(error); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 86f58713afb..47395e37724 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -902,8 +902,8 @@ export interface ExtHostCustomEditorsShape { viewType: string, initData: { title: string; - webviewOptions: IWebviewContentOptions; - panelOptions: IWebviewPanelOptions; + contentOptions: IWebviewContentOptions; + options: IWebviewPanelOptions; }, position: EditorGroupColumn, cancellation: CancellationToken diff --git a/src/vs/workbench/api/common/extHostCustomEditors.ts b/src/vs/workbench/api/common/extHostCustomEditors.ts index 24ee34186c0..04aa98ad3a8 100644 --- a/src/vs/workbench/api/common/extHostCustomEditors.ts +++ b/src/vs/workbench/api/common/extHostCustomEditors.ts @@ -112,7 +112,6 @@ class CustomDocumentStore { private key(viewType: string, resource: vscode.Uri): string { return `${viewType}@@@${resource}`; } - } const enum WebviewEditorType { @@ -187,7 +186,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor } else { disposables.add(this._editorProviders.addCustomProvider(viewType, extension, provider)); - if (this.supportEditing(provider)) { + if (isCustomEditorProviderWithEditingCapability(provider)) { disposables.add(provider.onDidChangeCustomDocument(e => { const entry = this.getCustomDocumentEntry(viewType, e.document.uri); if (isEditEvent(e)) { @@ -223,12 +222,12 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor const document = await entry.provider.openCustomDocument(revivedResource, { backupId, untitledDocumentData: untitledDocumentData?.buffer }, cancellation); let storageRoot: URI | undefined; - if (this.supportEditing(entry.provider) && this._extensionStoragePaths) { + if (isCustomEditorProviderWithEditingCapability(entry.provider) && this._extensionStoragePaths) { storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension); } this._documents.add(viewType, document, storageRoot); - return { editable: this.supportEditing(entry.provider) }; + return { editable: isCustomEditorProviderWithEditingCapability(entry.provider) }; } async $disposeCustomDocument(resource: UriComponents, viewType: string): Promise { @@ -253,8 +252,8 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor viewType: string, initData: { title: string; - webviewOptions: extHostProtocol.IWebviewContentOptions; - panelOptions: extHostProtocol.IWebviewPanelOptions; + contentOptions: extHostProtocol.IWebviewContentOptions; + options: extHostProtocol.IWebviewPanelOptions; }, position: EditorGroupColumn, cancellation: CancellationToken, @@ -266,26 +265,23 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor const viewColumn = typeConverters.ViewColumn.to(position); - const webview = this._extHostWebview.createNewWebview(handle, initData.webviewOptions, entry.extension); - const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, initData.title, viewColumn, initData.panelOptions, webview, true); + const webview = this._extHostWebview.createNewWebview(handle, initData.contentOptions, entry.extension); + const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, initData.title, viewColumn, initData.options, webview, true); const revivedResource = URI.revive(resource); switch (entry.type) { - case WebviewEditorType.Custom: - { - const { document } = this.getCustomDocumentEntry(viewType, revivedResource); - return entry.provider.resolveCustomEditor(document, panel, cancellation); - } - case WebviewEditorType.Text: - { - const document = this._extHostDocuments.getDocument(revivedResource); - return entry.provider.resolveCustomTextEditor(document, panel, cancellation); - } - default: - { - throw new Error('Unknown webview provider type'); - } + case WebviewEditorType.Custom: { + const { document } = this.getCustomDocumentEntry(viewType, revivedResource); + return entry.provider.resolveCustomEditor(document, panel, cancellation); + } + case WebviewEditorType.Text: { + const document = this._extHostDocuments.getDocument(revivedResource); + return entry.provider.resolveCustomTextEditor(document, panel, cancellation); + } + default: { + throw new Error('Unknown webview provider type'); + } } } @@ -366,17 +362,15 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor private getCustomEditorProvider(viewType: string): vscode.CustomEditorProvider { const entry = this._editorProviders.get(viewType); const provider = entry?.provider; - if (!provider || !this.supportEditing(provider)) { + if (!provider || !isCustomEditorProviderWithEditingCapability(provider)) { throw new Error('Custom document is not editable'); } return provider; } +} - private supportEditing( - provider: vscode.CustomTextEditorProvider | vscode.CustomEditorProvider | vscode.CustomReadonlyEditorProvider - ): provider is vscode.CustomEditorProvider { - return !!(provider as vscode.CustomEditorProvider).onDidChangeCustomDocument; - } +function isCustomEditorProviderWithEditingCapability(provider: vscode.CustomTextEditorProvider | vscode.CustomEditorProvider | vscode.CustomReadonlyEditorProvider): provider is vscode.CustomEditorProvider { + return !!(provider as vscode.CustomEditorProvider).onDidChangeCustomDocument; } function isCustomTextEditorProvider(provider: vscode.CustomReadonlyEditorProvider | vscode.CustomTextEditorProvider): provider is vscode.CustomTextEditorProvider { @@ -392,4 +386,3 @@ function hashPath(resource: URI): string { const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString(); return hash(str) + ''; } - From cc8feda3809683037ad5f7522664335cb4643ee9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 16:05:08 -0700 Subject: [PATCH 503/599] Use Object.entries for updating styles in webview (#163359) Use Object.entries for updating styles --- .../workbench/contrib/webview/browser/pre/index-no-csp.html | 4 ++-- src/vs/workbench/contrib/webview/browser/pre/index.html | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html b/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html index cd4afd479a5..12b1fdcda44 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html @@ -512,8 +512,8 @@ } // Re-add new properties - for (const variable of Object.keys(initData.styles)) { - documentStyle.setProperty(`--${variable}`, initData.styles[variable]); + for (const [variable, value] of Object.entries(initData.styles)) { + documentStyle.setProperty(`--${variable}`, value); } } }; diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index 6c90f4d295a..3b364180027 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -5,7 +5,7 @@ + content="default-src 'none'; script-src 'sha256-WedTLLcy1WD2tkMNIDWTY7p5GAXwF+3pVt9Bd3nh6x4=' 'self'; frame-src 'self'; style-src 'unsafe-inline';"> Date: Tue, 11 Oct 2022 16:06:58 -0700 Subject: [PATCH 504/599] Align switch case style in service worker (#163364) --- .../webview/browser/pre/service-worker.js | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js index f4257b4d972..c4fad5a8b2c 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -122,39 +122,37 @@ const methodNotAllowed = () => sw.addEventListener('message', async (event) => { switch (event.data.channel) { - case 'version': - { - const source = /** @type {Client} */ (event.source); - sw.clients.get(source.id).then(client => { - if (client) { - client.postMessage({ - channel: 'version', - version: VERSION - }); - } - }); - return; - } - case 'did-load-resource': - { - /** @type {ResourceResponse} */ - const response = event.data.data; - if (!resourceRequestStore.resolve(response.id, response)) { - console.log('Could not resolve unknown resource', response.path); + case 'version': { + const source = /** @type {Client} */ (event.source); + sw.clients.get(source.id).then(client => { + if (client) { + client.postMessage({ + channel: 'version', + version: VERSION + }); } - return; + }); + return; + } + case 'did-load-resource': { + /** @type {ResourceResponse} */ + const response = event.data.data; + if (!resourceRequestStore.resolve(response.id, response)) { + console.log('Could not resolve unknown resource', response.path); } - case 'did-load-localhost': - { - const data = event.data.data; - if (!localhostRequestStore.resolve(data.id, data.location)) { - console.log('Could not resolve unknown localhost', data.origin); - } - return; + return; + } + case 'did-load-localhost': { + const data = event.data.data; + if (!localhostRequestStore.resolve(data.id, data.location)) { + console.log('Could not resolve unknown localhost', data.origin); } - default: + return; + } + default: { console.log('Unknown message'); return; + } } }); @@ -174,8 +172,9 @@ sw.addEventListener('fetch', (event) => { query: requestUrl.search.replace(/^\?/, ''), })); } - default: + default: { return event.respondWith(methodNotAllowed()); + } } } @@ -186,16 +185,17 @@ sw.addEventListener('fetch', (event) => { if (requestUrl.origin !== sw.origin && requestUrl.host === remoteAuthority) { switch (event.request.method) { case 'GET': - case 'HEAD': + case 'HEAD': { return event.respondWith(processResourceRequest(event, { path: requestUrl.pathname, scheme: requestUrl.protocol.slice(0, requestUrl.protocol.length - 1), authority: requestUrl.host, query: requestUrl.search.replace(/^\?/, ''), })); - - default: + } + default: { return event.respondWith(methodNotAllowed()); + } } } From d05d85a78b3790bab72d205dcb7a684a18309540 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 16:08:17 -0700 Subject: [PATCH 505/599] Move html rewriting for old webviews to (#163367) The `asWebviewUri` methods was introduced in VS Code 1.38. It's silly that we still force every single webview to pay the cost of trying to rewrite the old style uris we supported in very old versions of VS Code Instead I've moved this logic into the extension host and disabled it for all extensions that target VS Code 1.60+ or newer. This means it never applies to internal webviews, notebooks, webview views, or custom editors (these public apis were all introduced after the switch to `asWebviewUri`) --- .../markdown-language-features/package.json | 2 +- extensions/media-preview/package.json | 2 +- extensions/simple-browser/package.json | 2 +- src/vs/workbench/api/common/extHostWebview.ts | 47 +++++++++++++++++-- .../contrib/webview/browser/webviewElement.ts | 29 ++---------- 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 763f946d9a3..2d8d4487f17 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -8,7 +8,7 @@ "license": "MIT", "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { - "vscode": "^1.20.0" + "vscode": "^1.70.0" }, "main": "./out/extension", "browser": "./dist/browser/extension", diff --git a/extensions/media-preview/package.json b/extensions/media-preview/package.json index b82a4eef836..384ab75f58b 100644 --- a/extensions/media-preview/package.json +++ b/extensions/media-preview/package.json @@ -12,7 +12,7 @@ "license": "MIT", "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { - "vscode": "^1.39.0" + "vscode": "^1.70.0" }, "main": "./out/extension", "browser": "./dist/browser/extension.js", diff --git a/extensions/simple-browser/package.json b/extensions/simple-browser/package.json index 2db456cb387..bcd83d483d3 100644 --- a/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -11,7 +11,7 @@ "license": "MIT", "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { - "vscode": "^1.53.0" + "vscode": "^1.70.0" }, "main": "./out/extension", "browser": "./dist/browser/extension", diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index db22cb7fc13..11359a68969 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -33,7 +33,8 @@ export class ExtHostWebview implements vscode.Webview { #isDisposed: boolean = false; #hasCalledAsWebviewUri = false; - #serializeBuffersForPostMessage = false; + #serializeBuffersForPostMessage: boolean; + #shouldRewriteOldResourceUris: boolean; constructor( handle: extHostProtocol.WebviewHandle, @@ -51,6 +52,7 @@ export class ExtHostWebview implements vscode.Webview { this.#workspace = workspace; this.#extension = extension; this.#serializeBuffersForPostMessage = shouldSerializeBuffersForPostMessage(extension); + this.#shouldRewriteOldResourceUris = shouldTryRewritingOldResourceUris(extension); this.#deprecationService = deprecationService; } @@ -98,12 +100,12 @@ export class ExtHostWebview implements vscode.Webview { this.assertNotDisposed(); if (this.#html !== value) { this.#html = value; - if (!this.#hasCalledAsWebviewUri && /(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) { + if (this.#shouldRewriteOldResourceUris && !this.#hasCalledAsWebviewUri && /(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) { this.#hasCalledAsWebviewUri = true; this.#deprecationService.report('Webview vscode-resource: uris', this.#extension, `Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`); } - this.#proxy.$setHtml(this.#handle, value); + this.#proxy.$setHtml(this.#handle, this.rewriteOldResourceUrlsIfNeeded(value)); } } @@ -131,6 +133,32 @@ export class ExtHostWebview implements vscode.Webview { throw new Error('Webview is disposed'); } } + + private rewriteOldResourceUrlsIfNeeded(value: string): string { + if (!this.#shouldRewriteOldResourceUris) { + return value; + } + + const isRemote = this.#extension.extensionLocation?.scheme === Schemas.vscodeRemote; + const remoteAuthority = this.#extension.extensionLocation.scheme === Schemas.vscodeRemote ? this.#extension.extensionLocation.authority : undefined; + return value + .replace(/(["'])(?:vscode-resource):(\/\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (_match, startQuote, _1, scheme, path, endQuote) => { + const uri = URI.from({ + scheme: scheme || 'file', + path: decodeURIComponent(path), + }); + const webviewUri = asWebviewUri(uri, { isRemote, authority: remoteAuthority }).toString(); + return `${startQuote}${webviewUri}${endQuote}`; + }) + .replace(/(["'])(?:vscode-webview-resource):(\/\/[^\s\/'"]+\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (_match, startQuote, _1, scheme, path, endQuote) => { + const uri = URI.from({ + scheme: scheme || 'file', + path: decodeURIComponent(path), + }); + const webviewUri = asWebviewUri(uri, { isRemote, authority: remoteAuthority }).toString(); + return `${startQuote}${webviewUri}${endQuote}`; + }); + } } export function shouldSerializeBuffersForPostMessage(extension: IExtensionDescription): boolean { @@ -142,6 +170,19 @@ export function shouldSerializeBuffersForPostMessage(extension: IExtensionDescri } } +function shouldTryRewritingOldResourceUris(extension: IExtensionDescription): boolean { + try { + const version = normalizeVersion(parseVersion(extension.engines.vscode)); + if (!version) { + return false; + } + + return version.majorBase < 1 || (version.majorBase === 1 && version.minorBase < 60); + } catch { + return false; + } +} + export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape { private readonly _webviewProxy: extHostProtocol.MainThreadWebviewsShape; diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index bb38d8b1756..45e735a28ed 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -11,7 +11,7 @@ import { streamToBuffer, VSBufferReadableStream } from 'vs/base/common/buffer'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { COI, Schemas } from 'vs/base/common/network'; +import { COI } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { localize } from 'vs/nls'; @@ -30,7 +30,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITunnelService } from 'vs/platform/tunnel/common/tunnel'; import { WebviewPortMappingManager } from 'vs/platform/webview/common/webviewPortMapping'; import { parentOriginHash } from 'vs/workbench/browser/webview'; -import { asWebviewUri, decodeAuthority, webviewGenericCspSource, webviewRootResourceAuthority } from 'vs/workbench/common/webview'; +import { decodeAuthority, webviewGenericCspSource, webviewRootResourceAuthority } from 'vs/workbench/common/webview'; import { loadLocalResource, WebviewResourceResponse } from 'vs/workbench/contrib/webview/browser/resourceLoading'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; import { areWebviewContentOptionsEqual, IWebview, WebviewContentOptions, WebviewExtensionDescription, WebviewMessageReceivedEvent, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; @@ -645,37 +645,14 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD } public set html(value: string) { - const rewrittenHtml = this.rewriteVsCodeResourceUrls(value); this.doUpdateContent({ - html: rewrittenHtml, + html: value, options: this.content.options, state: this.content.state, }); this._onDidHtmlChange.fire(value); } - private rewriteVsCodeResourceUrls(value: string): string { - const isRemote = this.extension?.location?.scheme === Schemas.vscodeRemote; - const remoteAuthority = this.extension?.location?.scheme === Schemas.vscodeRemote ? this.extension.location.authority : undefined; - return value - .replace(/(["'])(?:vscode-resource):(\/\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (_match, startQuote, _1, scheme, path, endQuote) => { - const uri = URI.from({ - scheme: scheme || 'file', - path: decodeURIComponent(path), - }); - const webviewUri = asWebviewUri(uri, { isRemote, authority: remoteAuthority }).toString(); - return `${startQuote}${webviewUri}${endQuote}`; - }) - .replace(/(["'])(?:vscode-webview-resource):(\/\/[^\s\/'"]+\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (_match, startQuote, _1, scheme, path, endQuote) => { - const uri = URI.from({ - scheme: scheme || 'file', - path: decodeURIComponent(path), - }); - const webviewUri = asWebviewUri(uri, { isRemote, authority: remoteAuthority }).toString(); - return `${startQuote}${webviewUri}${endQuote}`; - }); - } - public set contentOptions(options: WebviewContentOptions) { this._logService.debug(`Webview(${this.id}): will update content options`); From fa6b137214dabd8354d0f3027ec798cf347cc89c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 16:15:28 -0700 Subject: [PATCH 506/599] Inline factory methods (#163363) --- .../customEditor/browser/customEditors.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 12adb973d5f..f4245a1995b 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -26,7 +26,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { CONTEXT_ACTIVE_CUSTOM_EDITOR_ID, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CustomEditorCapabilities, CustomEditorInfo, CustomEditorInfoCollection, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { DiffEditorInputFactoryFunction, EditorInputFactoryFunction, IEditorResolverService, IEditorType, RegisteredEditorPriority, UntitledEditorInputFactoryFunction } from 'vs/workbench/services/editor/common/editorResolverService'; +import { IEditorResolverService, IEditorType, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ContributedCustomEditors } from '../common/contributedCustomEditors'; import { CustomEditorInput } from './customEditorInput'; @@ -119,16 +119,6 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ continue; } - const editorInputFactory: EditorInputFactoryFunction = ({ resource }, group) => { - return { editor: CustomEditorInput.create(this.instantiationService, resource, contributedEditor.id, group.id) }; - }; - const untitledEditorInputFactory: UntitledEditorInputFactoryFunction = ({ resource }, group) => { - return { editor: CustomEditorInput.create(this.instantiationService, resource ?? URI.from({ scheme: Schemas.untitled, authority: `Untitled-${this._untitledCounter++}` }), contributedEditor.id, group.id) }; - }; - const diffEditorInputFactory: DiffEditorInputFactoryFunction = (diffEditorInput, group) => { - return { editor: this.createDiffEditorInput(diffEditorInput, contributedEditor.id, group) }; - }; - this._editorResolverDisposables.add(this.editorResolverService.registerEditor( globPattern.filenamePattern, { @@ -141,9 +131,15 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ singlePerResource: () => !this.getCustomEditorCapabilities(contributedEditor.id)?.supportsMultipleEditorsPerDocument ?? true }, { - createEditorInput: editorInputFactory, - createUntitledEditorInput: untitledEditorInputFactory, - createDiffEditorInput: diffEditorInputFactory, + createEditorInput: ({ resource }, group) => { + return { editor: CustomEditorInput.create(this.instantiationService, resource, contributedEditor.id, group.id) }; + }, + createUntitledEditorInput: ({ resource }, group) => { + return { editor: CustomEditorInput.create(this.instantiationService, resource ?? URI.from({ scheme: Schemas.untitled, authority: `Untitled-${this._untitledCounter++}` }), contributedEditor.id, group.id) }; + }, + createDiffEditorInput: (diffEditorInput, group) => { + return { editor: this.createDiffEditorInput(diffEditorInput, contributedEditor.id, group) }; + }, } )); } From 6d96eb0dfbf6ed781a2369f8ae381e3f71f50646 Mon Sep 17 00:00:00 2001 From: Ian Huff Date: Tue, 11 Oct 2022 16:27:24 -0700 Subject: [PATCH 507/599] update distro to allow Jupyter access to notebookControllerAffinityHidden (#163369) Co-authored-by: Ian Huff --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c6a867e9b3..e441f0f4e08 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.73.0", - "distro": "76fdab745a3dcf7a4a13b0f7f549d680e6323972", + "distro": "33ffc394a05e9cb3e9ac1fe2a72ab75610cf0d7e", "author": { "name": "Microsoft Corporation" }, From 1bda1e241ce632ecc6dfa26c9b126eb023b7bc87 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 17:13:00 -0700 Subject: [PATCH 508/599] Pick up latest TS for building VS Code (#163375) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e441f0f4e08..55394b42987 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "ts-loader": "^9.2.7", "ts-node": "^10.9.1", "tsec": "0.1.4", - "typescript": "^4.9.0-dev.20221005", + "typescript": "^4.9.0-dev.20221011", "typescript-formatter": "7.1.0", "underscore": "^1.12.1", "util": "^0.12.4", diff --git a/yarn.lock b/yarn.lock index 6c3a49eb969..86e04612a79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10771,10 +10771,10 @@ typescript@^2.6.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= -typescript@^4.9.0-dev.20221005: - version "4.9.0-dev.20221005" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.0-dev.20221005.tgz#ebfb29da9c5b054736ba1e00b3d6aaad49e0228e" - integrity sha512-uKa1ioEqENveT1YE90O1PoX27pdr+wWvKOcpGJaDNninks4m2Ygjj5ZcHb+AKuqdc1b8A39EvSZDWSxXky9F2Q== +typescript@^4.9.0-dev.20221011: + version "4.9.0-dev.20221011" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.0-dev.20221011.tgz#5c0ccbb7cfc1d8928fec987b7fc490cd664869e3" + integrity sha512-ONzbj3hrlLtfCGhDV7zP9FHoVgYo7+zRvphDqNNoqg2B3uqnxw57Ql/zPThRfepFmISdd/P03owzxeBUE48xqA== typical@^4.0.0: version "4.0.0" From 28891790e9571f2fbba473095f4162517e9ca276 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 11 Oct 2022 17:27:39 -0700 Subject: [PATCH 509/599] Send breakpoint init requests in parallel (#163250) * Send breakpoint init requests in parallel Fix #163248 * Keep serial breakpoint init style when the DA does not support the configurationDone request * Extract complex setBreakpoints expression --- .../contrib/debug/browser/debugService.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 7e86b539725..ff82f476352 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -1050,12 +1050,27 @@ export class DebugService implements IDebugService { } async sendAllBreakpoints(session?: IDebugSession): Promise { - await Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session))); - await this.sendFunctionBreakpoints(session); - await this.sendDataBreakpoints(session); - await this.sendInstructionBreakpoints(session); - // send exception breakpoints at the end since some debug adapters rely on the order - await this.sendExceptionBreakpoints(session); + const setBreakpointsPromises = distinct(this.model.getBreakpoints(), bp => bp.uri.toString()) + .map(bp => this.sendBreakpoints(bp.uri, false, session)); + + // If sending breakpoints to one session which we know supports the configurationDone request, can make all requests in parallel + if (session?.capabilities.supportsConfigurationDoneRequest) { + await Promise.all([ + ...setBreakpointsPromises, + this.sendFunctionBreakpoints(session), + this.sendDataBreakpoints(session), + this.sendInstructionBreakpoints(session), + this.sendExceptionBreakpoints(session), + ]); + } else { + await Promise.all(setBreakpointsPromises); + await this.sendFunctionBreakpoints(session); + await this.sendDataBreakpoints(session); + await this.sendInstructionBreakpoints(session); + // send exception breakpoints at the end since some debug adapters may rely on the order - this was the case before + // the configurationDone request was introduced. + await this.sendExceptionBreakpoints(session); + } } private async sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise { From 6cf68a1f23ee09d13e7e2bc4f7e8e2de1c5ef714 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 17:41:13 -0700 Subject: [PATCH 510/599] Remove .only and fix tests (#163376) Fixes #162159 --- .../src/test/documentLink.test.ts | 7 +++---- .../markdown-language-features/src/test/engine.test.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/extensions/markdown-language-features/src/test/documentLink.test.ts b/extensions/markdown-language-features/src/test/documentLink.test.ts index 37fe52e3dfb..0000069a660 100644 --- a/extensions/markdown-language-features/src/test/documentLink.test.ts +++ b/extensions/markdown-language-features/src/test/documentLink.test.ts @@ -134,7 +134,7 @@ async function getLinksForFile(file: vscode.Uri): Promise } }); - test('Should navigate to fragment within current untitled file', async () => { // TODO: skip for now for ls migration + test.skip('Should navigate to fragment within current untitled file', async () => { // TODO: skip for now for ls migration const testFile = workspaceFile('x.md').with({ scheme: 'untitled' }); await withFileContents(testFile, joinLines( '[](#second)', @@ -169,9 +169,8 @@ async function withFileContents(file: vscode.Uri, contents: string): Promise { }); }); - suite.only('image-caching', () => { + suite('image-caching', () => { const input = '![](img.png) [](no-img.png) ![](http://example.org/img.png) ![](img.png) ![](./img2.png)'; test('Extracts all images', async () => { From e1a373defd153d84a95f0d274af6745d52523456 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 17:42:10 -0700 Subject: [PATCH 511/599] Finalize markdown link updating on file move (#163378) Fixes #148146 --- .../markdown-language-features/package.json | 18 +++++++-------- .../package.nls.json | 12 +++++----- .../src/languageFeatures/linkUpdater.ts | 22 +++++++++---------- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 2d8d4487f17..250a6ddc8a8 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -516,7 +516,7 @@ "error" ] }, - "markdown.experimental.updateLinksOnFileMove.enabled": { + "markdown.updateLinksOnFileMove.enabled": { "type": "string", "enum": [ "prompt", @@ -524,30 +524,30 @@ "never" ], "markdownEnumDescriptions": [ - "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.prompt%", - "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.always%", - "%configuration.markdown.experimental.updateLinksOnFileMove.enabled.never%" + "%configuration.markdown.updateLinksOnFileMove.enabled.prompt%", + "%configuration.markdown.updateLinksOnFileMove.enabled.always%", + "%configuration.markdown.updateLinksOnFileMove.enabled.never%" ], "default": "never", - "markdownDescription": "%configuration.markdown.experimental.updateLinksOnFileMove.enabled%", + "markdownDescription": "%configuration.markdown.updateLinksOnFileMove.enabled%", "scope": "resource", "tags": [ "experimental" ] }, - "markdown.experimental.updateLinksOnFileMove.externalFileGlobs": { + "markdown.updateLinksOnFileMove.externalFileGlobs": { "type": "string", "default": "**/*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp,avif,tiff,svg,mp4}", - "description": "%configuration.markdown.experimental.updateLinksOnFileMove.fileGlobs%", + "description": "%configuration.markdown.updateLinksOnFileMove.fileGlobs%", "scope": "resource", "tags": [ "experimental" ] }, - "markdown.experimental.updateLinksOnFileMove.enableForDirectories": { + "markdown.updateLinksOnFileMove.enableForDirectories": { "type": "boolean", "default": true, - "description": "%configuration.markdown.experimental.updateLinksOnFileMove.enableForDirectories%", + "description": "%configuration.markdown.updateLinksOnFileMove.enableForDirectories%", "scope": "resource", "tags": [ "experimental" diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index b1d65edabe2..731a8a059e5 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -39,11 +39,11 @@ "configuration.markdown.validate.ignoredLinks.description": "Configure links that should not be validated. For example adding `/about` would not validate the link `[about](/about)`, while the glob `/assets/**/*.svg` would let you skip validation for any link to `.svg` files under the `assets` directory.", "configuration.markdown.validate.unusedLinkDefinitions.description": "Validate link definitions that are unused in the current file.", "configuration.markdown.validate.duplicateLinkDefinitions.description": "Validate duplicated definitions in the current file.", - "configuration.markdown.experimental.updateLinksOnFileMove.enabled": "Try to update links in Markdown files when a file is renamed/moved in the workspace. Use `#markdown.experimental.updateLinksOnFileMove.externalFileGlobs#` to configure which files trigger link updates.", - "configuration.markdown.experimental.updateLinksOnFileMove.enabled.prompt": "Prompt on each file move.", - "configuration.markdown.experimental.updateLinksOnFileMove.enabled.always": "Always update links automatically.", - "configuration.markdown.experimental.updateLinksOnFileMove.enabled.never": "Never try to update link and don't prompt.", - "configuration.markdown.experimental.updateLinksOnFileMove.fileGlobs": "A glob that specifies which files besides markdown should trigger a link update.", - "configuration.markdown.experimental.updateLinksOnFileMove.enableForDirectories": "enable/disable updating links when a directory is moved or renamed in the workspace.", + "configuration.markdown.updateLinksOnFileMove.enabled": "Try to update links in Markdown files when a file is renamed/moved in the workspace. Use `#markdown.updateLinksOnFileMove.externalFileGlobs#` to configure which files trigger link updates.", + "configuration.markdown.updateLinksOnFileMove.enabled.prompt": "Prompt on each file move.", + "configuration.markdown.updateLinksOnFileMove.enabled.always": "Always update links automatically.", + "configuration.markdown.updateLinksOnFileMove.enabled.never": "Never try to update link and don't prompt.", + "configuration.markdown.updateLinksOnFileMove.fileGlobs": "A glob that specifies which files besides markdown should trigger a link update.", + "configuration.markdown.updateLinksOnFileMove.enableForDirectories": "enable/disable updating links when a directory is moved or renamed in the workspace.", "workspaceTrust": "Required for loading styles configured in the workspace." } diff --git a/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts index 32553783bfa..0b50ed4fc80 100644 --- a/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts +++ b/extensions/markdown-language-features/src/languageFeatures/linkUpdater.ts @@ -18,9 +18,9 @@ import { convertRange } from './fileReferences'; const localize = nls.loadMessageBundle(); const settingNames = Object.freeze({ - enabled: 'experimental.updateLinksOnFileMove.enabled', - externalFileGlobs: 'experimental.updateLinksOnFileMove.externalFileGlobs', - enableForDirectories: 'experimental.updateLinksOnFileMove.enableForDirectories', + enabled: 'updateLinksOnFileMove.enabled', + externalFileGlobs: 'updateLinksOnFileMove.externalFileGlobs', + enableForDirectories: 'updateLinksOnFileMove.enableForDirectories', }); const enum UpdateLinksOnFileMoveSetting { @@ -45,14 +45,11 @@ class UpdateLinksOnFileRenameHandler extends Disposable { super(); this._register(vscode.workspace.onDidRenameFiles(async (e) => { - for (const { newUri, oldUri } of e.files) { - const config = vscode.workspace.getConfiguration('markdown', newUri); - if (!await this.shouldParticipateInLinkUpdate(config, newUri)) { - continue; + await Promise.all(e.files.map(async (rename) => { + if (await this.shouldParticipateInLinkUpdate(rename.newUri)) { + this._pendingRenames.add(rename); } - - this._pendingRenames.add({ newUri, oldUri }); - } + })); if (this._pendingRenames.size) { this._delayer.trigger(() => { @@ -95,7 +92,8 @@ class UpdateLinksOnFileRenameHandler extends Disposable { return false; } } - private async shouldParticipateInLinkUpdate(config: vscode.WorkspaceConfiguration, newUri: vscode.Uri): Promise { + private async shouldParticipateInLinkUpdate(newUri: vscode.Uri): Promise { + const config = vscode.workspace.getConfiguration('markdown', newUri); const setting = config.get(settingNames.enabled); if (setting === UpdateLinksOnFileMoveSetting.Never) { return false; @@ -230,6 +228,6 @@ class UpdateLinksOnFileRenameHandler extends Disposable { } } -export function registerUpdateLinksOnRename(client: MdLanguageClient) { +export function registerUpdateLinksOnRename(client: MdLanguageClient): vscode.Disposable { return new UpdateLinksOnFileRenameHandler(client); } From bad5e65a099f416001050b7f3fed1a88f9b38d7a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 11 Oct 2022 18:21:42 -0700 Subject: [PATCH 512/599] Don't log this error (#163384) I think it's expected that sometimes the resource from the debug session will outlive the session itself Fix #163270 --- src/vs/workbench/contrib/debug/common/debugContentProvider.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/common/debugContentProvider.ts b/src/vs/workbench/contrib/debug/common/debugContentProvider.ts index e7c4d271d2e..62bf8a6c423 100644 --- a/src/vs/workbench/contrib/debug/common/debugContentProvider.ts +++ b/src/vs/workbench/contrib/debug/common/debugContentProvider.ts @@ -18,6 +18,7 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Range } from 'vs/editor/common/core/range'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'; +import { ErrorNoTelemetry } from 'vs/base/common/errors'; /** * Debug URI format @@ -89,7 +90,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC } if (!session) { - return Promise.reject(new Error(localize('unable', "Unable to resolve the resource without a debug session"))); + return Promise.reject(new ErrorNoTelemetry(localize('unable', "Unable to resolve the resource without a debug session"))); } const createErrModel = (errMsg?: string) => { this.debugService.sourceIsNotAvailable(resource); From 8b0248854a4c6996ddea13e30dcc4fb0b56ef53b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 19:03:42 -0700 Subject: [PATCH 513/599] Clean up how the notebook renderer entrypoint is passed around (#163373) This internally makes entrypoint into a single property instead of splitting it across `entrypoint` and `extends` Also removes unused properties from `INotebookRendererInfo` --- .../browser/notebookExtensionPoint.ts | 4 +-- .../view/renderers/backLayerWebView.ts | 8 +++-- .../browser/view/renderers/webviewMessages.ts | 3 +- .../browser/view/renderers/webviewPreloads.ts | 8 ++--- .../contrib/notebook/common/notebookCommon.ts | 20 ++++++------ .../notebook/common/notebookOutputRenderer.ts | 31 +++++++------------ 6 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts index 651082499a8..f28fc03d29b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts @@ -6,7 +6,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { NotebookEditorPriority, NotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookEditorPriority, ContributedNotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const NotebookEditorContribution = Object.freeze({ type: 'type', @@ -36,7 +36,7 @@ export interface INotebookRendererContribution { readonly [NotebookRendererContribution.id]?: string; readonly [NotebookRendererContribution.displayName]: string; readonly [NotebookRendererContribution.mimeTypes]?: readonly string[]; - readonly [NotebookRendererContribution.entrypoint]: NotebookRendererEntrypoint; + readonly [NotebookRendererContribution.entrypoint]: ContributedNotebookRendererEntrypoint; readonly [NotebookRendererContribution.hardDependencies]: readonly string[]; readonly [NotebookRendererContribution.optionalDependencies]: readonly string[]; readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index f01090a0561..ba6810f0afb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -403,12 +403,14 @@ export class BackLayerWebView extends Disposable { private getRendererData(): RendererMetadata[] { return this.notebookService.getRenderers().map((renderer): RendererMetadata => { - const entrypoint = this.asWebviewUri(renderer.entrypoint, renderer.extensionLocation).toString(); + const entrypoint = { + extends: renderer.entrypoint.extends, + path: this.asWebviewUri(renderer.entrypoint.path, renderer.extensionLocation).toString() + }; return { id: renderer.id, entrypoint, mimeTypes: renderer.mimeTypes, - extends: renderer.extends, messaging: renderer.messaging !== RendererMessagingSpec.Never, isBuiltin: renderer.isBuiltin }; @@ -923,7 +925,7 @@ var requirejs = (function() { const notebookDir = this.getNotebookBaseUri(); return [ ...this.notebookService.getNotebookProviderResourceRoots(), - ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint)), + ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint.path)), ...workspaceFolders, notebookDir, ...this.getBuiltinLocalResourceRoots() diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 79adc52e51e..8b0902ba129 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -275,9 +275,8 @@ export interface IUpdateControllerPreloadsMessage { export interface RendererMetadata { readonly id: string; - readonly entrypoint: string; + readonly entrypoint: { readonly extends: string | undefined; readonly path: string }; readonly mimeTypes: readonly string[]; - readonly extends: string | undefined; readonly messaging: boolean; readonly isBuiltin: boolean; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 6062c79818c..c5817113f92 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1314,7 +1314,7 @@ async function webviewPreloads(ctx: PreloadContext) { /** Inner function cached in the _loadPromise(). */ private async _load(): Promise { - const module: RendererModule = await __import(this.data.entrypoint); + const module: RendererModule = await __import(this.data.entrypoint.path); if (!module) { return; } @@ -1324,7 +1324,7 @@ async function webviewPreloads(ctx: PreloadContext) { // Load all renderers that extend this renderer await Promise.all( ctx.rendererData - .filter(d => d.extends === this.data.id) + .filter(d => d.entrypoint.extends === this.data.id) .map(async d => { const renderer = renderers.getRenderer(d.id); if (!renderer) { @@ -1436,7 +1436,7 @@ async function webviewPreloads(ctx: PreloadContext) { } private rendererEqual(a: webviewMessages.RendererMetadata, b: webviewMessages.RendererMetadata) { - if (a.entrypoint !== b.entrypoint || a.id !== b.id || a.extends !== b.extends || a.messaging !== b.messaging) { + if (a.id !== b.id || a.entrypoint.path !== b.entrypoint.path || a.entrypoint.extends !== b.entrypoint.extends || a.messaging !== b.messaging) { return false; } @@ -1497,7 +1497,7 @@ async function webviewPreloads(ctx: PreloadContext) { .find((renderer) => renderer.data.id === preferredRendererId); } else { const renderers = Array.from(this._renderers.values()) - .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends); + .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.entrypoint.extends); if (renderers.length) { // De-prioritize built-in renderers diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 0e2f1fe9ea6..403a07a082f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -75,7 +75,7 @@ export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap; - extensionLocation: URI; - extensionId: ExtensionIdentifier; - messaging: RendererMessagingSpec; + readonly id: string; + readonly displayName: string; + readonly entrypoint: NotebookRendererEntrypoint; + readonly extensionLocation: URI; + readonly extensionId: ExtensionIdentifier; + readonly messaging: RendererMessagingSpec; readonly mimeTypes: readonly string[]; - readonly dependencies: readonly string[]; - readonly isBuiltin: boolean; matchesWithoutKernel(mimeType: string): NotebookRendererMatch; diff --git a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts index e22c7fd486f..ab8c71a1294 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts @@ -8,7 +8,7 @@ import { Iterable } from 'vs/base/common/iterator'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { INotebookRendererInfo, NotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookRendererInfo, ContributedNotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec, NotebookRendererEntrypoint } from 'vs/workbench/contrib/notebook/common/notebookCommon'; class DependencyList { private readonly value: ReadonlySet; @@ -19,10 +19,6 @@ class DependencyList { this.defined = this.value.size > 0; } - public values(): string[] { - return Array.from(this.value); - } - /** Gets whether any of the 'available' dependencies match the ones in this list */ public matches(available: ReadonlyArray) { // For now this is simple, but this may expand to support globs later @@ -34,17 +30,13 @@ class DependencyList { export class NotebookOutputRendererInfo implements INotebookRendererInfo { readonly id: string; - readonly extends?: string; - readonly entrypoint: URI; + readonly entrypoint: NotebookRendererEntrypoint; readonly displayName: string; readonly extensionLocation: URI; readonly extensionId: ExtensionIdentifier; readonly hardDependencies: DependencyList; readonly optionalDependencies: DependencyList; - /** @see RendererMessagingSpec */ readonly messaging: RendererMessagingSpec; - // todo: re-add preloads in pure renderer API - readonly preloads: ReadonlyArray = []; readonly mimeTypes: readonly string[]; private readonly mimeTypeGlobs: glob.ParsedPattern[]; @@ -54,7 +46,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { constructor(descriptor: { readonly id: string; readonly displayName: string; - readonly entrypoint: NotebookRendererEntrypoint; + readonly entrypoint: ContributedNotebookRendererEntrypoint; readonly mimeTypes: readonly string[]; readonly extension: IExtensionDescription; readonly dependencies: readonly string[] | undefined; @@ -67,10 +59,15 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.isBuiltin = descriptor.extension.isBuiltin; if (typeof descriptor.entrypoint === 'string') { - this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint); + this.entrypoint = { + extends: undefined, + path: joinPath(this.extensionLocation, descriptor.entrypoint) + }; } else { - this.extends = descriptor.entrypoint.extends; - this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint.path); + this.entrypoint = { + extends: descriptor.entrypoint.extends, + path: joinPath(this.extensionLocation, descriptor.entrypoint.path) + }; } this.displayName = descriptor.displayName; @@ -81,10 +78,6 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.messaging = descriptor.requiresMessaging ?? RendererMessagingSpec.Never; } - public get dependencies(): string[] { - return this.hardDependencies.values(); - } - public matchesWithoutKernel(mimeType: string) { if (!this.matchesMimeTypeOnly(mimeType)) { return NotebookRendererMatch.Never; @@ -118,7 +111,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { } private matchesMimeTypeOnly(mimeType: string) { - if (this.extends !== undefined) { + if (!URI.isUri(this.entrypoint)) { // We're extending another renderer return false; } From fdb8812822d00005242fe4250f69aaa5269a7706 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 11 Oct 2022 19:31:41 -0700 Subject: [PATCH 514/599] Always mark notebook list rendering `elementDisposables` as disposed (#163382) Mark notebook list rendering elementDisposables as disposed This updates `disposeTemplate` for notebook list rendering to mark the `elementDisposables` as disposed instead of simply clearing them. This is helpful if you are using `TRACK_DISPOSABLES`, and will also log if you try adding to the disposable after it has been disposed of Also marks more template fields as readonly --- .../browser/diff/notebookDiffEditorBrowser.ts | 1 - .../browser/diff/notebookTextDiffList.ts | 2 ++ .../browser/view/notebookRenderingCommon.ts | 16 ++++++++-------- .../browser/view/renderers/cellRenderer.ts | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 13559d512e4..e881fda60b7 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -75,7 +75,6 @@ export interface CellDiffSingleSideRenderTemplate extends CellDiffCommonRenderTe readonly metadataInfoContainer: HTMLElement; readonly outputHeaderContainer: HTMLElement; readonly outputInfoContainer: HTMLElement; - } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 3504ac2a58d..fe5b564916d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -147,6 +147,7 @@ export class CellDiffSingleSideRenderer implements IListRenderer Date: Tue, 11 Oct 2022 20:25:51 -0700 Subject: [PATCH 515/599] Finalize notebookDebugOptions API (#163316) * Finalize notebookDebugOptions API Fix #147264 * Backcompat for the option from vscode-jupyter * Undo comment * Fix build --- extensions/vscode-api-tests/package.json | 1 - .../api/browser/mainThreadDebugService.ts | 7 +++-- .../workbench/api/common/extHost.protocol.ts | 6 ++-- .../api/common/extHostDebugService.ts | 8 +++-- .../contrib/debug/browser/callStackView.ts | 4 --- .../contrib/debug/browser/debugService.ts | 2 +- .../contrib/debug/browser/debugSession.ts | 15 ++++++++-- .../contrib/debug/browser/debugToolBar.ts | 8 ++++- .../debug/browser/statusbarColorProvider.ts | 10 ++----- .../workbench/contrib/debug/common/debug.ts | 10 ++++--- .../debug/test/browser/baseDebugView.test.ts | 16 ++++++---- .../contrib/debug/test/browser/mockDebug.ts | 3 ++ .../common/extensionsApiProposals.ts | 1 - src/vscode-dts/vscode.d.ts | 20 +++++++++++++ .../vscode.proposed.notebookDebugOptions.d.ts | 29 ------------------- 15 files changed, 77 insertions(+), 63 deletions(-) delete mode 100644 src/vscode-dts/vscode.proposed.notebookDebugOptions.d.ts diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index c705e53d1fa..36b444e2301 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -20,7 +20,6 @@ "notebookCellExecutionState", "notebookContentProvider", "notebookControllerKind", - "notebookDebugOptions", "notebookDeprecated", "notebookLiveShare", "notebookMessaging", diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index a9ee9c85cfb..a459965d108 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -230,9 +230,12 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb lifecycleManagedByParent: options.lifecycleManagedByParent, repl: options.repl, compact: options.compact, - debugUI: options.debugUI, compoundRoot: parentSession?.compoundRoot, - saveBeforeRestart: saveBeforeStart + saveBeforeRestart: saveBeforeStart, + + suppressDebugStatusbar: options.suppressDebugStatusbar, + suppressDebugToolbar: options.suppressDebugToolbar, + suppressDebugView: options.suppressDebugView, }; try { return this.debugService.startDebugging(launch, nameOrConfig, debugOptions, saveBeforeStart); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 47395e37724..3bb8699d408 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1226,9 +1226,9 @@ export interface IStartDebuggingOptions { repl?: IDebugSessionReplMode; noDebug?: boolean; compact?: boolean; - debugUI?: { - simple?: boolean; - }; + suppressDebugToolbar?: boolean; + suppressDebugStatusbar?: boolean; + suppressDebugView?: boolean; suppressSaveBeforeStart?: boolean; } diff --git a/src/vs/workbench/api/common/extHostDebugService.ts b/src/vs/workbench/api/common/extHostDebugService.ts index 9e0e03f1379..ba7e411aee1 100644 --- a/src/vs/workbench/api/common/extHostDebugService.ts +++ b/src/vs/workbench/api/common/extHostDebugService.ts @@ -285,8 +285,12 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate', noDebug: options.noDebug, compact: options.compact, - debugUI: options.debugUI, - suppressSaveBeforeStart: options.suppressSaveBeforeStart + suppressSaveBeforeStart: options.suppressSaveBeforeStart, + + // Check debugUI for back-compat, #147264 + suppressDebugStatusbar: options.suppressDebugStatusbar ?? (options as any).debugUI?.simple, + suppressDebugToolbar: options.suppressDebugToolbar ?? (options as any).debugUI?.simple, + suppressDebugView: options.suppressDebugView ?? (options as any).debugUI?.simple, }); } diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index fb4c19d14da..fe90489df17 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -695,10 +695,6 @@ class ThreadsRenderer implements ICompressibleTreeRenderer, FuzzyScore>, index: number, templateData: IThreadTemplateData, height: number | undefined): void { - templateData.elementDisposable.clear(); - } - disposeTemplate(templateData: IThreadTemplateData): void { templateData.templateDisposable.dispose(); } diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index ff82f476352..aa117289421 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -571,7 +571,7 @@ export class DebugService implements IDebugService { const openDebug = this.configurationService.getValue('debug').openDebug; // Open debug viewlet based on the visibility of the side bar and openDebug setting. Do not open for 'run without debug' - if (!configuration.resolved.noDebug && (openDebug === 'openOnSessionStart' || (openDebug !== 'neverOpen' && this.viewModel.firstSessionStart)) && !session.isSimpleUI) { + if (!configuration.resolved.noDebug && (openDebug === 'openOnSessionStart' || (openDebug !== 'neverOpen' && this.viewModel.firstSessionStart)) && !session.suppressDebugView) { await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar); } diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 2dd3ebf0241..57597ac5458 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -172,10 +172,19 @@ export class DebugSession implements IDebugSession { return this._options.compoundRoot; } - get isSimpleUI(): boolean { - return this._options.debugUI?.simple ?? false; + get suppressDebugStatusbar(): boolean { + return this._options.suppressDebugStatusbar ?? false; } + get suppressDebugToolbar(): boolean { + return this._options.suppressDebugToolbar ?? false; + } + + get suppressDebugView(): boolean { + return this._options.suppressDebugView ?? false; + } + + get autoExpandLazyVariables(): boolean { // This tiny helper avoids converting the entire debug model to use service injection return this.configurationService.getValue('debug').autoExpandLazyVariables; @@ -971,7 +980,7 @@ export class DebugSession implements IDebugSession { } if (thread.stoppedDetails) { - if (thread.stoppedDetails.reason === 'breakpoint' && this.configurationService.getValue('debug').openDebug === 'openOnDebugBreak' && !this.isSimpleUI) { + if (thread.stoppedDetails.reason === 'breakpoint' && this.configurationService.getValue('debug').openDebug === 'openOnDebugBreak' && !this.suppressDebugView) { await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar); } diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 8836e317cc9..68a459f09c6 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -99,7 +99,13 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { this.updateScheduler = this._register(new RunOnceScheduler(() => { const state = this.debugService.state; const toolBarLocation = this.configurationService.getValue('debug').toolBarLocation; - if (state === State.Inactive || toolBarLocation === 'docked' || toolBarLocation === 'hidden' || this.debugService.getViewModel().focusedSession?.isSimpleUI || (state === State.Initializing && this.debugService.initializingOptions?.debugUI?.simple)) { + if ( + state === State.Inactive || + toolBarLocation === 'docked' || + toolBarLocation === 'hidden' || + this.debugService.getModel().getSessions().every(s => s.suppressDebugToolbar) || + (state === State.Initializing && this.debugService.initializingOptions?.suppressDebugToolbar) + ) { return this.hide(); } diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index 5ec8c29bae1..0932492fc82 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -69,7 +69,7 @@ export class StatusBarColorProvider implements IWorkbenchContribution { } protected update(): void { - this.enabled = isStatusbarInDebugMode(this.debugService.state, this.debugService.getViewModel().focusedSession); + this.enabled = isStatusbarInDebugMode(this.debugService.state, this.debugService.getModel().getSessions()); } dispose(): void { @@ -78,12 +78,8 @@ export class StatusBarColorProvider implements IWorkbenchContribution { } } -export function isStatusbarInDebugMode(state: State, session: IDebugSession | undefined): boolean { - if (state === State.Inactive || state === State.Initializing || session?.isSimpleUI) { - return false; - } - const isRunningWithoutDebug = session?.configuration?.noDebug; - if (isRunningWithoutDebug) { +export function isStatusbarInDebugMode(state: State, sessions: IDebugSession[]): boolean { + if (state === State.Inactive || state === State.Initializing || sessions.every(s => s.suppressDebugStatusbar || s.configuration?.noDebug)) { return false; } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 1c800a672ce..3480cdecf3f 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -203,11 +203,11 @@ export interface IDebugSessionOptions { repl?: IDebugSessionReplMode; compoundRoot?: DebugCompoundRoot; compact?: boolean; - debugUI?: { - simple?: boolean; - }; startedByUser?: boolean; saveBeforeRestart?: boolean; + suppressDebugToolbar?: boolean; + suppressDebugStatusbar?: boolean; + suppressDebugView?: boolean; } export interface IDataBreakpointInfoResponse { @@ -300,8 +300,10 @@ export interface IDebugSession extends ITreeElement { readonly compoundRoot: DebugCompoundRoot | undefined; readonly saveBeforeRestart: boolean; readonly name: string; - readonly isSimpleUI: boolean; readonly autoExpandLazyVariables: boolean; + readonly suppressDebugToolbar: boolean; + readonly suppressDebugStatusbar: boolean; + readonly suppressDebugView: boolean; setSubId(subId: string | undefined): void; diff --git a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts index ab592668f64..a6169299daa 100644 --- a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts @@ -133,11 +133,17 @@ suite('Debug - Base Debug View', () => { test('statusbar in debug mode', () => { const model = createMockDebugModel(); const session = createMockSession(model); - assert.strictEqual(isStatusbarInDebugMode(State.Inactive, undefined), false); - assert.strictEqual(isStatusbarInDebugMode(State.Initializing, session), false); - assert.strictEqual(isStatusbarInDebugMode(State.Running, session), true); - assert.strictEqual(isStatusbarInDebugMode(State.Stopped, session), true); + const session2 = createMockSession(model, undefined, { suppressDebugStatusbar: true }); + assert.strictEqual(isStatusbarInDebugMode(State.Inactive, []), false); + assert.strictEqual(isStatusbarInDebugMode(State.Initializing, [session]), false); + assert.strictEqual(isStatusbarInDebugMode(State.Running, [session]), true); + assert.strictEqual(isStatusbarInDebugMode(State.Stopped, [session]), true); + + assert.strictEqual(isStatusbarInDebugMode(State.Running, [session2]), false); + assert.strictEqual(isStatusbarInDebugMode(State.Running, [session, session2]), true); + session.configuration.noDebug = true; - assert.strictEqual(isStatusbarInDebugMode(State.Running, session), false); + assert.strictEqual(isStatusbarInDebugMode(State.Running, [session]), false); + assert.strictEqual(isStatusbarInDebugMode(State.Running, [session, session2]), false); }); }); diff --git a/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts b/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts index 44eff810343..13df888a098 100644 --- a/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts @@ -168,6 +168,9 @@ export class MockDebugService implements IDebugService { } export class MockSession implements IDebugSession { + readonly suppressDebugToolbar = false; + readonly suppressDebugStatusbar = false; + readonly suppressDebugView = false; readonly autoExpandLazyVariables = false; getMemory(memoryReference: string): IMemoryRegion { diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index b0c572aeeea..facd28600fb 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -42,7 +42,6 @@ export const allApiProposals = Object.freeze({ notebookContentProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookContentProvider.d.ts', notebookControllerAffinityHidden: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookControllerAffinityHidden.d.ts', notebookControllerKind: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookControllerKind.d.ts', - notebookDebugOptions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookDebugOptions.d.ts', notebookDeprecated: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookDeprecated.d.ts', notebookEditor: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookEditor.d.ts', notebookKernelSource: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookKernelSource.d.ts', diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 8de4fa1ee08..ebabd4c8827 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -14828,6 +14828,26 @@ declare module 'vscode' { * If compact is true, debug sessions with a single child are hidden in the CALL STACK view to make the tree more compact. */ compact?: boolean; + + /** + * When true, a save will not be triggered for open editors when starting a debug session, regardless of the value of the `debug.saveBeforeStart` setting. + */ + suppressSaveBeforeStart?: boolean; + + /** + * When true, the debug toolbar will not be shown for this session. + */ + suppressDebugToolbar?: boolean; + + /** + * When true, the window statusbar color will not be changed for this session. + */ + suppressDebugStatusbar?: boolean; + + /** + * When true, the debug viewlet will not be automatically revealed for this session. + */ + suppressDebugView?: boolean; } /** diff --git a/src/vscode-dts/vscode.proposed.notebookDebugOptions.d.ts b/src/vscode-dts/vscode.proposed.notebookDebugOptions.d.ts deleted file mode 100644 index a05e21671b3..00000000000 --- a/src/vscode-dts/vscode.proposed.notebookDebugOptions.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - // eslint-disable-next-line local/vscode-dts-region-comments - // @roblourens: debugUI.simple: https://github.com/microsoft/vscode/issues/147264. Used for Jupyter's Run By Line. - // suppressSaveBeforeStart: https://github.com/microsoft/vscode/issues/147263. Used to enable debugging untitled/unsaved notebooks. - - /** - * Options for {@link debug.startDebugging starting a debug session}. - */ - export interface DebugSessionOptions { - - debugUI?: { - /** - * When true, the debug toolbar will not be shown for this session, the window statusbar color will not be changed, and the debug viewlet will not be automatically revealed. - */ - simple?: boolean; - }; - - /** - * When true, a save will not be triggered for open editors when starting a debug session, regardless of the value of the `debug.saveBeforeStart` setting. - */ - suppressSaveBeforeStart?: boolean; - } -} From 24b8eb0d548828db3de30f1a33c4dcebb460047b Mon Sep 17 00:00:00 2001 From: Jean Pierre Date: Tue, 11 Oct 2022 22:59:54 -0500 Subject: [PATCH 516/599] Fixes simple browser webview is not reused if restored (#163389) Fixes #163387 --- extensions/simple-browser/src/simpleBrowserManager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/simple-browser/src/simpleBrowserManager.ts b/extensions/simple-browser/src/simpleBrowserManager.ts index 9d59c1816ab..25a4e9175f5 100644 --- a/extensions/simple-browser/src/simpleBrowserManager.ts +++ b/extensions/simple-browser/src/simpleBrowserManager.ts @@ -34,7 +34,9 @@ export class SimpleBrowserManager { const url = state?.url ?? ''; const view = SimpleBrowserView.restore(this.extensionUri, url, panel); this.registerWebviewListeners(view); - return; + if (!this._activeView) { + this._activeView = view; + } } private registerWebviewListeners(view: SimpleBrowserView) { @@ -46,4 +48,3 @@ export class SimpleBrowserManager { } } - From 3e4e3518165e78181d2275e7745a8a59cea32e18 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 11 Oct 2022 21:24:43 -0700 Subject: [PATCH 517/599] Enforce ILocalizedString usage with f1 property via types (#162991) * Enforce ILocalizedString usage with f1 property via types * complete comment * Visit all symbols when encountering a union type * use ILocalizedString * fix tests Co-authored-by: Alex Dima --- build/lib/treeshaking.js | 116 +++++++++------- build/lib/treeshaking.ts | 128 ++++++++++-------- src/vs/platform/actions/common/actions.ts | 43 +++++- .../browser/extensions.contribution.ts | 8 +- .../commands/abstractSnippetsActions.ts | 4 +- .../browser/commands/configureSnippets.ts | 2 +- .../terminal/browser/terminalActions.ts | 2 +- .../browser/keybindingsEditorModel.test.ts | 2 +- 8 files changed, 183 insertions(+), 122 deletions(-) diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index ff18694436d..029235f7709 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -490,54 +490,56 @@ function markNodes(ts, languageService, options) { } const nodeSourceFile = node.getSourceFile(); const loop = (node) => { - const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); - if (symbolImportNode) { - setColor(symbolImportNode, 2 /* NodeColor.Black */); - const importDeclarationNode = findParentImportDeclaration(symbolImportNode); - if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { - enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); + const symbols = getRealNodeSymbol(ts, checker, node); + for (const { symbol, symbolImportNode } of symbols) { + if (symbolImportNode) { + setColor(symbolImportNode, 2 /* NodeColor.Black */); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); + } } - } - if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { - for (let i = 0, len = symbol.declarations.length; i < len; i++) { - const declaration = symbol.declarations[i]; - if (ts.isSourceFile(declaration)) { - // Do not enqueue full source files - // (they can be the declaration of a module import) - continue; - } - if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { - enqueue_black(declaration.name); - for (let j = 0; j < declaration.members.length; j++) { - const member = declaration.members[j]; - const memberName = member.name ? member.name.getText() : null; - if (ts.isConstructorDeclaration(member) - || ts.isConstructSignatureDeclaration(member) - || ts.isIndexSignatureDeclaration(member) - || ts.isCallSignatureDeclaration(member) - || memberName === '[Symbol.iterator]' - || memberName === '[Symbol.toStringTag]' - || memberName === 'toJSON' - || memberName === 'toString' - || memberName === 'dispose' // TODO: keeping all `dispose` methods - || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... - ) { - enqueue_black(member); + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + for (let i = 0, len = symbol.declarations.length; i < len; i++) { + const declaration = symbol.declarations[i]; + if (ts.isSourceFile(declaration)) { + // Do not enqueue full source files + // (they can be the declaration of a module import) + continue; + } + if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { + enqueue_black(declaration.name); + for (let j = 0; j < declaration.members.length; j++) { + const member = declaration.members[j]; + const memberName = member.name ? member.name.getText() : null; + if (ts.isConstructorDeclaration(member) + || ts.isConstructSignatureDeclaration(member) + || ts.isIndexSignatureDeclaration(member) + || ts.isCallSignatureDeclaration(member) + || memberName === '[Symbol.iterator]' + || memberName === '[Symbol.toStringTag]' + || memberName === 'toJSON' + || memberName === 'toString' + || memberName === 'dispose' // TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... + ) { + enqueue_black(member); + } + if (isStaticMemberWithSideEffects(ts, member)) { + enqueue_black(member); + } } - if (isStaticMemberWithSideEffects(ts, member)) { - enqueue_black(member); + // queue the heritage clauses + if (declaration.heritageClauses) { + for (const heritageClause of declaration.heritageClauses) { + enqueue_black(heritageClause); + } } } - // queue the heritage clauses - if (declaration.heritageClauses) { - for (const heritageClause of declaration.heritageClauses) { - enqueue_black(heritageClause); - } + else { + enqueue_black(declaration); } } - else { - enqueue_black(declaration); - } } } node.forEachChild(loop); @@ -736,13 +738,20 @@ function findSymbolFromHeritageType(ts, checker, type) { return findSymbolFromHeritageType(ts, checker, type.expression); } if (ts.isIdentifier(type)) { - return getRealNodeSymbol(ts, checker, type)[0]; + const tmp = getRealNodeSymbol(ts, checker, type); + return (tmp.length > 0 ? tmp[0].symbol : null); } if (ts.isPropertyAccessExpression(type)) { return findSymbolFromHeritageType(ts, checker, type.name); } return null; } +class SymbolImportTuple { + constructor(symbol, symbolImportNode) { + this.symbol = symbol; + this.symbolImportNode = symbolImportNode; + } +} /** * Returns the node's symbol and the `import` node (if the symbol resolved from a different module) */ @@ -774,7 +783,7 @@ function getRealNodeSymbol(ts, checker, node) { } if (!ts.isShorthandPropertyAssignment(node)) { if (node.getChildCount() !== 0) { - return [null, null]; + return []; } } const { parent } = node; @@ -820,10 +829,7 @@ function getRealNodeSymbol(ts, checker, node) { const type = checker.getTypeAtLocation(parent.parent); if (name && type) { if (type.isUnion()) { - const prop = type.types[0].getProperty(name); - if (prop) { - symbol = prop; - } + return generateMultipleSymbols(type, name, importNode); } else { const prop = type.getProperty(name); @@ -854,9 +860,19 @@ function getRealNodeSymbol(ts, checker, node) { } } if (symbol && symbol.declarations) { - return [symbol, importNode]; + return [new SymbolImportTuple(symbol, importNode)]; + } + return []; + function generateMultipleSymbols(type, name, importNode) { + const result = []; + for (const t of type.types) { + const prop = t.getProperty(name); + if (prop && prop.declarations) { + result.push(new SymbolImportTuple(prop, importNode)); + } + } + return result; } - return [null, null]; } /** Get the token whose text contains the position */ function getTokenAtPosition(ts, sourceFile, position, allowPositionInLeadingTrivia, includeEndPosition) { diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index ef829426d94..020e567eb72 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -609,58 +609,60 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language const nodeSourceFile = node.getSourceFile(); const loop = (node: ts.Node) => { - const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node); - if (symbolImportNode) { - setColor(symbolImportNode, NodeColor.Black); - const importDeclarationNode = findParentImportDeclaration(symbolImportNode); - if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { - enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); - } - } - - if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { - for (let i = 0, len = symbol.declarations.length; i < len; i++) { - const declaration = symbol.declarations[i]; - if (ts.isSourceFile(declaration)) { - // Do not enqueue full source files - // (they can be the declaration of a module import) - continue; + const symbols = getRealNodeSymbol(ts, checker, node); + for (const { symbol, symbolImportNode } of symbols) { + if (symbolImportNode) { + setColor(symbolImportNode, NodeColor.Black); + const importDeclarationNode = findParentImportDeclaration(symbolImportNode); + if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) { + enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text); } + } - if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { - enqueue_black(declaration.name!); - - for (let j = 0; j < declaration.members.length; j++) { - const member = declaration.members[j]; - const memberName = member.name ? member.name.getText() : null; - if ( - ts.isConstructorDeclaration(member) - || ts.isConstructSignatureDeclaration(member) - || ts.isIndexSignatureDeclaration(member) - || ts.isCallSignatureDeclaration(member) - || memberName === '[Symbol.iterator]' - || memberName === '[Symbol.toStringTag]' - || memberName === 'toJSON' - || memberName === 'toString' - || memberName === 'dispose'// TODO: keeping all `dispose` methods - || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... - ) { - enqueue_black(member); - } - - if (isStaticMemberWithSideEffects(ts, member)) { - enqueue_black(member); - } + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + for (let i = 0, len = symbol.declarations.length; i < len; i++) { + const declaration = symbol.declarations[i]; + if (ts.isSourceFile(declaration)) { + // Do not enqueue full source files + // (they can be the declaration of a module import) + continue; } - // queue the heritage clauses - if (declaration.heritageClauses) { - for (const heritageClause of declaration.heritageClauses) { - enqueue_black(heritageClause); + if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { + enqueue_black(declaration.name!); + + for (let j = 0; j < declaration.members.length; j++) { + const member = declaration.members[j]; + const memberName = member.name ? member.name.getText() : null; + if ( + ts.isConstructorDeclaration(member) + || ts.isConstructSignatureDeclaration(member) + || ts.isIndexSignatureDeclaration(member) + || ts.isCallSignatureDeclaration(member) + || memberName === '[Symbol.iterator]' + || memberName === '[Symbol.toStringTag]' + || memberName === 'toJSON' + || memberName === 'toString' + || memberName === 'dispose'// TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... + ) { + enqueue_black(member); + } + + if (isStaticMemberWithSideEffects(ts, member)) { + enqueue_black(member); + } } + + // queue the heritage clauses + if (declaration.heritageClauses) { + for (const heritageClause of declaration.heritageClauses) { + enqueue_black(heritageClause); + } + } + } else { + enqueue_black(declaration); } - } else { - enqueue_black(declaration); } } } @@ -879,7 +881,8 @@ function findSymbolFromHeritageType(ts: typeof import('typescript'), checker: ts return findSymbolFromHeritageType(ts, checker, type.expression); } if (ts.isIdentifier(type)) { - return getRealNodeSymbol(ts, checker, type)[0]; + const tmp = getRealNodeSymbol(ts, checker, type); + return (tmp.length > 0 ? tmp[0].symbol : null); } if (ts.isPropertyAccessExpression(type)) { return findSymbolFromHeritageType(ts, checker, type.name); @@ -887,10 +890,17 @@ function findSymbolFromHeritageType(ts: typeof import('typescript'), checker: ts return null; } +class SymbolImportTuple { + constructor( + public readonly symbol: ts.Symbol | null, + public readonly symbolImportNode: ts.Declaration | null + ) { } +} + /** * Returns the node's symbol and the `import` node (if the symbol resolved from a different module) */ -function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChecker, node: ts.Node): [ts.Symbol | null, ts.Declaration | null] { +function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChecker, node: ts.Node): SymbolImportTuple[] { // Use some TypeScript internals to avoid code duplication type ObjectLiteralElementWithName = ts.ObjectLiteralElement & { name: ts.PropertyName; parent: ts.ObjectLiteralExpression | ts.JsxAttributes }; @@ -923,7 +933,7 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec if (!ts.isShorthandPropertyAssignment(node)) { if (node.getChildCount() !== 0) { - return [null, null]; + return []; } } @@ -976,10 +986,7 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec const type = checker.getTypeAtLocation(parent.parent); if (name && type) { if (type.isUnion()) { - const prop = type.types[0].getProperty(name); - if (prop) { - symbol = prop; - } + return generateMultipleSymbols(type, name, importNode); } else { const prop = type.getProperty(name); if (prop) { @@ -1011,10 +1018,21 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec } if (symbol && symbol.declarations) { - return [symbol, importNode]; + return [new SymbolImportTuple(symbol, importNode)]; } - return [null, null]; + return []; + + function generateMultipleSymbols(type: ts.UnionType, name: string, importNode: ts.Declaration | null): SymbolImportTuple[] { + const result: SymbolImportTuple[] = []; + for (const t of type.types) { + const prop = t.getProperty(name); + if (prop && prop.declarations) { + result.push(new SymbolImportTuple(prop, importNode)); + } + } + return result; + } } /** Get the token whose text contains the position */ diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 7ea373d798a..c09a7e422a3 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -540,13 +540,7 @@ export class SyncActionDescriptor { type OneOrN = T | T[]; -export interface IAction2Options extends ICommandAction { - - /** - * Shorthand to add this command to the command palette - */ - f1?: boolean; - +interface IAction2CommonOptions extends ICommandAction { /** * One or many menu items. */ @@ -571,6 +565,41 @@ export interface IAction2Options extends ICommandAction { _isFakeAction?: true; } +interface IBaseAction2Options extends IAction2CommonOptions { + + /** + * This type is used when an action is not going to show up in the command palette. + * In that case, it's able to use a string for the `title` and `category` properties. + */ + f1?: false; +} + +interface ICommandPaletteOptions extends IAction2CommonOptions { + + /** + * The title of the command that will be displayed in the command palette after the category. + * This overrides {@link ICommandAction.title} to ensure a string isn't used so that the title + * includes the localized value and the original value for users using language packs. + */ + title: ICommandActionTitle; + + /** + * The category of the command that will be displayed in the command palette before the title suffixed. + * with a colon This overrides {@link ICommandAction.title} to ensure a string isn't used so that + * the title includes the localized value and the original value for users using language packs. + */ + category?: keyof typeof Categories | ILocalizedString; + + /** + * Shorthand to add this command to the command palette. Note: this is not the only way to declare that + * a command should be in the command palette... however, enforcing ILocalizedString in the other scenarios + * is much more challenging and this gets us most of the way there. + */ + f1: true; +} + +export type IAction2Options = ICommandPaletteOptions | IBaseAction2Options; + export interface IAction2F1RequiredOptions { title: ICommandActionTitle; category?: keyof typeof Categories | ILocalizedString; diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 4bbf610ea74..5571c168904 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -448,10 +448,10 @@ async function runAction(action: IAction): Promise { } } -interface IExtensionActionOptions extends IAction2Options { +type IExtensionActionOptions = IAction2Options & { menuTitles?: { [id: string]: string }; run(accessor: ServicesAccessor, ...args: any[]): Promise; -} +}; class ExtensionsContributions extends Disposable implements IWorkbenchContribution { @@ -994,9 +994,8 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi title: { value: localize('extensionUpdates', "Show Extension Updates"), original: 'Show Extension Updates' }, category: ExtensionsLocalizedLabel, precondition: CONTEXT_HAS_GALLERY, + f1: true, menu: [{ - id: MenuId.CommandPalette, - }, { id: extensionsFilterSubMenu, group: '3_installed', when: CONTEXT_HAS_GALLERY, @@ -1049,7 +1048,6 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi id: 'workbench.extensions.action.showDisabledExtensions', title: { value: localize('showDisabledExtensions', "Show Disabled Extensions"), original: 'Show Disabled Extensions' }, category: ExtensionsLocalizedLabel, - menu: [{ id: MenuId.CommandPalette, when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER) diff --git a/src/vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions.ts b/src/vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions.ts index 46f62be9e1c..cf919a8c50b 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions.ts @@ -7,12 +7,12 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { Action2, IAction2Options } from 'vs/platform/actions/common/actions'; -const defaultOptions: Partial = { +const defaultOptions = { category: { value: localize('snippets', 'Snippets'), original: 'Snippets' }, -}; +} as const; export abstract class SnippetsAction extends Action2 { diff --git a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts index 3bc1b0b6b89..baee9823a1f 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts @@ -214,8 +214,8 @@ export class ConfigureSnippets extends SnippetsAction { mnemonicTitle: nls.localize({ key: 'miOpenSnippets', comment: ['&& denotes a mnemonic'] }, "User &&Snippets"), original: 'User Snippets' }, + f1: true, menu: [ - { id: MenuId.CommandPalette }, { id: MenuId.MenubarPreferencesMenu, group: '3_snippets', order: 1 }, { id: MenuId.GlobalActivity, group: '3_snippets', order: 1 }, ] diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 6540fbab441..3dd0ba3046a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -2234,7 +2234,7 @@ export function registerTerminalActions() { id: TerminalCommandId.ShowTextureAtlas, title: { value: localize('workbench.action.terminal.showTextureAtlas', "Show Terminal Texture Atlas"), original: 'Show Terminal Texture Atlas' }, f1: true, - category: Categories.Developer.value, + category: Categories.Developer, precondition: ContextKeyExpr.or(TerminalContextKeys.isOpen) }); } diff --git a/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts index 62c6d2c84fa..aa3fcee7718 100644 --- a/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts @@ -672,7 +672,7 @@ suite('KeybindingsEditorModel', () => { constructor() { super({ id: command, - title, + title: { value: title, original: title }, f1: true }); } From 72a982d0d3f9279bd5e0a594ddba771313012b3d Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 12 Oct 2022 09:08:09 +0200 Subject: [PATCH 518/599] Fix typo in regex (#163404) --- build/lib/standalone.js | 2 +- build/lib/standalone.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/lib/standalone.js b/build/lib/standalone.js index 1121e56ff94..80accea5f4e 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -180,7 +180,7 @@ function createESMSourcesAndResources2(options) { + relativePath + fileContents.substring(end + 1)); } - fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { + fileContents = fileContents.replace(/import ([a-zA-Z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { return `import * as ${m1} from ${m2};`; }); write(getDestAbsoluteFilePath(file), fileContents); diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index f2181e6f274..775a1be5996 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -212,7 +212,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { ); } - fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { + fileContents = fileContents.replace(/import ([a-zA-Z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) { return `import * as ${m1} from ${m2};`; }); From 8c946e23f45f39fdd982cff1e1fce02a8e3dc719 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 12 Oct 2022 09:12:39 +0200 Subject: [PATCH 519/599] Git - Fix typo in setting description (#163400) Fix typo in setting description --- extensions/git/package.nls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index fdc97d8afa2..104aaa6479e 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -128,7 +128,7 @@ "config.checkoutType.remote": "Remote branches", "config.branchPrefix": "Prefix used when creating a new branch.", "config.branchProtection": "List of protected branches. By default, a prompt is shown before changes are committed to a protected branch. The prompt can be controlled using the `#git.branchProtectionPrompt#` setting.", - "config.branchProtectionPrompt": "Controls whether a prompt is being before changes are committed to a protected branch.", + "config.branchProtectionPrompt": "Controls whether a prompt is being shown before changes are committed to a protected branch.", "config.branchProtectionPrompt.alwaysCommit": "Always commit changes to the protected branch.", "config.branchProtectionPrompt.alwaysCommitToNewBranch": "Always commit changes to a new branch.", "config.branchProtectionPrompt.alwaysPrompt": "Always prompt before changes are committed to a protected branch.", From a3d8c337610dec6dbd24f4250639715327fb613f Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 12 Oct 2022 11:22:48 +0200 Subject: [PATCH 520/599] Revert "Clean up how the notebook renderer entrypoint is passed around (#163373)" This reverts commit 8b0248854a4c6996ddea13e30dcc4fb0b56ef53b. Workaround for https://github.com/microsoft/vscode/issues/163415 --- .../browser/notebookExtensionPoint.ts | 4 +-- .../view/renderers/backLayerWebView.ts | 8 ++--- .../browser/view/renderers/webviewMessages.ts | 3 +- .../browser/view/renderers/webviewPreloads.ts | 8 ++--- .../contrib/notebook/common/notebookCommon.ts | 20 ++++++------ .../notebook/common/notebookOutputRenderer.ts | 31 ++++++++++++------- 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts index f28fc03d29b..651082499a8 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts @@ -6,7 +6,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { NotebookEditorPriority, ContributedNotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookEditorPriority, NotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const NotebookEditorContribution = Object.freeze({ type: 'type', @@ -36,7 +36,7 @@ export interface INotebookRendererContribution { readonly [NotebookRendererContribution.id]?: string; readonly [NotebookRendererContribution.displayName]: string; readonly [NotebookRendererContribution.mimeTypes]?: readonly string[]; - readonly [NotebookRendererContribution.entrypoint]: ContributedNotebookRendererEntrypoint; + readonly [NotebookRendererContribution.entrypoint]: NotebookRendererEntrypoint; readonly [NotebookRendererContribution.hardDependencies]: readonly string[]; readonly [NotebookRendererContribution.optionalDependencies]: readonly string[]; readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index ba6810f0afb..f01090a0561 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -403,14 +403,12 @@ export class BackLayerWebView extends Disposable { private getRendererData(): RendererMetadata[] { return this.notebookService.getRenderers().map((renderer): RendererMetadata => { - const entrypoint = { - extends: renderer.entrypoint.extends, - path: this.asWebviewUri(renderer.entrypoint.path, renderer.extensionLocation).toString() - }; + const entrypoint = this.asWebviewUri(renderer.entrypoint, renderer.extensionLocation).toString(); return { id: renderer.id, entrypoint, mimeTypes: renderer.mimeTypes, + extends: renderer.extends, messaging: renderer.messaging !== RendererMessagingSpec.Never, isBuiltin: renderer.isBuiltin }; @@ -925,7 +923,7 @@ var requirejs = (function() { const notebookDir = this.getNotebookBaseUri(); return [ ...this.notebookService.getNotebookProviderResourceRoots(), - ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint.path)), + ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint)), ...workspaceFolders, notebookDir, ...this.getBuiltinLocalResourceRoots() diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 8b0902ba129..79adc52e51e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -275,8 +275,9 @@ export interface IUpdateControllerPreloadsMessage { export interface RendererMetadata { readonly id: string; - readonly entrypoint: { readonly extends: string | undefined; readonly path: string }; + readonly entrypoint: string; readonly mimeTypes: readonly string[]; + readonly extends: string | undefined; readonly messaging: boolean; readonly isBuiltin: boolean; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index c5817113f92..6062c79818c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1314,7 +1314,7 @@ async function webviewPreloads(ctx: PreloadContext) { /** Inner function cached in the _loadPromise(). */ private async _load(): Promise { - const module: RendererModule = await __import(this.data.entrypoint.path); + const module: RendererModule = await __import(this.data.entrypoint); if (!module) { return; } @@ -1324,7 +1324,7 @@ async function webviewPreloads(ctx: PreloadContext) { // Load all renderers that extend this renderer await Promise.all( ctx.rendererData - .filter(d => d.entrypoint.extends === this.data.id) + .filter(d => d.extends === this.data.id) .map(async d => { const renderer = renderers.getRenderer(d.id); if (!renderer) { @@ -1436,7 +1436,7 @@ async function webviewPreloads(ctx: PreloadContext) { } private rendererEqual(a: webviewMessages.RendererMetadata, b: webviewMessages.RendererMetadata) { - if (a.id !== b.id || a.entrypoint.path !== b.entrypoint.path || a.entrypoint.extends !== b.entrypoint.extends || a.messaging !== b.messaging) { + if (a.entrypoint !== b.entrypoint || a.id !== b.id || a.extends !== b.extends || a.messaging !== b.messaging) { return false; } @@ -1497,7 +1497,7 @@ async function webviewPreloads(ctx: PreloadContext) { .find((renderer) => renderer.data.id === preferredRendererId); } else { const renderers = Array.from(this._renderers.values()) - .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.entrypoint.extends); + .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends); if (renderers.length) { // De-prioritize built-in renderers diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 403a07a082f..0e2f1fe9ea6 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -75,7 +75,7 @@ export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap; + extensionLocation: URI; + extensionId: ExtensionIdentifier; + messaging: RendererMessagingSpec; readonly mimeTypes: readonly string[]; + readonly dependencies: readonly string[]; + readonly isBuiltin: boolean; matchesWithoutKernel(mimeType: string): NotebookRendererMatch; diff --git a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts index ab8c71a1294..e22c7fd486f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts @@ -8,7 +8,7 @@ import { Iterable } from 'vs/base/common/iterator'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { INotebookRendererInfo, ContributedNotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec, NotebookRendererEntrypoint } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookRendererInfo, NotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; class DependencyList { private readonly value: ReadonlySet; @@ -19,6 +19,10 @@ class DependencyList { this.defined = this.value.size > 0; } + public values(): string[] { + return Array.from(this.value); + } + /** Gets whether any of the 'available' dependencies match the ones in this list */ public matches(available: ReadonlyArray) { // For now this is simple, but this may expand to support globs later @@ -30,13 +34,17 @@ class DependencyList { export class NotebookOutputRendererInfo implements INotebookRendererInfo { readonly id: string; - readonly entrypoint: NotebookRendererEntrypoint; + readonly extends?: string; + readonly entrypoint: URI; readonly displayName: string; readonly extensionLocation: URI; readonly extensionId: ExtensionIdentifier; readonly hardDependencies: DependencyList; readonly optionalDependencies: DependencyList; + /** @see RendererMessagingSpec */ readonly messaging: RendererMessagingSpec; + // todo: re-add preloads in pure renderer API + readonly preloads: ReadonlyArray = []; readonly mimeTypes: readonly string[]; private readonly mimeTypeGlobs: glob.ParsedPattern[]; @@ -46,7 +54,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { constructor(descriptor: { readonly id: string; readonly displayName: string; - readonly entrypoint: ContributedNotebookRendererEntrypoint; + readonly entrypoint: NotebookRendererEntrypoint; readonly mimeTypes: readonly string[]; readonly extension: IExtensionDescription; readonly dependencies: readonly string[] | undefined; @@ -59,15 +67,10 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.isBuiltin = descriptor.extension.isBuiltin; if (typeof descriptor.entrypoint === 'string') { - this.entrypoint = { - extends: undefined, - path: joinPath(this.extensionLocation, descriptor.entrypoint) - }; + this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint); } else { - this.entrypoint = { - extends: descriptor.entrypoint.extends, - path: joinPath(this.extensionLocation, descriptor.entrypoint.path) - }; + this.extends = descriptor.entrypoint.extends; + this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint.path); } this.displayName = descriptor.displayName; @@ -78,6 +81,10 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.messaging = descriptor.requiresMessaging ?? RendererMessagingSpec.Never; } + public get dependencies(): string[] { + return this.hardDependencies.values(); + } + public matchesWithoutKernel(mimeType: string) { if (!this.matchesMimeTypeOnly(mimeType)) { return NotebookRendererMatch.Never; @@ -111,7 +118,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { } private matchesMimeTypeOnly(mimeType: string) { - if (!URI.isUri(this.entrypoint)) { // We're extending another renderer + if (this.extends !== undefined) { return false; } From 44673c2129d4bb1294478f84be5f4fa9c9aa4355 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 12 Oct 2022 12:38:48 +0200 Subject: [PATCH 521/599] add more logging (#163419) * add more logging * fix tests: check remote.all for remote change --- .../userDataSync/common/globalStateMerge.ts | 14 ++---- .../userDataSync/common/globalStateSync.ts | 14 +++--- .../test/common/globalStateMerge.test.ts | 50 +++++++++---------- .../views/common/viewContainerModel.ts | 22 ++++++-- 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/vs/platform/userDataSync/common/globalStateMerge.ts b/src/vs/platform/userDataSync/common/globalStateMerge.ts index 8f2e51bb67d..930706f3c15 100644 --- a/src/vs/platform/userDataSync/common/globalStateMerge.ts +++ b/src/vs/platform/userDataSync/common/globalStateMerge.ts @@ -10,18 +10,18 @@ import { IStorageValue, SYNC_SERVICE_URL_TYPE } from 'vs/platform/userDataSync/c export interface IMergeResult { local: { added: IStringDictionary; removed: string[]; updated: IStringDictionary }; - remote: IStringDictionary | null; + remote: { added: string[]; removed: string[]; updated: string[]; all: IStringDictionary | null }; } export function merge(localStorage: IStringDictionary, remoteStorage: IStringDictionary | null, baseStorage: IStringDictionary | null, storageKeys: { machine: ReadonlyArray; unregistered: ReadonlyArray }, logService: ILogService): IMergeResult { if (!remoteStorage) { - return { remote: Object.keys(localStorage).length > 0 ? localStorage : null, local: { added: {}, removed: [], updated: {} } }; + return { remote: { added: Object.keys(localStorage), removed: [], updated: [], all: Object.keys(localStorage).length > 0 ? localStorage : null }, local: { added: {}, removed: [], updated: {} } }; } const localToRemote = compare(localStorage, remoteStorage); if (localToRemote.added.size === 0 && localToRemote.removed.size === 0 && localToRemote.updated.size === 0) { // No changes found between local and remote. - return { remote: null, local: { added: {}, removed: [], updated: {} } }; + return { remote: { added: [], removed: [], updated: [], all: null }, local: { added: {}, removed: [], updated: {} } }; } const baseToRemote = baseStorage ? compare(baseStorage, remoteStorage) : { added: Object.keys(remoteStorage).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; @@ -116,7 +116,8 @@ export function merge(localStorage: IStringDictionary, remoteStor local.removed.push(key); } - return { local, remote: areSame(remote, remoteStorage) ? null : remote }; + const result = compare(remoteStorage, remote); + return { local, remote: { added: [...result.added], updated: [...result.updated], removed: [...result.removed], all: result.added.size === 0 && result.removed.size === 0 && result.updated.size === 0 ? null : remote } }; } function compare(from: IStringDictionary, to: IStringDictionary): { added: Set; removed: Set; updated: Set } { @@ -140,8 +141,3 @@ function compare(from: IStringDictionary, to: IStringDictionary): { ad return { added, removed, updated }; } -function areSame(a: IStringDictionary, b: IStringDictionary): boolean { - const { added, removed, updated } = compare(a, b); - return added.size === 0 && removed.size === 0 && updated.size === 0; -} - diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index e10896d7bf8..eabf5326051 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -37,7 +37,7 @@ type StorageKeys = { machine: string[]; user: string[]; unregistered: string[] } interface IGlobalStateResourceMergeResult extends IAcceptResult { readonly local: { added: IStringDictionary; removed: string[]; updated: IStringDictionary }; - readonly remote: IStringDictionary | null; + readonly remote: { added: string[]; removed: string[]; updated: string[]; all: IStringDictionary | null }; } export interface IGlobalStateResourcePreview extends IResourcePreview { @@ -133,7 +133,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs local, remote, localChange: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0 ? Change.Modified : Change.None, - remoteChange: remote !== null ? Change.Modified : Change.None, + remoteChange: remote.all !== null ? Change.Modified : Change.None, }; const localContent = stringify(localGlobalState, false); @@ -162,7 +162,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs const localGlobalState = await this.getLocalGlobalState(); const storageKeys = await this.getStorageKeys(lastSyncGlobalState); const { remote } = merge(localGlobalState.storage, lastSyncGlobalState.storage, lastSyncGlobalState.storage, storageKeys, this.logService); - return remote !== null; + return remote.all !== null; } protected async getMergeResult(resourcePreview: IGlobalStateResourcePreview, token: CancellationToken): Promise { @@ -193,7 +193,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs return { content: resourcePreview.localContent, local: { added: {}, removed: [], updated: {} }, - remote: resourcePreview.localUserData.storage, + remote: { added: Object.keys(resourcePreview.localUserData.storage), removed: [], updated: [], all: resourcePreview.localUserData.storage }, localChange: Change.None, remoteChange: Change.Modified, }; @@ -214,7 +214,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs return { content: resourcePreview.remoteContent, local: { added: {}, removed: [], updated: {} }, - remote: null, + remote: { added: [], removed: [], updated: [], all: null }, localChange: Change.None, remoteChange: Change.None, }; @@ -240,9 +240,9 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs if (remoteChange !== Change.None) { // update remote this.logService.trace(`${this.syncResourceLogLabel}: Updating remote ui state...`); - const content = JSON.stringify({ storage: remote }); + const content = JSON.stringify({ storage: remote.all }); remoteUserData = await this.updateRemoteUserData(content, force ? null : remoteUserData.ref); - this.logService.info(`${this.syncResourceLogLabel}: Updated remote ui state`); + this.logService.info(`${this.syncResourceLogLabel}: Updated remote ui state.${remote.added.length ? ` Added: ${remote.added}.` : ''}${remote.updated.length ? ` Updated: ${remote.updated}.` : ''}${remote.removed.length ? ` Removed: ${remote.removed}.` : ''}`); } if (lastSyncUserData?.ref !== remoteUserData.ref) { diff --git a/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts b/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts index 50ff413ed27..be518dba470 100644 --- a/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts +++ b/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts @@ -18,7 +18,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when local and remote are same with multiple entries and local is not synced yet', async () => { @@ -30,7 +30,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when local and remote are same with multiple entries in different order and local is not synced yet', async () => { @@ -42,7 +42,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when local and remote are same with different base content', async () => { @@ -55,7 +55,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when a new entry is added to remote and local has not synced yet', async () => { @@ -67,7 +67,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, { 'b': { version: 1, value: 'b' } }); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when multiple new entries are added to remote and local is not synced yet', async () => { @@ -79,7 +79,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, { 'b': { version: 1, value: 'b' }, 'a': { version: 1, value: 'a' } }); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when new entry is added to remote from base and local has not changed', async () => { @@ -91,7 +91,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, { 'b': { version: 1, value: 'b' } }); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when an entry is removed from remote from base and local has not changed', async () => { @@ -103,7 +103,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, ['b']); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when all entries are removed from base and local has not changed', async () => { @@ -115,7 +115,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, ['b', 'a']); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when an entry is updated in remote from base and local has not changed', async () => { @@ -127,7 +127,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, { 'a': { version: 1, value: 'b' } }); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when remote has moved forwarded with multiple changes and local stays with base', async () => { @@ -139,7 +139,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, { 'c': { version: 1, value: 'c' } }); assert.deepStrictEqual(actual.local.updated, { 'a': { version: 1, value: 'd' } }); assert.deepStrictEqual(actual.local.removed, ['b']); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when new entries are added to local and local is not synced yet', async () => { @@ -151,7 +151,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when multiple new entries are added to local from base and remote is not changed', async () => { @@ -163,7 +163,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when an entry is removed from local from base and remote has not changed', async () => { @@ -175,7 +175,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when an entry is updated in local from base and remote has not changed', async () => { @@ -187,7 +187,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when local has moved forwarded with multiple changes and remote stays with base', async () => { @@ -199,7 +199,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when local and remote with one entry but different value and local is not synced yet', async () => { @@ -211,7 +211,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, { 'a': { version: 1, value: 'b' } }); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when the entry is removed in remote but updated in local and a new entry is added in remote', async () => { @@ -224,7 +224,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, { 'c': { version: 1, value: 'c' } }); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, { 'a': { version: 1, value: 'a' }, 'c': { version: 1, value: 'c' }, 'b': { version: 1, value: 'd' } }); + assert.deepStrictEqual(actual.remote.all, { 'a': { version: 1, value: 'a' }, 'c': { version: 1, value: 'c' }, 'b': { version: 1, value: 'd' } }); }); test('merge with single entry and local is empty', async () => { @@ -237,7 +237,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when local and remote has moved forward with conflicts', async () => { @@ -250,7 +250,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when a new entry is added to remote but scoped to machine locally and local is not synced yet', async () => { @@ -262,7 +262,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when an entry is updated to remote but scoped to machine locally', async () => { @@ -274,7 +274,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, null); + assert.deepStrictEqual(actual.remote.all, null); }); test('merge when a local value is removed and scoped to machine locally', async () => { @@ -287,7 +287,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge when local moved forwared by changing a key to machine scope', async () => { @@ -300,7 +300,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, local); + assert.deepStrictEqual(actual.remote.all, local); }); test('merge should not remove remote keys if not registered', async () => { @@ -313,7 +313,7 @@ suite('GlobalStateMerge', () => { assert.deepStrictEqual(actual.local.added, {}); assert.deepStrictEqual(actual.local.updated, {}); assert.deepStrictEqual(actual.local.removed, []); - assert.deepStrictEqual(actual.remote, { 'a': { version: 1, value: 'a' }, 'b': { version: 1, value: 'b' }, 'c': { version: 1, value: 'c' } }); + assert.deepStrictEqual(actual.remote.all, { 'a': { version: 1, value: 'a' }, 'b': { version: 1, value: 'b' }, 'c': { version: 1, value: 'c' } }); }); }); diff --git a/src/vs/workbench/services/views/common/viewContainerModel.ts b/src/vs/workbench/services/views/common/viewContainerModel.ts index 0418f5ee6cd..4bbed6f5ffd 100644 --- a/src/vs/workbench/services/views/common/viewContainerModel.ts +++ b/src/vs/workbench/services/views/common/viewContainerModel.ts @@ -18,6 +18,7 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IStringDictionary } from 'vs/base/common/collections'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; import { localize } from 'vs/nls'; +import { ILogService } from 'vs/platform/log/common/log'; export function getViewsStateStorageId(viewContainerStorageId: string): string { return `${viewContainerStorageId}.hidden`; } @@ -88,6 +89,7 @@ class ViewDescriptorsState extends Disposable { viewContainerStorageId: string, viewContainerName: string, @IStorageService private readonly storageService: IStorageService, + @ILogService private readonly logService: ILogService, ) { super(); @@ -162,6 +164,9 @@ class ViewDescriptorsState extends Disposable { const state = this.get(id); if (state) { if (state.visibleGlobal !== !storedState.isHidden) { + if (!storedState.isHidden) { + this.logService.info(`View visibility state changed: ${id} is now visible`); + } changedStates.push({ id, visible: !storedState.isHidden }); } } else { @@ -348,6 +353,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode readonly viewContainer: ViewContainer, @IInstantiationService instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, + @ILogService private readonly logService: ILogService, ) { super(); @@ -356,10 +362,11 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode this._register(this.viewDescriptorsState.onDidChangeStoredState(items => this.updateVisibility(items))); this._register(Event.any( - this.onDidAddVisibleViewDescriptors, - this.onDidRemoveVisibleViewDescriptors, - this.onDidMoveVisibleViewDescriptors) - (() => { + Event.map(this.onDidAddVisibleViewDescriptors, added => `Added views:${added.map(v => v.viewDescriptor.id).join(',')}`), + Event.map(this.onDidRemoveVisibleViewDescriptors, removed => `Removed views:${removed.map(v => v.viewDescriptor.id).join(',')}`), + Event.map(this.onDidMoveVisibleViewDescriptors, ({ from, to }) => `Moved view ${from.viewDescriptor.id} to ${to.viewDescriptor.id}`)) + (message => { + this.logService.info(message); this.viewDescriptorsState.updateState(this.allViewDescriptors); this.updateContainerInfo(); })); @@ -464,6 +471,9 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode viewDescriptorItem.state.visibleWorkspace = visible; } else { viewDescriptorItem.state.visibleGlobal = visible; + if (visible) { + this.logService.info(`Showing view ${viewDescriptorItem.viewDescriptor.id} in the container ${this.viewContainer.id}`); + } } // return `true` only if visibility is changed @@ -532,7 +542,11 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode if (viewDescriptor.workspace) { state.visibleWorkspace = isUndefinedOrNull(addedViewDescriptorState.visible) ? (isUndefinedOrNull(state.visibleWorkspace) ? !viewDescriptor.hideByDefault : state.visibleWorkspace) : addedViewDescriptorState.visible; } else { + const isVisible = state.visibleGlobal; state.visibleGlobal = isUndefinedOrNull(addedViewDescriptorState.visible) ? (isUndefinedOrNull(state.visibleGlobal) ? !viewDescriptor.hideByDefault : state.visibleGlobal) : addedViewDescriptorState.visible; + if (state.visibleGlobal && !isVisible) { + this.logService.info(`Added view ${viewDescriptor.id} in the container ${this.viewContainer.id} and showing it`); + } } state.collapsed = isUndefinedOrNull(addedViewDescriptorState.collapsed) ? (isUndefinedOrNull(state.collapsed) ? !!viewDescriptor.collapsed : state.collapsed) : addedViewDescriptorState.collapsed; } else { From 9c706ce0d4d57fde08cfab2ce5d3eccc66e6b279 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 12 Oct 2022 13:30:42 +0200 Subject: [PATCH 522/599] Implements #159027 (#163420) --- .../view/editors/resultCodeEditorView.ts | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index af9124ee5a0..dccc796b2ca 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { reset } from 'vs/base/browser/dom'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { CompareResult } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; @@ -67,18 +68,21 @@ export class ResultCodeEditorView extends CodeEditorView { })); - this._register(autorun('update remainingConflicts label', reader => { - // this is a bit of a hack, but it's the easiest way to get the label to update - // when the view model updates, as the the base class resets the label in the setModel call. - this.viewModel.read(reader); + const remainingConflictsActionBar = this._register(new ActionBar(this.htmlElements.detail)); - const model = this.model.read(reader); + this._register(autorun('update remainingConflicts label', reader => { + const vm = this.viewModel.read(reader); + if (!vm) { + return; + } + + const model = vm.model; if (!model) { return; } const count = model.unhandledConflictsCount.read(reader); - this.htmlElements.detail.innerText = count === 1 + const text = count === 1 ? localize( 'mergeEditor.remainingConflicts', '{0} Conflict Remaining', @@ -90,6 +94,19 @@ export class ResultCodeEditorView extends CodeEditorView { count ); + remainingConflictsActionBar.clear(); + remainingConflictsActionBar.push({ + class: undefined, + enabled: count > 0, + id: 'nextConflict', + label: text, + run() { + vm.goToNextModifiedBaseRange(m => !model.isHandled(m).get()); + }, + tooltip: count > 0 + ? localize('goToNextConflict', 'Go to next conflict') + : localize('allConflictHandled', 'All conflicts handled, the merge can be completed now.'), + }); })); From 3e4df233504ef2442cf032924f0aa71923a208cb Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:31:08 +0200 Subject: [PATCH 523/599] Git- get commit input template in parallel with other operations (#163423) --- extensions/git/src/repository.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 48dbdd5065d..d72547f2ab8 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -2035,7 +2035,7 @@ export class Repository implements Disposable { if (sort !== 'alphabetically' && sort !== 'committerdate') { sort = 'alphabetically'; } - const [refs, remotes, submodules, rebaseCommit, mergeInProgress] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit(), this.isMergeInProgress()]); + const [refs, remotes, submodules, rebaseCommit, mergeInProgress, commitTemplate] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit(), this.isMergeInProgress(), this.getInputTemplate()]); this._HEAD = HEAD; this._refs = refs!; @@ -2103,7 +2103,7 @@ export class Repository implements Disposable { this._onDidChangeStatus.fire(); - this._sourceControl.commitTemplate = await this.getInputTemplate(); + this._sourceControl.commitTemplate = commitTemplate; } private setCountBadge(): void { From 3992d5b9abe7c6d3cf0381ef356f32a111e9c979 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:31:31 +0200 Subject: [PATCH 524/599] Git - Show progress indicator while running fetch (#163425) Show progress indicator while running fetch --- extensions/git/src/autofetch.ts | 2 +- extensions/git/src/repository.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/extensions/git/src/autofetch.ts b/extensions/git/src/autofetch.ts index 5a45a522d19..75180de6303 100644 --- a/extensions/git/src/autofetch.ts +++ b/extensions/git/src/autofetch.ts @@ -114,7 +114,7 @@ export class AutoFetcher { try { if (this._fetchAll) { - await this.repository.fetchAll(); + await this.repository.fetchAll({ silent: true }); } else { await this.repository.fetchDefault({ silent: true }); } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index d72547f2ab8..5697163e20d 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -325,6 +325,7 @@ export const enum Operation { Reset = 'Reset', Remote = 'Remote', Fetch = 'Fetch', + FetchNoProgress = 'FetchNoProgress', Pull = 'Pull', Push = 'Push', CherryPick = 'CherryPick', @@ -377,7 +378,7 @@ function isReadOnly(operation: Operation): boolean { function shouldShowProgress(operation: Operation): boolean { switch (operation) { - case Operation.Fetch: + case Operation.FetchNoProgress: case Operation.CheckIgnore: case Operation.GetObjectDetails: case Operation.Show: @@ -1469,8 +1470,8 @@ export class Repository implements Disposable { } @throttle - async fetchAll(cancellationToken?: CancellationToken): Promise { - await this._fetch({ all: true, cancellationToken }); + async fetchAll(options: { silent?: boolean } = {}, cancellationToken?: CancellationToken): Promise { + await this._fetch({ all: true, silent: options.silent, cancellationToken }); } async fetch(options: FetchOptions): Promise { @@ -1484,7 +1485,8 @@ export class Repository implements Disposable { options.prune = prune; } - await this.run(Operation.Fetch, async () => this.repository.fetch(options)); + const operation = options.silent === true ? Operation.FetchNoProgress : Operation.Fetch; + await this.run(operation, async () => this.repository.fetch(options)); } @throttle @@ -1588,7 +1590,7 @@ export class Repository implements Disposable { const fn = async (cancellationToken?: CancellationToken) => { // When fetchOnPull is enabled, fetch all branches when pulling if (fetchOnPull) { - await this.fetchAll(cancellationToken); + await this.fetchAll({}, cancellationToken); } if (await this.checkIfMaybeRebased(this.HEAD?.name)) { From bbc1c35e4c683276b9d3f89c2dcab144576746bc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 05:44:30 -0700 Subject: [PATCH 525/599] Re-use disposable store while rendering elements (#163398) While rendering, the tree renderer currently creates a `DisposableStore` every time `renderElement` is called. For better performance, we should instead re-use a disposable store that is stored on the template data I've also moved some cleanup logic to `disposeElement` instead of putting it in this store. This avoids creating and registering extra disposables --- .../workbench/browser/parts/views/treeView.ts | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index c4ef9dc916c..bf75f767367 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -1024,13 +1024,13 @@ registerThemingParticipant((theme, collector) => { }); interface ITreeExplorerTemplateData { - elementDisposable: IDisposable; - container: HTMLElement; - resourceLabel: IResourceLabel; - icon: HTMLElement; - checkboxContainer: HTMLElement; + readonly elementDisposable: DisposableStore; + readonly container: HTMLElement; + readonly resourceLabel: IResourceLabel; + readonly icon: HTMLElement; + readonly checkboxContainer: HTMLElement; checkbox?: TreeItemCheckbox; - actionBar: ActionBar; + readonly actionBar: ActionBar; } class TreeRenderer extends Disposable implements ITreeRenderer { @@ -1084,7 +1084,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer, index: number, templateData: ITreeExplorerTemplateData): void { - templateData.elementDisposable.dispose(); const node = element.element; const resource = node.resourceUri ? URI.revive(node.resourceUri) : null; const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : (resource ? { label: basename(resource) } : undefined); @@ -1150,10 +1149,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer('explorer.decorations'); @@ -1205,7 +1201,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer this.treeViewsService.removeRenderedTreeItemElement(node))); // remember rendered element this._renderedElements.set(element, templateData); - disposableStore.add({ dispose: () => this._renderedElements.delete(element) }); } private rerender() { @@ -1234,7 +1228,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer { checkbox.dispose(); templateData.checkbox = undefined; } }); } templateData.checkbox.render(node); } @@ -1299,8 +1292,13 @@ class TreeRenderer extends Disposable implements ITreeRenderer, index: number, templateData: ITreeExplorerTemplateData): void { - templateData.elementDisposable.dispose(); + templateData.elementDisposable.clear(); + this._renderedElements.delete(resource); + this.treeViewsService.removeRenderedTreeItemElement(resource.element); + + templateData.checkbox?.dispose(); + templateData.checkbox = undefined; } disposeTemplate(templateData: ITreeExplorerTemplateData): void { From e2dd710d998f0538bde3dffbd330d33339aadc56 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 12 Oct 2022 15:43:11 +0200 Subject: [PATCH 526/599] Revert "Always dispose test editor even if a test fails" This reverts commit 7f17834a595c7f0977ff6407994a8e4f531cc920. --- src/vs/editor/test/browser/testCodeEditor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index 9fb9e854b35..9278f28c685 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -133,7 +133,7 @@ function isTextModel(arg: ITextModel | string | string[] | ITextBufferFactory): function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => void): void; function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise): Promise; -async function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise | void): Promise | void> { +function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise | void): Promise | void { const disposables = new DisposableStore(); const instantiationService = createCodeEditorServices(disposables, options.serviceCollection); delete options.serviceCollection; @@ -149,12 +149,12 @@ async function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBu const editor = disposables.add(instantiateTestCodeEditor(instantiationService, model, options)); const viewModel = editor.getViewModel()!; viewModel.setHasFocus(true); - try { - const result = callback(editor, editor.getViewModel()!, instantiationService); - await result; - } finally { - disposables.dispose(); + const result = callback(editor, editor.getViewModel()!, instantiationService); + if (result) { + return result.then(() => disposables.dispose()); } + + disposables.dispose(); } export function createCodeEditorServices(disposables: DisposableStore, services: ServiceCollection = new ServiceCollection()): TestInstantiationService { From b43c281df20d7f5f8443d500c3fb4974ecafb8f9 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 12 Oct 2022 15:56:36 +0200 Subject: [PATCH 527/599] Git - Attempt to parse HEAD file before invoking git.exe (#162572) * Attempt to parse HEAD file before invoking git.exe * Pull request feedback * Pull request feedback * More pull request feedback --- extensions/git/src/git.ts | 54 +++++++++++++++++++++++++++++-------- extensions/git/src/model.ts | 2 +- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 46d58ce6d90..eaf4dc74163 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -18,6 +18,7 @@ import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git'; import * as byline from 'byline'; import { StringDecoder } from 'string_decoder'; +import { OutputChannelLogger } from './log'; import TelemetryReporter from '@vscode/extension-telemetry'; // https://github.com/microsoft/vscode/issues/65693 @@ -400,8 +401,8 @@ export class Git { return Versions.compare(Versions.fromString(this.version), Versions.fromString(version)); } - open(repository: string, dotGit: { path: string; commonPath?: string }): Repository { - return new Repository(this, repository, dotGit); + open(repository: string, dotGit: { path: string; commonPath?: string }, outputChannelLogger: OutputChannelLogger): Repository { + return new Repository(this, repository, dotGit, outputChannelLogger); } async init(repository: string): Promise { @@ -913,7 +914,8 @@ export class Repository { constructor( private _git: Git, private repositoryRoot: string, - readonly dotGit: { path: string; commonPath?: string } + readonly dotGit: { path: string; commonPath?: string }, + private outputChannelLogger: OutputChannelLogger ) { } get git(): Git { @@ -1996,6 +1998,16 @@ export class Repository { async getHEAD(): Promise { try { + // Attempt to parse the HEAD file + const result = await this.getHEADFS(); + return result; + } + catch (err) { + this.outputChannelLogger.logWarning(err.message); + } + + try { + // Fallback to using git to determine HEAD const result = await this.exec(['symbolic-ref', '--short', 'HEAD']); if (!result.stdout) { @@ -2003,15 +2015,35 @@ export class Repository { } return { name: result.stdout.trim(), commit: undefined, type: RefType.Head }; - } catch (err) { - const result = await this.exec(['rev-parse', 'HEAD']); - - if (!result.stdout) { - throw new Error('Error parsing HEAD'); - } - - return { name: undefined, commit: result.stdout.trim(), type: RefType.Head }; } + catch (err) { } + + // Detached HEAD + const result = await this.exec(['rev-parse', 'HEAD']); + + if (!result.stdout) { + throw new Error('Error parsing HEAD'); + } + + return { name: undefined, commit: result.stdout.trim(), type: RefType.Head }; + } + + async getHEADFS(): Promise { + const raw = await fs.readFile(path.join(this.dotGit.commonPath ?? this.dotGit.path, 'HEAD'), 'utf8'); + + // Branch + const branchMatch = raw.match(/^ref: refs\/heads\/(?.*)$/m); + if (branchMatch?.groups?.name) { + return { name: branchMatch.groups.name, commit: undefined, type: RefType.Head }; + } + + // Detached + const commitMatch = raw.match(/^(?[0-9a-f]{40})$/m); + if (commitMatch?.groups?.commit) { + return { name: undefined, commit: commitMatch.groups.commit, type: RefType.Head }; + } + + throw new Error(`Unable to parse HEAD file. HEAD file contents: ${raw}.`); } async findTrackingBranches(upstreamBranch: string): Promise { diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 1914f1fb134..d25289c5f3f 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -387,7 +387,7 @@ export class Model implements IRemoteSourcePublisherRegistry, IPostCommitCommand } const dotGit = await this.git.getRepositoryDotGit(repositoryRoot); - const repository = new Repository(this.git.open(repositoryRoot, dotGit), this, this, this, this.globalState, this.outputChannelLogger, this.telemetryReporter); + const repository = new Repository(this.git.open(repositoryRoot, dotGit, this.outputChannelLogger), this, this, this, this.globalState, this.outputChannelLogger, this.telemetryReporter); this.open(repository); repository.status(); // do not await this, we want SCM to know about the repo asap From 5e2f5e57cb2d3a222d43de51541b0eda207914e8 Mon Sep 17 00:00:00 2001 From: John Murray Date: Wed, 12 Oct 2022 15:00:31 +0100 Subject: [PATCH 528/599] Link to vscode-discussions repo from New Issue click (#162643) --- .github/ISSUE_TEMPLATE/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 51e7f366043..35dab07012c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,3 +3,6 @@ contact_links: - name: Question url: https://stackoverflow.com/questions/tagged/visual-studio-code about: Please ask and answer questions here. + - name: Extension Development + url: https://github.com/microsoft/vscode-discussions/discussions/5 + about: Please use this for extension development questions and ideas. From bf220dd91e46d061cf37dbb6e0092370519ab8e1 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 12 Oct 2022 08:47:13 -0700 Subject: [PATCH 529/599] Darken red colour in light theme for better contrast (#163335) --- .../theme-defaults/themes/light_vs.json | 4 +- .../test/colorize-results/12750_html.json | 6 +- .../test/colorize-results/14119_less.json | 10 +- .../test/colorize-results/25920_html.json | 24 +- .../test/colorize-results/test-4287_pug.json | 6 +- .../test/colorize-results/test-7115_xml.json | 22 +- .../test-cssvariables_less.json | 20 +- .../test-cssvariables_scss.json | 20 +- .../colorize-results/test-embedding_html.json | 28 +- .../colorize-results/test-regex_coffee.json | 4 +- .../colorize-results/test-variables_css.json | 12 +- .../test/colorize-results/test_coffee.json | 4 +- .../test/colorize-results/test_cshtml.json | 54 +- .../test/colorize-results/test_css.json | 296 ++++---- .../colorize-results/test_handlebars.json | 38 +- .../test/colorize-results/test_hbs.json | 42 +- .../test/colorize-results/test_html.json | 60 +- .../test/colorize-results/test_jsx.json | 18 +- .../test/colorize-results/test_less.json | 212 +++--- .../test/colorize-results/test_md.json | 20 +- .../test/colorize-results/test_pug.json | 54 +- .../test/colorize-results/test_scss.json | 664 +++++++++--------- .../test/colorize-results/test_xml.json | 46 +- 23 files changed, 832 insertions(+), 832 deletions(-) diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index 0a6eaf61703..9a5092043d9 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -104,7 +104,7 @@ { "scope": "entity.other.attribute-name", "settings": { - "foreground": "#ff0000" + "foreground": "#e50000" } }, { @@ -329,7 +329,7 @@ "source.coffee.embedded" ], "settings": { - "foreground": "#ff0000" + "foreground": "#e50000" } }, { diff --git a/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json b/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json index 75021ecfe32..3989f39d021 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json @@ -40,9 +40,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -479,4 +479,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json b/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json index dae875b1f49..b7b57e957c9 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json @@ -40,9 +40,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -52,9 +52,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -251,4 +251,4 @@ "hc_light": "default: #292929" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json b/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json index d80f8d84182..ed95595fd58 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json @@ -76,9 +76,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -196,9 +196,9 @@ "t": "text.html.derivative meta.embedded.block.html text.html.basic meta.tag.structure.div.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -388,9 +388,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -652,9 +652,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -772,9 +772,9 @@ "t": "text.html.derivative meta.embedded.block.html text.html.basic meta.tag.structure.div.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -964,9 +964,9 @@ "t": "text.html.derivative meta.tag.structure.body.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json b/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json index 98c382df18b..4ec8289167e 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json @@ -4,9 +4,9 @@ "t": "text.pug entity.other.attribute-name.class.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -23,4 +23,4 @@ "hc_light": "string.comment.buffered.block.pug: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json b/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json index 95e8817adcb..e2b4189dbc2 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json @@ -28,9 +28,9 @@ "t": "text.xml meta.tag.preprocessor.xml entity.other.attribute-name.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -88,9 +88,9 @@ "t": "text.xml meta.tag.preprocessor.xml entity.other.attribute-name.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -148,9 +148,9 @@ "t": "text.xml meta.tag.preprocessor.xml entity.other.attribute-name.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -316,9 +316,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -388,9 +388,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -635,4 +635,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json index d13d4367a82..419443b11de 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json @@ -64,9 +64,9 @@ "t": "source.css.less meta.property-list.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -76,9 +76,9 @@ "t": "source.css.less meta.property-list.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -160,9 +160,9 @@ "t": "source.css.less meta.property-list.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -172,9 +172,9 @@ "t": "source.css.less meta.property-list.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -400,9 +400,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json index 6e922a532cd..ee81512b5ca 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json @@ -64,9 +64,9 @@ "t": "source.css.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -148,9 +148,9 @@ "t": "source.css.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -268,9 +268,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -376,9 +376,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -508,9 +508,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json b/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json index a48d921ebaa..b22ea1d7793 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json @@ -268,9 +268,9 @@ "t": "text.html.derivative meta.embedded.block.html source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -424,9 +424,9 @@ "t": "text.html.derivative meta.tag.inline.a.start.html meta.attribute.event-handler.blur.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -508,9 +508,9 @@ "t": "text.html.derivative meta.tag.inline.a.start.html meta.attribute.event-handler.click.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -592,9 +592,9 @@ "t": "text.html.derivative meta.tag.inline.a.start.html meta.attribute.event-handler.drag.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -724,9 +724,9 @@ "t": "text.html.derivative meta.tag.structure.div.start.html meta.attribute.style.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -868,9 +868,9 @@ "t": "text.html.derivative meta.tag.structure.div.start.html meta.attribute.style.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1012,9 +1012,9 @@ "t": "text.html.derivative meta.tag.structure.div.start.html meta.attribute.style.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json b/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json index 4140c9f0b45..e05badae2cf 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json @@ -508,9 +508,9 @@ "t": "source.coffee string.regexp.multiline.coffee source.coffee.embedded.source", "r": { "dark_plus": "source.coffee.embedded: #9CDCFE", - "light_plus": "source.coffee.embedded: #FF0000", + "light_plus": "source.coffee.embedded: #E50000", "dark_vs": "source.coffee.embedded: #9CDCFE", - "light_vs": "source.coffee.embedded: #FF0000", + "light_vs": "source.coffee.embedded: #E50000", "hc_black": "source.coffee.embedded: #D4D4D4", "hc_light": "source.coffee.embedded: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json b/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json index 4bc08534cae..f2bb411df60 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json @@ -64,9 +64,9 @@ "t": "source.css meta.property-list.css variable.css", "r": { "dark_plus": "variable.css: #9CDCFE", - "light_plus": "variable.css: #FF0000", + "light_plus": "variable.css: #E50000", "dark_vs": "variable.css: #9CDCFE", - "light_vs": "variable.css: #FF0000", + "light_vs": "variable.css: #E50000", "hc_black": "variable.css: #D4D4D4", "hc_light": "variable.css: #264F78" } @@ -148,9 +148,9 @@ "t": "source.css meta.property-list.css variable.css", "r": { "dark_plus": "variable.css: #9CDCFE", - "light_plus": "variable.css: #FF0000", + "light_plus": "variable.css: #E50000", "dark_vs": "variable.css: #9CDCFE", - "light_vs": "variable.css: #FF0000", + "light_vs": "variable.css: #E50000", "hc_black": "variable.css: #D4D4D4", "hc_light": "variable.css: #264F78" } @@ -352,9 +352,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json b/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json index 37474def82e..c173079cd2a 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json @@ -354,7 +354,7 @@ "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", "dark_vs": "source.coffee.embedded: #9CDCFE", - "light_vs": "source.coffee.embedded: #FF0000", + "light_vs": "source.coffee.embedded: #E50000", "hc_black": "variable: #9CDCFE", "hc_light": "variable: #001080" } @@ -642,7 +642,7 @@ "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", "dark_vs": "source.coffee.embedded: #9CDCFE", - "light_vs": "source.coffee.embedded: #FF0000", + "light_vs": "source.coffee.embedded: #E50000", "hc_black": "variable: #9CDCFE", "hc_light": "variable: #001080" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json index 4ab45dd0d66..16e42371716 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json @@ -1312,9 +1312,9 @@ "t": "text.html.cshtml meta.tag.metadata.doctype.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1372,9 +1372,9 @@ "t": "text.html.cshtml meta.tag.structure.html.start.html meta.attribute.lang.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1636,9 +1636,9 @@ "t": "text.html.cshtml meta.tag.metadata.meta.void.html meta.attribute.charset.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2044,9 +2044,9 @@ "t": "text.html.cshtml meta.tag.structure.form.start.html meta.attribute.action.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2104,9 +2104,9 @@ "t": "text.html.cshtml meta.tag.structure.form.start.html meta.attribute.method.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2260,9 +2260,9 @@ "t": "text.html.cshtml meta.tag.structure.label.start.html meta.attribute.for.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2428,9 +2428,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2500,9 +2500,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.name.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2716,9 +2716,9 @@ "t": "text.html.cshtml meta.tag.structure.label.start.html meta.attribute.for.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2884,9 +2884,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2956,9 +2956,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.name.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -3172,9 +3172,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -3244,9 +3244,9 @@ "t": "text.html.cshtml meta.tag.structure.input.void.html meta.attribute.value.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -3887,4 +3887,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_css.json b/extensions/vscode-colorize-tests/test/colorize-results/test_css.json index 3278b1768d1..1d023e0aba3 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_css.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_css.json @@ -700,9 +700,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -772,9 +772,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -892,9 +892,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1036,9 +1036,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1108,9 +1108,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1192,9 +1192,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1408,9 +1408,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1480,9 +1480,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1552,9 +1552,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1708,9 +1708,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2068,9 +2068,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2224,9 +2224,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2452,9 +2452,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2524,9 +2524,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2644,9 +2644,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2836,9 +2836,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2920,9 +2920,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2992,9 +2992,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3148,9 +3148,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3220,9 +3220,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3292,9 +3292,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3448,9 +3448,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3520,9 +3520,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3592,9 +3592,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3676,9 +3676,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3916,9 +3916,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3988,9 +3988,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4120,9 +4120,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4288,9 +4288,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4468,9 +4468,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4636,9 +4636,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4708,9 +4708,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4840,9 +4840,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4924,9 +4924,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5080,9 +5080,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5284,9 +5284,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5368,9 +5368,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5440,9 +5440,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5524,9 +5524,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5608,9 +5608,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5680,9 +5680,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5764,9 +5764,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5836,9 +5836,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5956,9 +5956,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6040,9 +6040,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6184,9 +6184,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6256,9 +6256,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6448,9 +6448,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6532,9 +6532,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6688,9 +6688,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6844,9 +6844,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6976,9 +6976,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7048,9 +7048,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7288,9 +7288,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7372,9 +7372,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7516,9 +7516,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7744,9 +7744,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7888,9 +7888,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7972,9 +7972,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8044,9 +8044,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8116,9 +8116,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8284,9 +8284,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8428,9 +8428,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8632,9 +8632,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8716,9 +8716,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8800,9 +8800,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9016,9 +9016,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9232,9 +9232,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9388,9 +9388,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9592,9 +9592,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9664,9 +9664,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9748,9 +9748,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9820,9 +9820,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9904,9 +9904,9 @@ "t": "source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json b/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json index e73ac0561eb..64eaa2eef81 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json @@ -40,9 +40,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -52,9 +52,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -856,9 +856,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -868,9 +868,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1048,9 +1048,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1060,9 +1060,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1612,9 +1612,9 @@ "t": "text.html.handlebars meta.tag.block.any.html meta.attribute-with-value.id.html entity.other.attribute-name.id.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1840,9 +1840,9 @@ "t": "text.html.handlebars meta.tag.inline.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1852,9 +1852,9 @@ "t": "text.html.handlebars meta.tag.inline.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2303,4 +2303,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json index 428e98c1118..99d47827659 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json @@ -124,9 +124,9 @@ "t": "text.html.handlebars meta.tag.block.any.html meta.attribute-with-value.id.html entity.other.attribute-name.id.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -352,9 +352,9 @@ "t": "text.html.handlebars meta.tag.inline.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -364,9 +364,9 @@ "t": "text.html.handlebars meta.tag.inline.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1072,9 +1072,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1084,9 +1084,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1528,9 +1528,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html entity.other.attribute-name.generic.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1540,9 +1540,9 @@ "t": "text.html.handlebars meta.tag.block.any.html entity.other.attribute-name.html punctuation.separator.key-value.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1662,7 +1662,7 @@ "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "variable: #9CDCFE", "hc_light": "variable: #001080" } @@ -1672,9 +1672,9 @@ "t": "text.html.handlebars meta.function.inline.other.handlebars entity.other.attribute-name.handlebars", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1974,7 +1974,7 @@ "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "variable: #9CDCFE", "hc_light": "variable: #001080" } @@ -1984,9 +1984,9 @@ "t": "text.html.handlebars meta.function.inline.other.handlebars entity.other.attribute-name.handlebars", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2135,4 +2135,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_html.json b/extensions/vscode-colorize-tests/test/colorize-results/test_html.json index a622ecb8611..2070e202ee8 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_html.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_html.json @@ -124,9 +124,9 @@ "t": "text.html.derivative meta.tag.metadata.meta.void.html meta.attribute.charset.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -340,9 +340,9 @@ "t": "text.html.derivative meta.tag.metadata.link.void.html meta.attribute.href.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -412,9 +412,9 @@ "t": "text.html.derivative meta.tag.metadata.link.void.html meta.attribute.rel.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -544,9 +544,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.style.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -676,9 +676,9 @@ "t": "text.html.derivative meta.embedded.block.html source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -748,9 +748,9 @@ "t": "text.html.derivative meta.embedded.block.html source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1024,9 +1024,9 @@ "t": "text.html.derivative meta.tag.structure.div.start.html meta.attribute.id.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1240,9 +1240,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.src.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1408,9 +1408,9 @@ "t": "text.html.derivative meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.src.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2512,9 +2512,9 @@ "t": "text.html.derivative meta.tag.structure.div.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2632,9 +2632,9 @@ "t": "text.html.derivative meta.tag.inline.span.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2764,9 +2764,9 @@ "t": "text.html.derivative meta.tag.inline.span.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2884,9 +2884,9 @@ "t": "text.html.derivative meta.tag.inline.a.start.html meta.attribute.href.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -3088,9 +3088,9 @@ "t": "text.html.derivative meta.tag.inline.span.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -3208,9 +3208,9 @@ "t": "text.html.derivative meta.tag.inline.a.start.html meta.attribute.href.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json b/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json index bc89c8dd8b4..1b2f32d6270 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json @@ -1948,9 +1948,9 @@ "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2008,9 +2008,9 @@ "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2380,9 +2380,9 @@ "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2452,9 +2452,9 @@ "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -2615,4 +2615,4 @@ "hc_light": "default: #292929" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_less.json b/extensions/vscode-colorize-tests/test/colorize-results/test_less.json index 6ac176bdbbd..f26403edc50 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_less.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_less.json @@ -340,9 +340,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -352,9 +352,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -436,9 +436,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -448,9 +448,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -484,9 +484,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -496,9 +496,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -592,9 +592,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -604,9 +604,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -664,9 +664,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -700,9 +700,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -712,9 +712,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -736,9 +736,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -748,9 +748,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -808,9 +808,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -820,9 +820,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -856,9 +856,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -868,9 +868,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1012,9 +1012,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1024,9 +1024,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1108,9 +1108,9 @@ "t": "source.css.less meta.property-list.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1120,9 +1120,9 @@ "t": "source.css.less meta.property-list.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1408,9 +1408,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1468,9 +1468,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1480,9 +1480,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1576,9 +1576,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1636,9 +1636,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -1648,9 +1648,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2116,9 +2116,9 @@ "t": "source.css.less meta.property-list.css meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2200,9 +2200,9 @@ "t": "source.css.less meta.property-list.css meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2344,9 +2344,9 @@ "t": "source.css.less meta.property-list.css meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2476,9 +2476,9 @@ "t": "source.css.less meta.property-list.css meta.property-list.css meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2620,9 +2620,9 @@ "t": "source.css.less meta.property-list.css meta.property-list.css meta.property-list.css meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2764,9 +2764,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2776,9 +2776,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2848,9 +2848,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2860,9 +2860,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2920,9 +2920,9 @@ "t": "source.css.less variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -2932,9 +2932,9 @@ "t": "source.css.less variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3052,9 +3052,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3100,9 +3100,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3112,9 +3112,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3208,9 +3208,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3244,9 +3244,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3256,9 +3256,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3292,9 +3292,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3340,9 +3340,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3352,9 +3352,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3508,9 +3508,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3556,9 +3556,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3568,9 +3568,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3664,9 +3664,9 @@ "t": "source.css.less meta.property-list.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3724,9 +3724,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less punctuation.definition.variable.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } @@ -3736,9 +3736,9 @@ "t": "source.css.less meta.property-list.css meta.property-value.css variable.other.less", "r": { "dark_plus": "variable.other.less: #9CDCFE", - "light_plus": "variable.other.less: #FF0000", + "light_plus": "variable.other.less: #E50000", "dark_vs": "variable.other.less: #9CDCFE", - "light_vs": "variable.other.less: #FF0000", + "light_vs": "variable.other.less: #E50000", "hc_black": "variable.other.less: #D4D4D4", "hc_light": "variable.other.less: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_md.json b/extensions/vscode-colorize-tests/test/colorize-results/test_md.json index 66549f6d2d4..78de60b2f92 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_md.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_md.json @@ -424,9 +424,9 @@ "t": "text.html.markdown meta.tag.structure.div.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -496,9 +496,9 @@ "t": "text.html.markdown meta.tag.structure.div.start.html meta.attribute.unrecognized.markdown.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -724,9 +724,9 @@ "t": "text.html.markdown meta.embedded.block.html meta.tag.metadata.script.start.html meta.attribute.type.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -916,9 +916,9 @@ "t": "text.html.markdown meta.tag.inline.b.start.html meta.attribute.class.html entity.other.attribute-name.html", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1156,9 +1156,9 @@ "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css meta.property-name.css support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json b/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json index ef09f64c9fd..e0e47e6d326 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json @@ -112,9 +112,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -436,9 +436,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -964,9 +964,9 @@ "t": "text.pug entity.other.attribute-name.class.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1132,9 +1132,9 @@ "t": "text.pug entity.other.attribute-name.class.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1180,9 +1180,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1228,9 +1228,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1276,9 +1276,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1360,9 +1360,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1408,9 +1408,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1492,9 +1492,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1540,9 +1540,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1624,9 +1624,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1672,9 +1672,9 @@ "t": "text.pug meta.tag.other entity.other.attribute-name.tag.pug", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1859,4 +1859,4 @@ "hc_light": "default: #292929" } } -] \ No newline at end of file +] diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json b/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json index 4e86712fa61..3d5c91da983 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json @@ -280,9 +280,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -436,9 +436,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -568,9 +568,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -736,9 +736,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -940,9 +940,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1060,9 +1060,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1204,9 +1204,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1540,9 +1540,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1588,9 +1588,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -1672,9 +1672,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2776,9 +2776,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -2980,9 +2980,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3100,9 +3100,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3172,9 +3172,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3340,9 +3340,9 @@ "t": "source.css.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3424,9 +3424,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -3460,9 +3460,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3496,9 +3496,9 @@ "t": "source.css.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3580,9 +3580,9 @@ "t": "source.css.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3712,9 +3712,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3760,9 +3760,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3808,9 +3808,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3856,9 +3856,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -3952,9 +3952,9 @@ "t": "source.css.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -4024,9 +4024,9 @@ "t": "source.css.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -4180,9 +4180,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -4504,9 +4504,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4720,9 +4720,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4864,9 +4864,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -4996,9 +4996,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5356,9 +5356,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5560,9 +5560,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -5620,9 +5620,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -5692,9 +5692,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -5776,9 +5776,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -5908,9 +5908,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -5980,9 +5980,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6112,9 +6112,9 @@ "t": "source.css.scss meta.at-rule.function.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6208,9 +6208,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.return.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6256,9 +6256,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.return.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6316,9 +6316,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.return.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6424,9 +6424,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.return.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -6520,9 +6520,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -6760,9 +6760,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -7024,9 +7024,9 @@ "t": "source.css.scss meta.at-rule.import.scss string.quoted.double.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -7336,9 +7336,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7516,9 +7516,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.media.scss meta.property-list.media-query.scss meta.property-name.media-query.scss support.type.property-name.media.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7612,9 +7612,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7816,9 +7816,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -7936,9 +7936,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8164,9 +8164,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8284,9 +8284,9 @@ "t": "source.css.scss entity.other.attribute-name.placeholder.css punctuation.definition.entity.css", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -8296,9 +8296,9 @@ "t": "source.css.scss entity.other.attribute-name.placeholder.css", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -8344,9 +8344,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8416,9 +8416,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8488,9 +8488,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -8668,9 +8668,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.placeholder.css punctuation.definition.entity.css", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -8680,9 +8680,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.placeholder.css", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -8884,9 +8884,9 @@ "t": "source.css.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -8908,9 +8908,9 @@ "t": "source.css.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9028,9 +9028,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9160,9 +9160,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.at-rule.warn.scss string.quoted.double.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9232,9 +9232,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9328,9 +9328,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9448,9 +9448,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9580,9 +9580,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.at-rule.warn.scss string.quoted.double.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9652,9 +9652,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9748,9 +9748,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9808,9 +9808,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9880,9 +9880,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9916,9 +9916,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -9952,9 +9952,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -9988,9 +9988,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -10324,9 +10324,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -10588,9 +10588,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -10780,9 +10780,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -10948,9 +10948,9 @@ "t": "source.css.scss meta.definition.variable.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -11080,9 +11080,9 @@ "t": "source.css.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -11152,9 +11152,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -11296,9 +11296,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -11464,9 +11464,9 @@ "t": "source.css.scss meta.at-rule.for.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -11644,9 +11644,9 @@ "t": "source.css.scss meta.property-list.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -11704,9 +11704,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -11800,9 +11800,9 @@ "t": "source.css.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -11932,9 +11932,9 @@ "t": "source.css.scss meta.at-rule.each.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12052,9 +12052,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.property-list.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12124,9 +12124,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -12220,9 +12220,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss string.quoted.single.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12364,9 +12364,9 @@ "t": "source.css.scss meta.at-rule.each.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12448,9 +12448,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12580,9 +12580,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12640,9 +12640,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -12736,9 +12736,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12796,9 +12796,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -12832,9 +12832,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13012,9 +13012,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.function.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13048,9 +13048,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.function.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13144,9 +13144,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.for.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13240,9 +13240,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.for.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13360,9 +13360,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13492,9 +13492,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13528,9 +13528,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13636,9 +13636,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -13900,9 +13900,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.return.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -14104,9 +14104,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14176,9 +14176,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14260,9 +14260,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14356,9 +14356,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14572,9 +14572,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14752,9 +14752,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -14776,9 +14776,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -14884,9 +14884,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14932,9 +14932,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -14968,9 +14968,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -15004,9 +15004,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -15040,9 +15040,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -15436,9 +15436,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -15508,9 +15508,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.vendored.property-name.css", "r": { "dark_plus": "support.type.vendored.property-name: #9CDCFE", - "light_plus": "support.type.vendored.property-name: #FF0000", + "light_plus": "support.type.vendored.property-name: #E50000", "dark_vs": "support.type.vendored.property-name: #9CDCFE", - "light_vs": "support.type.vendored.property-name: #FF0000", + "light_vs": "support.type.vendored.property-name: #E50000", "hc_black": "support.type.vendored.property-name: #D4D4D4", "hc_light": "support.type.vendored.property-name: #264F78" } @@ -15544,9 +15544,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -15580,9 +15580,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.vendored.property-name.css", "r": { "dark_plus": "support.type.vendored.property-name: #9CDCFE", - "light_plus": "support.type.vendored.property-name: #FF0000", + "light_plus": "support.type.vendored.property-name: #E50000", "dark_vs": "support.type.vendored.property-name: #9CDCFE", - "light_vs": "support.type.vendored.property-name: #FF0000", + "light_vs": "support.type.vendored.property-name: #E50000", "hc_black": "support.type.vendored.property-name: #D4D4D4", "hc_light": "support.type.vendored.property-name: #264F78" } @@ -15616,9 +15616,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -15652,9 +15652,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -15688,9 +15688,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16252,9 +16252,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16276,9 +16276,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16300,9 +16300,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16360,9 +16360,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -16396,9 +16396,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16432,9 +16432,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -16468,9 +16468,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16504,9 +16504,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -16540,9 +16540,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-value.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16576,9 +16576,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -16828,9 +16828,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.include.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -17284,9 +17284,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -17464,9 +17464,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.at-rule.if.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -17668,9 +17668,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.attribute-selector.scss entity.other.attribute-name.attribute.scss", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -18016,9 +18016,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -18100,9 +18100,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -18364,9 +18364,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -19036,9 +19036,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -19084,9 +19084,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -19144,9 +19144,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -19324,9 +19324,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.mixin.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -19468,9 +19468,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -19564,9 +19564,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20152,9 +20152,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -20224,9 +20224,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -20440,9 +20440,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20524,9 +20524,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20644,9 +20644,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20740,9 +20740,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20788,9 +20788,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -20896,9 +20896,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -21136,9 +21136,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -21280,9 +21280,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -21484,9 +21484,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -21628,9 +21628,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -21736,9 +21736,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-name.scss support.type.vendored.property-name.css", "r": { "dark_plus": "support.type.vendored.property-name: #9CDCFE", - "light_plus": "support.type.vendored.property-name: #FF0000", + "light_plus": "support.type.vendored.property-name: #E50000", "dark_vs": "support.type.vendored.property-name: #9CDCFE", - "light_vs": "support.type.vendored.property-name: #FF0000", + "light_vs": "support.type.vendored.property-name: #E50000", "hc_black": "support.type.vendored.property-name: #D4D4D4", "hc_light": "support.type.vendored.property-name: #264F78" } @@ -21832,9 +21832,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -21952,9 +21952,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -22180,9 +22180,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -22324,9 +22324,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.at-rule.keyframes.scss meta.property-list.scss meta.property-name.scss support.type.property-name.css", "r": { "dark_plus": "support.type.property-name: #9CDCFE", - "light_plus": "support.type.property-name: #FF0000", + "light_plus": "support.type.property-name: #E50000", "dark_vs": "support.type.property-name: #9CDCFE", - "light_vs": "support.type.property-name: #FF0000", + "light_vs": "support.type.property-name: #E50000", "hc_black": "support.type.property-name: #D4D4D4", "hc_light": "support.type.property-name: #264F78" } @@ -22468,9 +22468,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.attribute-selector.scss entity.other.attribute-name.attribute.scss", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -22720,9 +22720,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } @@ -22804,9 +22804,9 @@ "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", - "light_plus": "variable.scss: #FF0000", + "light_plus": "variable.scss: #E50000", "dark_vs": "variable.scss: #9CDCFE", - "light_vs": "variable.scss: #FF0000", + "light_vs": "variable.scss: #E50000", "hc_black": "variable.scss: #D4D4D4", "hc_light": "variable.scss: #264F78" } diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json index 4b149ad534e..64b2f7bc6e8 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json @@ -88,9 +88,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -208,9 +208,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -328,9 +328,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -400,9 +400,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -568,9 +568,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -640,9 +640,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -952,9 +952,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1552,9 +1552,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1624,9 +1624,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1744,9 +1744,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1816,9 +1816,9 @@ "t": "text.xml meta.tag.xml entity.other.attribute-name.localname.xml", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", - "light_plus": "entity.other.attribute-name: #FF0000", + "light_plus": "entity.other.attribute-name: #E50000", "dark_vs": "entity.other.attribute-name: #9CDCFE", - "light_vs": "entity.other.attribute-name: #FF0000", + "light_vs": "entity.other.attribute-name: #E50000", "hc_black": "entity.other.attribute-name: #9CDCFE", "hc_light": "entity.other.attribute-name: #264F78" } @@ -1967,4 +1967,4 @@ "hc_light": "punctuation.definition.tag: #0F4A85" } } -] \ No newline at end of file +] From f26411046b004534e737d78fde52617969bf90db Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 09:02:22 -0700 Subject: [PATCH 530/599] Don't create extra disposable stores when rendering settings tree elements (#163407) Re-use disposable stores when rendering settings tree --- .../preferences/browser/settingsTree.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 834aab26324..d6f5f844270 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -582,7 +582,7 @@ function getFlatSettings(settingsGroups: ISettingsGroup[]) { } interface IDisposableTemplate { - toDispose: DisposableStore; + readonly toDispose: DisposableStore; } interface ISettingItemTemplate extends IDisposableTemplate { @@ -598,7 +598,7 @@ interface ISettingItemTemplate extends IDisposableTemplate { deprecationWarningElement: HTMLElement; indicatorsLabel: SettingsTreeIndicatorsLabel; toolbar: ToolBar; - elementDisposables: DisposableStore; + readonly elementDisposables: DisposableStore; } interface ISettingBoolItemTemplate extends ISettingItemTemplate { @@ -808,7 +808,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre const template: ISettingItemTemplate = { toDispose, - elementDisposables: new DisposableStore(), + elementDisposables: toDispose.add(new DisposableStore()), containerElement: container, categoryElement, @@ -895,7 +895,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre template.context = element; template.toolbar.context = element; const actions = this.disposableActionFactory(element.setting); - actions.forEach(a => isDisposable(a) && template.elementDisposables?.add(a)); + actions.forEach(a => isDisposable(a) && template.elementDisposables.add(a)); template.toolbar.setActions([], [...this.settingActions, ...actions]); const setting = element.setting; @@ -913,9 +913,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre template.descriptionElement.innerText = ''; if (element.setting.descriptionIsMarkdown) { - const disposables = new DisposableStore(); - template.elementDisposables.add(disposables); - const renderedDescription = this.renderSettingMarkdown(element, template.containerElement, element.description, disposables); + const renderedDescription = this.renderSettingMarkdown(element, template.containerElement, element.description, template.elementDisposables); template.descriptionElement.appendChild(renderedDescription); } else { template.descriptionElement.innerText = element.description; @@ -932,8 +930,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre }); const deprecationText = element.setting.deprecationMessage || ''; if (deprecationText && element.setting.deprecationMessageIsMarkdown) { - const disposables = new DisposableStore(); - template.elementDisposables.add(disposables); template.deprecationWarningElement.innerText = ''; template.deprecationWarningElement.appendChild(this.renderSettingMarkdown(element, template.containerElement, element.setting.deprecationMessage!, template.elementDisposables)); } else { @@ -966,7 +962,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre } } - private renderSettingMarkdown(element: SettingsTreeSettingElement, container: HTMLElement, text: string, disposeables: DisposableStore): HTMLElement { + private renderSettingMarkdown(element: SettingsTreeSettingElement, container: HTMLElement, text: string, disposables: DisposableStore): HTMLElement { // Rewrite `#editor.fontSize#` to link format text = fixSettingLinks(text); @@ -983,7 +979,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre this._openerService.open(content, { allowCommands: true }).catch(onUnexpectedError); } }, - disposables: disposeables + disposables }, asyncRenderCallback: () => { const height = container.clientHeight; @@ -992,7 +988,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre } }, }); - disposeables.add(renderedMarkdown); + disposables.add(renderedMarkdown); renderedMarkdown.element.classList.add('setting-item-markdown'); cleanRenderedMarkdown(renderedMarkdown.element); @@ -1002,7 +998,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre protected abstract renderValue(dataElement: SettingsTreeSettingElement, template: ISettingItemTemplate, onChange: (value: any) => void): void; disposeTemplate(template: IDisposableTemplate): void { - dispose(template.toDispose); + template.toDispose.dispose(); } disposeElement(_element: ITreeNode, _index: number, template: IDisposableTemplate, _height: number | undefined): void { @@ -1864,7 +1860,7 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre const template: ISettingBoolItemTemplate = { toDispose, - elementDisposables: new DisposableStore(), + elementDisposables: toDispose.add(new DisposableStore()), containerElement: container, categoryElement, From 61532aeb5643822cf46cb8ccf0301024ad4af483 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 09:02:57 -0700 Subject: [PATCH 531/599] Re-use DisposableStores when rendering explorer items (#163380) While trying to debug an performance issue with scrolling the explorer, I noticed that the explorer list renderer creates a new `DisposableStore` every time it renders an item For performance, it's better to create a DisposableStore for each template and then re-use this when rendering elements. This store is cleared in the `disposeElement` function --- .../files/browser/views/explorerViewer.ts | 46 ++++++++----------- .../files/test/browser/explorerView.test.ts | 4 +- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index b48b6da99f5..1d7d4cf70bd 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -255,9 +255,9 @@ export class CompressedNavigationController implements ICompressedNavigationCont } export interface IFileTemplateData { - elementDisposable: IDisposable; - label: IResourceLabel; - container: HTMLElement; + readonly elementDisposables: DisposableStore; + readonly label: IResourceLabel; + readonly container: HTMLElement; } export class FilesRenderer implements ICompressibleTreeRenderer, IListAccessibilityProvider, IDisposable { @@ -312,14 +312,12 @@ export class FilesRenderer implements ICompressibleTreeRenderer, index: number, templateData: IFileTemplateData): void { - templateData.elementDisposable.dispose(); const stat = node.element; const editableData = this.explorerService.getEditableData(stat); @@ -328,19 +326,17 @@ export class FilesRenderer implements ICompressibleTreeRenderer, FuzzyScore>, index: number, templateData: IFileTemplateData, height: number | undefined): void { - templateData.elementDisposable.dispose(); - const stat = node.element.elements[node.element.elements.length - 1]; const editable = node.element.elements.filter(e => this.explorerService.isEditable(e)); const editableData = editable.length === 0 ? undefined : this.explorerService.getEditableData(editable[0]); @@ -350,20 +346,19 @@ export class FilesRenderer implements ICompressibleTreeRenderer e.name); - disposables.add(this.renderStat(stat, label, id, node.filterData, templateData)); + this.renderStat(stat, label, id, node.filterData, templateData); const compressedNavigationController = new CompressedNavigationController(id, node.element.elements, templateData, node.depth, node.collapsed); - disposables.add(compressedNavigationController); + templateData.elementDisposables.add(compressedNavigationController); this.compressedNavigationControllers.set(stat, compressedNavigationController); // accessibility - disposables.add(this._onDidChangeActiveDescendant.add(compressedNavigationController.onDidChange)); + templateData.elementDisposables.add(this._onDidChangeActiveDescendant.add(compressedNavigationController.onDidChange)); - disposables.add(DOM.addDisposableListener(templateData.container, 'mousedown', e => { + templateData.elementDisposables.add(DOM.addDisposableListener(templateData.container, 'mousedown', e => { const result = getIconLabelNameFromHTMLElement(e.target); if (result) { @@ -371,21 +366,18 @@ export class FilesRenderer implements ICompressibleTreeRenderer this.compressedNavigationControllers.delete(stat))); - - templateData.elementDisposable = disposables; + templateData.elementDisposables.add(toDisposable(() => this.compressedNavigationControllers.delete(stat))); } // Input Box else { templateData.label.element.classList.remove('compressed'); templateData.label.element.style.display = 'none'; - templateData.elementDisposable = this.renderInputBox(templateData.container, editable[0], editableData); + templateData.elementDisposables.add(this.renderInputBox(templateData.container, editable[0], editableData)); } } - private renderStat(stat: ExplorerItem, label: string | string[], domId: string | undefined, filterData: FuzzyScore | undefined, templateData: IFileTemplateData): IDisposable { - const elementDisposables = new DisposableStore(); + private renderStat(stat: ExplorerItem, label: string | string[], domId: string | undefined, filterData: FuzzyScore | undefined, templateData: IFileTemplateData): void { templateData.label.element.style.display = 'flex'; const extraClasses = ['explorer-item']; if (this.explorerService.isCut(stat)) { @@ -421,18 +413,16 @@ export class FilesRenderer implements ICompressibleTreeRenderer setResourceData())); + templateData.elementDisposables.add(this.themeService.onDidFileIconThemeChange(() => setResourceData())); setResourceData(); - elementDisposables.add(templateData.label.onDidRender(() => { + templateData.elementDisposables.add(templateData.label.onDidRender(() => { try { this.updateWidth(stat); } catch (e) { // noop since the element might no longer be in the tree, no update of width necessary } })); - - return elementDisposables; } private renderInputBox(container: HTMLElement, stat: ExplorerItem, editableData: IEditableData): IDisposable { @@ -560,15 +550,15 @@ export class FilesRenderer implements ICompressibleTreeRenderer, index: number, templateData: IFileTemplateData): void { - templateData.elementDisposable.dispose(); + templateData.elementDisposables.clear(); } disposeCompressedElements(node: ITreeNode, FuzzyScore>, index: number, templateData: IFileTemplateData): void { - templateData.elementDisposable.dispose(); + templateData.elementDisposables.clear(); } disposeTemplate(templateData: IFileTemplateData): void { - templateData.elementDisposable.dispose(); + templateData.elementDisposables.dispose(); templateData.label.dispose(); } diff --git a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts index 35d1fb3ab9f..f02bc07ea5c 100644 --- a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts @@ -12,7 +12,7 @@ import { getContext } from 'vs/workbench/contrib/files/browser/views/explorerVie import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry'; import { CompressedNavigationController } from 'vs/workbench/contrib/files/browser/views/explorerViewer'; import * as dom from 'vs/base/browser/dom'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { provideDecorations } from 'vs/workbench/contrib/files/browser/views/explorerDecorationsProvider'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; const $ = dom.$; @@ -84,7 +84,7 @@ suite('Files - ExplorerView', () => { const navigationController = new CompressedNavigationController('id', [s1, s2, s3], { container, - elementDisposable: Disposable.None, + elementDisposables: new DisposableStore(), label: { container: label, onDidRender: emitter.event From 749f48091511250b543f244f49aedea57a6285f6 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 12 Oct 2022 09:37:24 -0700 Subject: [PATCH 532/599] Fix "Add Configuration" launch.json button on Windows (#163444) Fix #163266 --- src/vs/workbench/contrib/debug/browser/debugCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 80308ec506a..b33e1b7a7a4 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -927,7 +927,7 @@ registerAction2(class AddConfigurationAction extends Action2 { menu: { id: MenuId.EditorContent, when: ContextKeyExpr.and( - ContextKeyExpr.regex(ResourceContextKey.Path.key, /\.vscode\/launch\.json$/), + ContextKeyExpr.regex(ResourceContextKey.Path.key, /\.vscode[/\\]launch\.json$/), ActiveEditorContext.isEqualTo(TEXT_FILE_EDITOR_ID)) } }); From c56e49670ed87ab5fcfb5895f84a8564b865f645 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 10:19:43 -0700 Subject: [PATCH 533/599] Reduce event listeners created when rendering explorer items (#163394) Reduce event listeners created when rendering explorer Every time an explorer item is rendered, we currently hook up a `themeService.onDidFileIconThemeChange` listener for it. This ends up creating a lot of extra event listeners even though this even it pretty rarely fired Instead, this PR switches us to have a single listener the re-renders the entire tree. Since this should not be a common event, I believe this is reasonable. Profiling also shows that this cuts both the rendering time and amount of garbage generated --- .../files/browser/views/explorerView.ts | 1 + .../files/browser/views/explorerViewer.ts | 45 +++++++------------ 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index a36bc07ee12..eb3cb2b6df9 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -452,6 +452,7 @@ export class ExplorerView extends ViewPane implements IExplorerView { } }); this._register(this.tree); + this._register(this.themeService.onDidColorThemeChange(() => this.tree.rerender())); // Bind configuration const onDidChangeCompressionConfiguration = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('explorer.compactFolders')); diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 1d7d4cf70bd..b652e4e4948 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -384,37 +384,26 @@ export class FilesRenderer implements ICompressibleTreeRenderer { - // Offset nested children unless folders have both chevrons and icons, otherwise alignment breaks - const theme = this.themeService.getFileIconTheme(); + // Offset nested children unless folders have both chevrons and icons, otherwise alignment breaks + const theme = this.themeService.getFileIconTheme(); - // Hack to always render chevrons for file nests, or else may not be able to identify them. - const twistieContainer = (templateData.container.parentElement?.parentElement?.querySelector('.monaco-tl-twistie') as HTMLElement); - if (twistieContainer) { - if (stat.hasNests && theme.hidesExplorerArrows) { - twistieContainer.classList.add('force-twistie'); - } else { - twistieContainer.classList.remove('force-twistie'); - } - } + // Hack to always render chevrons for file nests, or else may not be able to identify them. + const twistieContainer = templateData.container.parentElement?.parentElement?.querySelector('.monaco-tl-twistie'); + twistieContainer?.classList.toggle('force-twistie', stat.hasNests && theme.hidesExplorerArrows); - // when explorer arrows are hidden or there are no folder icons, nests get misaligned as they are forced to have arrows and files typically have icons - // Apply some CSS magic to get things looking as reasonable as possible. - const themeIsUnhappyWithNesting = theme.hasFileIcons && (theme.hidesExplorerArrows || !theme.hasFolderIcons); - const realignNestedChildren = stat.nestedParent && themeIsUnhappyWithNesting; + // when explorer arrows are hidden or there are no folder icons, nests get misaligned as they are forced to have arrows and files typically have icons + // Apply some CSS magic to get things looking as reasonable as possible. + const themeIsUnhappyWithNesting = theme.hasFileIcons && (theme.hidesExplorerArrows || !theme.hasFolderIcons); + const realignNestedChildren = stat.nestedParent && themeIsUnhappyWithNesting; - templateData.label.setResource({ resource: stat.resource, name: label }, { - fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, - extraClasses: realignNestedChildren ? [...extraClasses, 'align-nest-icon-with-parent-icon'] : extraClasses, - fileDecorations: this.config.explorer.decorations, - matches: createMatches(filterData), - separator: this.labelService.getSeparator(stat.resource.scheme, stat.resource.authority), - domId - }); - }; - - templateData.elementDisposables.add(this.themeService.onDidFileIconThemeChange(() => setResourceData())); - setResourceData(); + templateData.label.setResource({ resource: stat.resource, name: label }, { + fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, + extraClasses: realignNestedChildren ? [...extraClasses, 'align-nest-icon-with-parent-icon'] : extraClasses, + fileDecorations: this.config.explorer.decorations, + matches: createMatches(filterData), + separator: this.labelService.getSeparator(stat.resource.scheme, stat.resource.authority), + domId + }); templateData.elementDisposables.add(templateData.label.onDidRender(() => { try { From b2d129c4e559cc12a64340f8b36c9a93ddbffefe Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 11:04:56 -0700 Subject: [PATCH 534/599] Fix ipv6 support for simple browser (#163374) Fixes #158599 This correctly handles ipv6 uris, such as `http://[::]:3000`. In these cases, the brackets are required --- extensions/simple-browser/src/extension.ts | 17 +++++++---------- .../simple-browser/src/simpleBrowserManager.ts | 3 ++- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/extensions/simple-browser/src/extension.ts b/extensions/simple-browser/src/extension.ts index 63131a43bcf..6d3ded5131b 100644 --- a/extensions/simple-browser/src/extension.ts +++ b/extensions/simple-browser/src/extension.ts @@ -23,18 +23,15 @@ const enabledHosts = new Set([ // localhost IPv4 '127.0.0.1', // localhost IPv6 - '0:0:0:0:0:0:0:1', - '::1', + '[0:0:0:0:0:0:0:1]', + '[::1]', // all interfaces IPv4 '0.0.0.0', // all interfaces IPv6 - '0:0:0:0:0:0:0:0', - '::' + '[0:0:0:0:0:0:0:0]', + '[::]' ]); -const IPv6Localhost = /0\:0\:0\:0\:0\:0\:0\:1|\:\:1/; -const IPv6AllInterfaces = /0\:0\:0\:0\:0\:0\:0\:0|\:\:/; - const openerId = 'simpleBrowser.open'; export function activate(context: vscode.ExtensionContext) { @@ -65,13 +62,13 @@ export function activate(context: vscode.ExtensionContext) { preserveFocus?: boolean; viewColumn: vscode.ViewColumn; }) => { - manager.show(url.toString(), showOptions); + manager.show(url, showOptions); })); context.subscriptions.push(vscode.window.registerExternalUriOpener(openerId, { canOpenExternalUri(uri: vscode.Uri) { // We have to replace the IPv6 hosts with IPv4 because URL can't handle IPv6. - const originalUri = new URL(uri.toString().replace(IPv6Localhost, '127.0.0.1').replace(IPv6AllInterfaces, '0.0.0.0')); + const originalUri = new URL(uri.toString(true)); if (enabledHosts.has(originalUri.hostname)) { return isWeb() ? vscode.ExternalUriOpenerPriority.Default @@ -81,7 +78,7 @@ export function activate(context: vscode.ExtensionContext) { return vscode.ExternalUriOpenerPriority.None; }, openExternalUri(resolveUri: vscode.Uri) { - return manager.show(resolveUri.toString(), { + return manager.show(resolveUri, { viewColumn: vscode.window.activeTextEditor ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active }); } diff --git a/extensions/simple-browser/src/simpleBrowserManager.ts b/extensions/simple-browser/src/simpleBrowserManager.ts index 25a4e9175f5..5cbcc86b342 100644 --- a/extensions/simple-browser/src/simpleBrowserManager.ts +++ b/extensions/simple-browser/src/simpleBrowserManager.ts @@ -19,7 +19,8 @@ export class SimpleBrowserManager { this._activeView = undefined; } - public show(url: string, options?: ShowOptions): void { + public show(inputUri: string | vscode.Uri, options?: ShowOptions): void { + const url = typeof inputUri === 'string' ? inputUri : inputUri.toString(true); if (this._activeView) { this._activeView.show(url, options); } else { From a2aeb3110a7e5cf2667e312dd5bfca01bb029769 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 11:06:27 -0700 Subject: [PATCH 535/599] Use `toggle` instead of dynamic call to class list add/remove (#163464) --- src/vs/base/parts/quickinput/browser/quickInput.ts | 2 +- .../contrib/welcomeGettingStarted/browser/gettingStarted.ts | 6 +++--- .../contrib/welcomeWalkthrough/browser/walkThroughPart.ts | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index dcf07adcf63..8d2d051b9f4 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -1674,7 +1674,7 @@ export class QuickInputController extends Disposable { ui.message.style.display = visibilities.message ? '' : 'none'; ui.progressBar.getContainer().style.display = visibilities.progressBar ? '' : 'none'; ui.list.display(!!visibilities.list); - ui.container.classList[visibilities.checkBox ? 'add' : 'remove']('show-checkboxes'); + ui.container.classList.toggle('show-checkboxes', visibilities.checkBox); this.updateLayout(); // TODO } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 95646185780..37fce5dcf39 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -1054,9 +1054,9 @@ export class GettingStartedPage extends EditorPane { this.layoutMarkdown?.(); - this.container.classList[size.height <= 600 ? 'add' : 'remove']('height-constrained'); - this.container.classList[size.width <= 400 ? 'add' : 'remove']('width-constrained'); - this.container.classList[size.width <= 800 ? 'add' : 'remove']('width-semi-constrained'); + this.container.classList.toggle('height-constrained', size.height <= 600); + this.container.classList.toggle('width-constrained', size.width <= 400); + this.container.classList.toggle('width-semi-constrained', size.width <= 800); } private updateCategoryProgress() { diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts index 01504f62f36..3e736453267 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts @@ -220,8 +220,7 @@ export class WalkThroughPart extends EditorPane { private updateSizeClasses() { const innerContent = this.content.firstElementChild; if (this.size && innerContent) { - const classList = innerContent.classList; - classList[this.size.height <= 685 ? 'add' : 'remove']('max-height-685px'); + innerContent.classList.toggle('max-height-685px', this.size.height <= 685); } } From 3c9854fe860a3e679aab5312674e8a8f4229017c Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 12 Oct 2022 22:35:13 +0200 Subject: [PATCH 536/599] Fixes #95328: Clamp the hover result range to make sure the hover stays on the same view line --- .../contrib/hover/browser/contentHover.ts | 21 ++++++-- .../hover/test/browser/contentHover.test.ts | 49 ++++++++++++++----- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 30de80e0952..e0f2246f5a6 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -24,6 +24,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest'; import { AsyncIterableObject } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { Constants } from 'vs/base/common/uint'; const $ = dom.$; @@ -240,7 +241,7 @@ export class ContentHoverController extends Disposable { } private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void { - const { showAtPosition, showAtRange, highlightRange } = ContentHoverController.computeHoverRanges(anchor.range, messages); + const { showAtPosition, showAtRange, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages); const disposables = new DisposableStore(); const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService)); @@ -301,7 +302,19 @@ export class ContentHoverController extends Disposable { className: 'hoverHighlight' }); - public static computeHoverRanges(anchorRange: Range, messages: IHoverPart[]) { + public static computeHoverRanges(editor: ICodeEditor, anchorRange: Range, messages: IHoverPart[]) { + let startColumnBoundary = 1; + let endColumnBoundary = Constants.MAX_SAFE_SMALL_INTEGER; + if (editor.hasModel()) { + // Ensure the range is on the current view line + const viewModel = editor._getViewModel(); + const coordinatesConverter = viewModel.coordinatesConverter; + const anchorViewRange = coordinatesConverter.convertModelRangeToViewRange(anchorRange); + const anchorViewRangeStart = new Position(anchorViewRange.startLineNumber, viewModel.getLineMinColumn(anchorViewRange.startLineNumber)); + const anchorViewRangeEnd = new Position(anchorViewRange.endLineNumber, viewModel.getLineMaxColumn(anchorViewRange.endLineNumber)); + startColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeStart).column; + endColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeEnd).column; + } // The anchor range is always on a single line const anchorLineNumber = anchorRange.startLineNumber; let renderStartColumn = anchorRange.startColumn; @@ -313,8 +326,8 @@ export class ContentHoverController extends Disposable { highlightRange = Range.plusRange(highlightRange, msg.range); if (msg.range.startLineNumber === anchorLineNumber && msg.range.endLineNumber === anchorLineNumber) { // this message has a range that is completely sitting on the line of the anchor - renderStartColumn = Math.min(renderStartColumn, msg.range.startColumn); - renderEndColumn = Math.max(renderEndColumn, msg.range.endColumn); + renderStartColumn = Math.max(Math.min(renderStartColumn, msg.range.startColumn), startColumnBoundary); + renderEndColumn = Math.min(Math.max(renderEndColumn, msg.range.endColumn), endColumnBoundary); } if (msg.forceShowAtRange) { forceShowAtRange = msg.range; diff --git a/src/vs/editor/contrib/hover/test/browser/contentHover.test.ts b/src/vs/editor/contrib/hover/test/browser/contentHover.test.ts index 7e35cea943b..1dacdd5a203 100644 --- a/src/vs/editor/contrib/hover/test/browser/contentHover.test.ts +++ b/src/vs/editor/contrib/hover/test/browser/contentHover.test.ts @@ -8,20 +8,45 @@ import { ContentHoverController } from 'vs/editor/contrib/hover/browser/contentH import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes'; +import { TestCodeEditorInstantiationOptions, withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; suite('Content Hover', () => { test('issue #151235: Gitlens hover shows up in the wrong place', () => { - const actual = ContentHoverController.computeHoverRanges( - new Range(5, 5, 5, 5), - [{ range: new Range(4, 1, 5, 6) }] - ); - assert.deepStrictEqual( - actual, - { - showAtPosition: new Position(5, 5), - showAtRange: new Range(5, 5, 5, 5), - highlightRange: new Range(4, 1, 5, 6) - } - ); + const text = 'just some text'; + withTestCodeEditor(text, {}, (editor) => { + const actual = ContentHoverController.computeHoverRanges( + editor, + new Range(5, 5, 5, 5), + [{ range: new Range(4, 1, 5, 6) }] + ); + assert.deepStrictEqual( + actual, + { + showAtPosition: new Position(5, 5), + showAtRange: new Range(5, 5, 5, 5), + highlightRange: new Range(4, 1, 5, 6) + } + ); + }); + }); + + test('issue #95328: Hover placement with word-wrap', () => { + const text = 'just some text'; + const opts: TestCodeEditorInstantiationOptions = { wordWrap: 'wordWrapColumn', wordWrapColumn: 6 }; + withTestCodeEditor(text, opts, (editor) => { + const actual = ContentHoverController.computeHoverRanges( + editor, + new Range(1, 8, 1, 8), + [{ range: new Range(1, 1, 1, 15) }] + ); + assert.deepStrictEqual( + actual, + { + showAtPosition: new Position(1, 6), + showAtRange: new Range(1, 6, 1, 11), + highlightRange: new Range(1, 1, 1, 15) + } + ); + }); }); }); From c1ac9ecbb5f22024433a63d5a5a12da5da14c47a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 12 Oct 2022 13:37:23 -0700 Subject: [PATCH 537/599] Initialize context keys a bit later to avoid triggering recursive instantiation (#163445) Fix #163314 --- .../contrib/debug/browser/debugService.ts | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index aa117289421..99327f8edd6 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -121,22 +121,10 @@ export class DebugService implements IDebugService { this.disposables.add(this.configurationManager); this.debugStorage = this.instantiationService.createInstance(DebugStorage); - contextKeyService.bufferChangeEvents(() => { - this.debugType = CONTEXT_DEBUG_TYPE.bindTo(contextKeyService); - this.debugState = CONTEXT_DEBUG_STATE.bindTo(contextKeyService); - this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService); - this.debugUx = CONTEXT_DEBUG_UX.bindTo(contextKeyService); - this.debugUx.set(this.debugStorage.loadDebugUxState()); - this.breakpointsExist = CONTEXT_BREAKPOINTS_EXIST.bindTo(contextKeyService); - // Need to set disassemblyViewFocus here to make it in the same context as the debug event handlers - this.disassemblyViewFocus = CONTEXT_DISASSEMBLY_VIEW_FOCUS.bindTo(contextKeyService); - }); this.chosenEnvironments = this.debugStorage.loadChosenEnvironments(); this.model = this.instantiationService.createInstance(DebugModel, this.debugStorage); this.telemetry = this.instantiationService.createInstance(DebugTelemetry, this.model); - const setBreakpointsExistContext = () => this.breakpointsExist.set(!!(this.model.getBreakpoints().length || this.model.getDataBreakpoints().length || this.model.getFunctionBreakpoints().length)); - setBreakpointsExistContext(); this.viewModel = new ViewModel(contextKeyService); this.taskRunner = this.instantiationService.createInstance(DebugTaskRunner); @@ -182,7 +170,6 @@ export class DebugService implements IDebugService { } } })); - this.disposables.add(this.model.onDidChangeBreakpoints(() => setBreakpointsExistContext())); this.disposables.add(editorService.onDidActiveEditorChange(() => { this.contextKeyService.bufferChangeEvents(() => { @@ -202,6 +189,27 @@ export class DebugService implements IDebugService { } } })); + + this.initContextKeys(contextKeyService); + } + + private initContextKeys(contextKeyService: IContextKeyService): void { + queueMicrotask(() => { + contextKeyService.bufferChangeEvents(() => { + this.debugType = CONTEXT_DEBUG_TYPE.bindTo(contextKeyService); + this.debugState = CONTEXT_DEBUG_STATE.bindTo(contextKeyService); + this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService); + this.debugUx = CONTEXT_DEBUG_UX.bindTo(contextKeyService); + this.debugUx.set(this.debugStorage.loadDebugUxState()); + this.breakpointsExist = CONTEXT_BREAKPOINTS_EXIST.bindTo(contextKeyService); + // Need to set disassemblyViewFocus here to make it in the same context as the debug event handlers + this.disassemblyViewFocus = CONTEXT_DISASSEMBLY_VIEW_FOCUS.bindTo(contextKeyService); + }); + + const setBreakpointsExistContext = () => this.breakpointsExist.set(!!(this.model.getBreakpoints().length || this.model.getDataBreakpoints().length || this.model.getFunctionBreakpoints().length)); + setBreakpointsExistContext(); + this.disposables.add(this.model.onDidChangeBreakpoints(() => setBreakpointsExistContext())); + }); } getModel(): IDebugModel { From 2c332cefa2ba7a55e48235b60753bfb5c1283232 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 12 Oct 2022 23:05:11 +0200 Subject: [PATCH 538/599] commit characters must check suggest model state before proceeding (#163467) fixes https://github.com/microsoft/vscode/issues/163431 --- .../suggest/browser/suggestCommitCharacters.ts | 14 ++++++++++++-- .../contrib/suggest/browser/suggestController.ts | 13 +++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts index 1b89a6435a8..61080e43376 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts @@ -8,6 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; +import { State, SuggestModel } from 'vs/editor/contrib/suggest/browser/suggestModel'; import { ISelectedSuggestion, SuggestWidget } from './suggestWidget'; export class CommitCharacterController { @@ -19,14 +20,23 @@ export class CommitCharacterController { readonly item: ISelectedSuggestion; }; - constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) { + constructor(editor: ICodeEditor, widget: SuggestWidget, model: SuggestModel, accept: (selected: ISelectedSuggestion) => any) { + + this._disposables.add(model.onDidSuggest(e => { + if (e.completionModel.items.length === 0) { + this.reset(); + } + })); + this._disposables.add(model.onDidCancel(e => { + this.reset(); + })); this._disposables.add(widget.onDidShow(() => this._onItem(widget.getFocusedItem()))); this._disposables.add(widget.onDidFocus(this._onItem, this)); this._disposables.add(widget.onDidHide(this.reset, this)); this._disposables.add(editor.onWillType(text => { - if (this._active && !widget.isFrozen()) { + if (this._active && !widget.isFrozen() && model.state !== State.Idle) { const ch = text.charCodeAt(text.length - 1); if (this._active.acceptCharacters.has(ch) && editor.getOption(EditorOption.acceptSuggestionOnCommitCharacter)) { accept(this._active.item); diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 14045fe6bec..21a4e1ff60d 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -47,8 +47,9 @@ import { basename, extname } from 'vs/base/common/resources'; import { hash } from 'vs/base/common/hash'; // sticky suggest widget which doesn't disappear on focus out and such -const _sticky = false; -// _sticky = Boolean("true"); // done "weirdly" so that a lint warning prevents you from pushing this +const _sticky = false + // || Boolean("true") // done "weirdly" so that a lint warning prevents you from pushing this + ; class LineSuffix { @@ -142,13 +143,9 @@ export class SuggestController implements IEditorContribution { this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, 0), this)); // Wire up logic to accept a suggestion on certain characters - const commitCharacterController = new CommitCharacterController(this.editor, widget, item => this._insertSuggestion(item, InsertFlags.NoAfterUndoStop)); + const commitCharacterController = new CommitCharacterController(this.editor, widget, this.model, item => this._insertSuggestion(item, InsertFlags.NoAfterUndoStop)); this._toDispose.add(commitCharacterController); - this._toDispose.add(this.model.onDidSuggest(e => { - if (e.completionModel.items.length === 0) { - commitCharacterController.reset(); - } - })); + // Wire up makes text edit context key const ctxMakesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService); From d055619b399e8bc4056d1b6d9c9e3dbad6384ebb Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 14:05:39 -0700 Subject: [PATCH 539/599] Re-use label listener when rendering explorer elements (#163474) This moves the label render listener to the template instead of being created for each element. To do this, we also need to store some context info on the current template data This further improves performance as it avoids registering an extra event and adding to the disposable store for each rendered explorer item --- .../files/browser/views/explorerViewer.ts | 36 ++++++++++++------- .../files/test/browser/explorerView.test.ts | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index b652e4e4948..e1ded9a550c 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -255,9 +255,12 @@ export class CompressedNavigationController implements ICompressedNavigationCont } export interface IFileTemplateData { + readonly templateDisposables: DisposableStore; readonly elementDisposables: DisposableStore; readonly label: IResourceLabel; readonly container: HTMLElement; + + currentContext?: ExplorerItem; } export class FilesRenderer implements ICompressibleTreeRenderer, IListAccessibilityProvider, IDisposable { @@ -312,13 +315,27 @@ export class FilesRenderer implements ICompressibleTreeRenderer { + try { + if (templateData.currentContext) { + this.updateWidth(templateData.currentContext); + } + } catch (e) { + // noop since the element might no longer be in the tree, no update of width necessary + } + })); + + const templateData: IFileTemplateData = { templateDisposables, elementDisposables: templateDisposables.add(new DisposableStore()), label, container }; + return templateData; } renderElement(node: ITreeNode, index: number, templateData: IFileTemplateData): void { const stat = node.element; + templateData.currentContext = stat; + const editableData = this.explorerService.getEditableData(stat); templateData.label.element.classList.remove('compressed'); @@ -338,6 +355,8 @@ export class FilesRenderer implements ICompressibleTreeRenderer, FuzzyScore>, index: number, templateData: IFileTemplateData, height: number | undefined): void { const stat = node.element.elements[node.element.elements.length - 1]; + templateData.currentContext = stat; + const editable = node.element.elements.filter(e => this.explorerService.isEditable(e)); const editableData = editable.length === 0 ? undefined : this.explorerService.getEditableData(editable[0]); @@ -404,14 +423,6 @@ export class FilesRenderer implements ICompressibleTreeRenderer { - try { - this.updateWidth(stat); - } catch (e) { - // noop since the element might no longer be in the tree, no update of width necessary - } - })); } private renderInputBox(container: HTMLElement, stat: ExplorerItem, editableData: IEditableData): IDisposable { @@ -539,16 +550,17 @@ export class FilesRenderer implements ICompressibleTreeRenderer, index: number, templateData: IFileTemplateData): void { + templateData.currentContext = undefined; templateData.elementDisposables.clear(); } disposeCompressedElements(node: ITreeNode, FuzzyScore>, index: number, templateData: IFileTemplateData): void { + templateData.currentContext = undefined; templateData.elementDisposables.clear(); } disposeTemplate(templateData: IFileTemplateData): void { - templateData.elementDisposables.dispose(); - templateData.label.dispose(); + templateData.templateDisposables.dispose(); } getCompressedNavigationController(stat: ExplorerItem): ICompressedNavigationController | undefined { diff --git a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts index f02bc07ea5c..77b772a742a 100644 --- a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts @@ -84,6 +84,7 @@ suite('Files - ExplorerView', () => { const navigationController = new CompressedNavigationController('id', [s1, s2, s3], { container, + templateDisposables: new DisposableStore(), elementDisposables: new DisposableStore(), label: { container: label, From 22ff985c19a0e36505ee86f5bf1e4c7f9c641bd7 Mon Sep 17 00:00:00 2001 From: Suven-p Date: Thu, 13 Oct 2022 02:51:19 +0545 Subject: [PATCH 540/599] Add multiple template parameters (#163191) --- .../src/utils/previewer.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/utils/previewer.ts b/extensions/typescript-language-features/src/utils/previewer.ts index a4a42086d17..1564cdd92dd 100644 --- a/extensions/typescript-language-features/src/utils/previewer.ts +++ b/extensions/typescript-language-features/src/utils/previewer.ts @@ -84,7 +84,7 @@ function getTagDocumentation( case 'extends': case 'param': case 'template': { - const body = (convertLinkTags(tag.text, filePathConverter)).split(/^(\S+)\s*-?\s*/); + const body = getTagBody(tag, filePathConverter); if (body?.length === 3) { const param = body[1]; const doc = body[2]; @@ -106,6 +106,18 @@ function getTagDocumentation( return label + (text.match(/\r\n|\n/g) ? ' \n' + text : ` \u2014 ${text}`); } +function getTagBody(tag: Proto.JSDocTagInfo, filePathConverter: IFilePathToResourceConverter): Array | undefined { + if (tag.name === 'template') { + const parts = tag.text; + if (parts && typeof (parts) !== 'string') { + const params = parts.filter(p => p.kind === 'typeParameterName').map(p => p.text).join(', '); + const docs = parts.filter(p => p.kind === 'text').map(p => convertLinkTags(p.text.replace(/^\s*-?\s*/, ''), filePathConverter)).join(' '); + return params ? ['', params, docs] : undefined; + } + } + return (convertLinkTags(tag.text, filePathConverter)).split(/^(\S+)\s*-?\s*/); +} + export function plainWithLinks( parts: readonly Proto.SymbolDisplayPart[] | string, filePathConverter: IFilePathToResourceConverter, From 342aa9c59a2ca6aab8fce5043874644718415d8a Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Wed, 12 Oct 2022 14:10:57 -0700 Subject: [PATCH 541/599] Improvements to i18n (#163372) * remove dead code from Transifex * use @vscode/l10n-dev for XLF operations for extensions * generated files * more generated files * remove dead code * move l10n-dev to where gulp is * generated --- build/lib/i18n.js | 455 ++--------------- build/lib/i18n.ts | 549 +++------------------ build/lib/test/i18n.test.js | 6 +- build/lib/test/i18n.test.ts | 6 +- build/npm/update-localization-extension.js | 2 +- package.json | 1 + yarn.lock | 88 +++- 7 files changed, 203 insertions(+), 904 deletions(-) diff --git a/build/lib/i18n.js b/build/lib/i18n.js index b97da8b9fbe..2d407ad6f1f 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -4,19 +4,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.prepareI18nFiles = exports.pullSetupXlfFiles = exports.findObsoleteResources = exports.pushXlfFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.Limiter = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; +exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; const path = require("path"); const fs = require("fs"); const event_stream_1 = require("event-stream"); const File = require("vinyl"); const Is = require("is"); const xml2js = require("xml2js"); -const https = require("https"); const gulp = require("gulp"); const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const iconv = require("@vscode/iconv-lite-umd"); -const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; +const l10n_dev_1 = require("@vscode/l10n-dev"); function log(message, ...rest) { fancyLog(ansiColors.green('[i18n]'), message, ...rest); } @@ -63,19 +62,6 @@ var BundledFormat; } BundledFormat.is = is; })(BundledFormat || (BundledFormat = {})); -var PackageJsonFormat; -(function (PackageJsonFormat) { - function is(value) { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - const element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } - PackageJsonFormat.is = is; -})(PackageJsonFormat || (PackageJsonFormat = {})); class Line { constructor(indent = 0) { this.buffer = []; @@ -184,31 +170,6 @@ class XLF { } } exports.XLF = XLF; -XLF.parsePseudo = function (xlfString) { - return new Promise((resolve) => { - const parser = new xml2js.Parser(); - const files = []; - parser.parseString(xlfString, function (_err, result) { - const fileNodes = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); -}; XLF.parse = function (xlfString) { return new Promise((resolve, reject) => { const parser = new xml2js.Parser(); @@ -222,8 +183,8 @@ XLF.parse = function (xlfString) { reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); } fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { + const name = file.$.original; + if (!name) { reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); } const language = file.$['target-language']; @@ -244,45 +205,18 @@ XLF.parse = function (xlfString) { val = val._ ? val._ : ''; } if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${name} is missing the ID attribute.`)); return; } messages[key] = decodeEntities(val); }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + files.push({ messages, name, language: language.toLowerCase() }); } }); resolve(files); }); }); }; -class Limiter { - constructor(maxDegreeOfParalellism) { - this.maxDegreeOfParalellism = maxDegreeOfParalellism; - this.outstandingPromises = []; - this.runningPromises = 0; - } - queue(factory) { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - consume() { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift(); - this.runningPromises++; - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - consumed() { - this.runningPromises--; - this.consume(); - } -} -exports.Limiter = Limiter; function sortLanguages(languages) { return languages.sort((a, b) => { return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); @@ -589,12 +523,12 @@ function createXlfFilesForExtensions() { return; } counter++; - let _xlf; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); + let _l10nMap; + function getL10nMap() { + if (!_l10nMap) { + _l10nMap = new Map(); } - return _xlf; + return _l10nMap; } gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe((0, event_stream_1.through)(function (file) { if (file.isBuffer()) { @@ -602,34 +536,22 @@ function createXlfFilesForExtensions() { const basename = path.basename(file.path); if (basename === 'package.nls.json') { const json = JSON.parse(buffer.toString('utf8')); - const keys = []; - const messages = []; - Object.keys(json).forEach((key) => { - const value = json[key]; - if (Is.string(value)) { - keys.push(key); - messages.push(value); - } - else if (value) { - keys.push({ - key, - comment: value.comment - }); - messages.push(value.message); - } - else { - keys.push(key); - messages.push(`Unknown message for key: ${key}`); - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + getL10nMap().set(`extensions/${extensionName}/package`, json); } else if (basename === 'nls.metadata.json') { const json = JSON.parse(buffer.toString('utf8')); const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (const file in json) { const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + const info = Object.create(null); + for (let i = 0; i < fileContent.messages.length; i++) { + const message = fileContent.messages[i]; + const { key, comment } = LocalizeInfo.is(fileContent.keys[i]) + ? fileContent.keys[i] + : { key: fileContent.keys[i], comment: undefined }; + info[key] = comment ? { message, comment } : message; + } + getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } } else { @@ -638,10 +560,10 @@ function createXlfFilesForExtensions() { } } }, function () { - if (_xlf) { + if (_l10nMap) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') + contents: Buffer.from((0, l10n_dev_1.getL10nXlf)(_l10nMap), 'utf8') }); folderStream.queue(xlfFile); } @@ -712,299 +634,7 @@ function createXlfFilesForIsl() { }); } exports.createXlfFilesForIsl = createXlfFilesForIsl; -function pushXlfFiles(apiHostname, username, password) { - const tryGetPromises = []; - const updateCreatePromises = []; - return (0, event_stream_1.through)(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } - else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.pushXlfFiles = pushXlfFiles; -function getAllResources(project, apiHostname, username, password) { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (res) => { - const buffer = []; - res.on('data', (chunk) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - const json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } - else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); -} -function findObsoleteResources(apiHostname, username, password) { - const resourcesByProject = Object.create(null); - resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone - return (0, event_stream_1.through)(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - const i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); - const extractedResources = []; - for (const project of [workbenchProject, editorProject]) { - for (const resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - const promises = []; - for (const project in resourcesByProject) { - promises.push(getAllResources(project, apiHostname, username, password).then(resources => { - const expectedResources = resourcesByProject[project]; - const unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - })); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.findObsoleteResources = findObsoleteResources; -function tryGetResource(project, slug, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } - else if (response.statusCode === 200) { - resolve(true); - } - else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - request.end(); - }); -} -function createResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - const request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } - else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -/** - * The following link provides information about how Transifex handles updates of a resource file: - * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files - */ -function updateResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - const request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - let responseBuffer = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } - else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { - const setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); -} -exports.pullSetupXlfFiles = pullSetupXlfFiles; -function pullXlfFiles(apiHostname, username, password, language, resources) { - const credentials = `${username}:${password}`; - const expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - return (0, event_stream_1.readable)(function (_count, callback) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - callback(); - }); -} -const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); -function retrieveResource(language, resource, apiHostname, credentials) { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - const transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - const request = https.request(options, (res) => { - const xlfBuffer = []; - res.on('data', (chunk) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } - else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } - else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); -} -function prepareI18nFiles() { - const parsePromises = []; - return (0, event_stream_1.through)(function (xlf) { - const stream = this; - const parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - const translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); -} -exports.prepareI18nFiles = prepareI18nFiles; -function createI18nFile(originalFilePath, messages) { +function createI18nFile(name, messages) { const result = Object.create(null); result[''] = [ '--------------------------------------------------------------------------------------------', @@ -1021,12 +651,20 @@ function createI18nFile(originalFilePath, messages) { content = content.replace(/\n/g, '\r\n'); } return new File({ - path: path.join(originalFilePath + '.i18n.json'), + path: path.join(name + '.i18n.json'), contents: Buffer.from(content, 'utf8') }); } const i18nPackVersion = '1.0.0'; -function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { +function getRecordFromL10nJsonFormat(l10nJsonFormat) { + const record = {}; + for (const key of Object.keys(l10nJsonFormat)) { + const value = l10nJsonFormat[key]; + record[key] = typeof value === 'string' ? value : value.message; + } + return record; +} +function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths) { const parsePromises = []; const mainPack = { version: i18nPackVersion, contents: {} }; const extensionsPacks = {}; @@ -1036,11 +674,11 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse const resource = path.basename(xlf.relative, '.xlf'); const contents = xlf.contents.toString(); log(`Found ${project}: ${resource}`); - const parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + const parsePromise = (0, l10n_dev_1.getL10nFilesFromXlf)(contents); parsePromises.push(parsePromise); parsePromise.then(resolvedFiles => { resolvedFiles.forEach(file => { - const path = file.originalFilePath; + const path = file.name; const firstSlash = path.indexOf('/'); if (project === extensionsProject) { let extPack = extensionsPacks[resource]; @@ -1050,14 +688,14 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse const externalId = externalExtensions[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; + extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } else { - extPack.contents[path] = file.messages; + extPack.contents[path] = getRecordFromL10nJsonFormat(file.messages); } } else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + mainPack.contents[path.substring(firstSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } }); }).catch(reason => { @@ -1099,7 +737,7 @@ function prepareIslFiles(language, innoSetupConfig) { parsePromises.push(parsePromise); parsePromise.then(resolvedFiles => { resolvedFiles.forEach(file => { - const translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + const translatedFile = createIslFile(file.name, file.messages, language, innoSetupConfig); stream.queue(translatedFile); }); }).catch(reason => { @@ -1114,14 +752,14 @@ function prepareIslFiles(language, innoSetupConfig) { }); } exports.prepareIslFiles = prepareIslFiles; -function createIslFile(originalFilePath, messages, language, innoSetup) { +function createIslFile(name, messages, language, innoSetup) { const content = []; let originalContent; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + if (path.basename(name) === 'Default') { + originalContent = new TextModel(fs.readFileSync(name + '.isl', 'utf8')); } else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + originalContent = new TextModel(fs.readFileSync(name + '.en.isl', 'utf8')); } originalContent.lines.forEach(line => { if (line.length > 0) { @@ -1143,7 +781,7 @@ function createIslFile(originalFilePath, messages, language, innoSetup) { } } }); - const basename = path.basename(originalFilePath); + const basename = path.basename(name); const filePath = `${basename}.${language.id}.isl`; const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); return new File({ @@ -1174,6 +812,3 @@ function encodeEntities(value) { function decodeEntities(value) { return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); } -function pseudify(message) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; -} diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 20c1dc93f99..0045bb64fcf 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -6,17 +6,15 @@ import * as path from 'path'; import * as fs from 'fs'; -import { through, readable, ThroughStream } from 'event-stream'; +import { through, ThroughStream } from 'event-stream'; import * as File from 'vinyl'; import * as Is from 'is'; import * as xml2js from 'xml2js'; -import * as https from 'https'; import * as gulp from 'gulp'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as iconv from '@vscode/iconv-lite-umd'; - -const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; +import { l10nJsonFormat, getL10nXlf, l10nJsonDetails, getL10nFilesFromXlf } from '@vscode/l10n-dev'; function log(message: any, ...rest: any[]): void { fancyLog(ansiColors.green('[i18n]'), message, ...rest); @@ -58,11 +56,6 @@ export const externalExtensionsWithTranslations = { 'vscode-node-debug2': 'ms-vscode.node-debug2' }; - -interface Map { - [key: string]: V; -} - interface Item { id: string; message: string; @@ -74,12 +67,6 @@ export interface Resource { project: string; } -interface ParsedXLF { - messages: Map; - originalFilePath: string; - language: string; -} - interface LocalizeInfo { key: string; comment: string[]; @@ -93,9 +80,9 @@ module LocalizeInfo { } interface BundledFormat { - keys: Map<(string | LocalizeInfo)[]>; - messages: Map; - bundles: Map; + keys: Record; + messages: Record; + bundles: Record; } module BundledFormat { @@ -111,27 +98,6 @@ module BundledFormat { } } -interface ValueFormat { - message: string; - comment: string[]; -} - -interface PackageJsonFormat { - [key: string]: string | ValueFormat; -} - -module PackageJsonFormat { - export function is(value: any): value is PackageJsonFormat { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - const element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } -} - interface BundledExtensionFormat { [key: string]: { messages: string[]; @@ -181,7 +147,7 @@ class TextModel { export class XLF { private buffer: string[]; - private files: Map; + private files: Record; public numberOfMessages: number; constructor(public project: string) { @@ -274,37 +240,11 @@ export class XLF { this.buffer.push(line.toString()); } - static parsePseudo = function (xlfString: string): Promise { - return new Promise((resolve) => { - const parser = new xml2js.Parser(); - const files: { messages: Map; originalFilePath: string; language: string }[] = []; - parser.parseString(xlfString, function (_err: any, result: any) { - const fileNodes: any[] = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages: Map = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit: any) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); - }; - - static parse = function (xlfString: string): Promise { + static parse = function (xlfString: string): Promise { return new Promise((resolve, reject) => { const parser = new xml2js.Parser(); - const files: { messages: Map; originalFilePath: string; language: string }[] = []; + const files: { messages: Record; name: string; language: string }[] = []; parser.parseString(xlfString, function (err: any, result: any) { if (err) { @@ -317,15 +257,15 @@ export class XLF { } fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { + const name = file.$.original; + if (!name) { reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); } const language = file.$['target-language']; if (!language) { reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); } - const messages: Map = {}; + const messages: Record = {}; const transUnits = file.body[0]['trans-unit']; if (transUnits) { @@ -341,12 +281,12 @@ export class XLF { val = val._ ? val._ : ''; } if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${name} is missing the ID attribute.`)); return; } messages[key] = decodeEntities(val); }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + files.push({ messages, name, language: language.toLowerCase() }); } }); @@ -356,49 +296,6 @@ export class XLF { }; } -export interface ITask { - (): T; -} - -interface ILimitedTaskFactory { - factory: ITask>; - c: (value?: T | Promise) => void; - e: (error?: any) => void; -} - -export class Limiter { - private runningPromises: number; - private outstandingPromises: ILimitedTaskFactory[]; - - constructor(private maxDegreeOfParalellism: number) { - this.outstandingPromises = []; - this.runningPromises = 0; - } - - queue(factory: ITask>): Promise { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - - private consume(): void { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift()!; - this.runningPromises++; - - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - - private consumed(): void { - this.runningPromises--; - this.consume(); - } -} - function sortLanguages(languages: Language[]): Language[] { return languages.sort((a: Language, b: Language): number => { return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); @@ -480,9 +377,9 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json const messageSection = json.messages; const bundleSection = json.bundles; - const statistics: Map = Object.create(null); + const statistics: Record = Object.create(null); - const defaultMessages: Map> = Object.create(null); + const defaultMessages: Record> = Object.create(null); const modules = Object.keys(keysSection); modules.forEach((module) => { const keys = keysSection[module]; @@ -491,7 +388,7 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); return; } - const messageMap: Map = Object.create(null); + const messageMap: Record = Object.create(null); defaultMessages[module] = messageMap; keys.map((key, i) => { if (typeof key === 'string') { @@ -514,7 +411,7 @@ function processCoreBundleFormat(fileHeader: string, languages: Language[], json } statistics[language.id] = 0; - const localizedModules: Map = Object.create(null); + const localizedModules: Record = Object.create(null); const languageFolderName = language.translationId || language.id; const i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); let allMessages: I18nFormat | undefined; @@ -648,7 +545,7 @@ export function createXlfFilesForCoreBundle(): ThroughStream { const basename = path.basename(file.path); if (basename === 'nls.metadata.json') { if (file.isBuffer()) { - const xlfs: Map = Object.create(null); + const xlfs: Record = Object.create(null); const json: BundledFormat = JSON.parse((file.contents as Buffer).toString('utf8')); for (const coreModule in json.keys) { const projectResource = getResource(coreModule); @@ -704,44 +601,35 @@ export function createXlfFilesForExtensions(): ThroughStream { return; } counter++; - let _xlf: XLF; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); + let _l10nMap: Map; + function getL10nMap() { + if (!_l10nMap) { + _l10nMap = new Map(); } - return _xlf; + return _l10nMap; } gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { if (file.isBuffer()) { const buffer: Buffer = file.contents as Buffer; const basename = path.basename(file.path); if (basename === 'package.nls.json') { - const json: PackageJsonFormat = JSON.parse(buffer.toString('utf8')); - const keys: Array = []; - const messages: string[] = []; - Object.keys(json).forEach((key) => { - const value = json[key]; - if (Is.string(value)) { - keys.push(key); - messages.push(value); - } else if (value) { - keys.push({ - key, - comment: value.comment - }); - messages.push(value.message); - } else { - keys.push(key); - messages.push(`Unknown message for key: ${key}`); - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + const json: l10nJsonFormat = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/package`, json); } else if (basename === 'nls.metadata.json') { const json: BundledExtensionFormat = JSON.parse(buffer.toString('utf8')); const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (const file in json) { const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + const info: l10nJsonFormat = Object.create(null); + for (let i = 0; i < fileContent.messages.length; i++) { + const message = fileContent.messages[i]; + const { key, comment } = LocalizeInfo.is(fileContent.keys[i]) + ? fileContent.keys[i] as LocalizeInfo + : { key: fileContent.keys[i] as string, comment: undefined }; + + info[key] = comment ? { message, comment } : message; + } + getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } } else { this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); @@ -749,10 +637,10 @@ export function createXlfFilesForExtensions(): ThroughStream { } } }, function () { - if (_xlf) { + if (_l10nMap) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') + contents: Buffer.from(getL10nXlf(_l10nMap), 'utf8') }); folderStream.queue(xlfFile); } @@ -828,321 +716,7 @@ export function createXlfFilesForIsl(): ThroughStream { }); } -export function pushXlfFiles(apiHostname: string, username: string, password: string): ThroughStream { - const tryGetPromises: Array> = []; - const updateCreatePromises: Array> = []; - - return through(function (this: ThroughStream, file: File) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); -} - -function getAllResources(project: string, apiHostname: string, username: string, password: string): Promise { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - - const request = https.request(options, (res) => { - const buffer: Buffer[] = []; - res.on('data', (chunk: Buffer) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - const json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); -} - -export function findObsoleteResources(apiHostname: string, username: string, password: string): ThroughStream { - const resourcesByProject: Map = Object.create(null); - resourcesByProject[extensionsProject] = ([] as any[]).concat(externalExtensionsWithTranslations); // clone - - return through(function (this: ThroughStream, file: File) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - const i18Resources = [...json.editor, ...json.workbench].map((r: Resource) => r.project + '/' + r.name.replace(/\//g, '_')); - const extractedResources: string[] = []; - for (const project of [workbenchProject, editorProject]) { - for (const resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - - const promises: Array> = []; - for (const project in resourcesByProject) { - promises.push( - getAllResources(project, apiHostname, username, password).then(resources => { - const expectedResources = resourcesByProject[project]; - const unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - }) - ); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); -} - -function tryGetResource(project: string, slug: string, apiHostname: string, credentials: string): Promise { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } else if (response.statusCode === 200) { - resolve(true); - } else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - - request.end(); - }); -} - -function createResource(project: string, slug: string, xlfFile: File, apiHostname: string, credentials: any): Promise { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - - const request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - - request.write(data); - request.end(); - }); -} - -/** - * The following link provides information about how Transifex handles updates of a resource file: - * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files - */ -function updateResource(project: string, slug: string, xlfFile: File, apiHostname: string, credentials: string): Promise { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - - const request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - - let responseBuffer: string = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - - request.write(data); - request.end(); - }); -} - -export function pullSetupXlfFiles(apiHostname: string, username: string, password: string, language: Language, includeDefault: boolean): NodeJS.ReadableStream { - const setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); -} - -function pullXlfFiles(apiHostname: string, username: string, password: string, language: Language, resources: Resource[]): NodeJS.ReadableStream { - const credentials = `${username}:${password}`; - const expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - - return readable(function (_count: any, callback: any) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file: File | null) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - - callback(); - }); -} -const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); - -function retrieveResource(language: Language, resource: Resource, apiHostname: string, credentials: string): Promise { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - const transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - - const request = https.request(options, (res) => { - const xlfBuffer: Buffer[] = []; - res.on('data', (chunk: Buffer) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); -} - -export function prepareI18nFiles(): ThroughStream { - const parsePromises: Promise[] = []; - - return through(function (this: ThroughStream, xlf: File) { - const stream = this; - const parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then( - resolvedFiles => { - resolvedFiles.forEach(file => { - const translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - } - ); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); -} - -function createI18nFile(originalFilePath: string, messages: any): File { +function createI18nFile(name: string, messages: any): File { const result = Object.create(null); result[''] = [ '--------------------------------------------------------------------------------------------', @@ -1160,7 +734,7 @@ function createI18nFile(originalFilePath: string, messages: any): File { content = content.replace(/\n/g, '\r\n'); } return new File({ - path: path.join(originalFilePath + '.i18n.json'), + path: path.join(name + '.i18n.json'), contents: Buffer.from(content, 'utf8') }); } @@ -1168,7 +742,7 @@ function createI18nFile(originalFilePath: string, messages: any): File { interface I18nPack { version: string; contents: { - [path: string]: Map; + [path: string]: Record; }; } @@ -1179,22 +753,31 @@ export interface TranslationPath { resourceName: string; } -export function prepareI18nPackFiles(externalExtensions: Map, resultingTranslationPaths: TranslationPath[], pseudo = false): NodeJS.ReadWriteStream { - const parsePromises: Promise[] = []; +function getRecordFromL10nJsonFormat(l10nJsonFormat: l10nJsonFormat): Record { + const record: Record = {}; + for (const key of Object.keys(l10nJsonFormat)) { + const value = l10nJsonFormat[key]; + record[key] = typeof value === 'string' ? value : value.message; + } + return record; +} + +export function prepareI18nPackFiles(externalExtensions: Record, resultingTranslationPaths: TranslationPath[]): NodeJS.ReadWriteStream { + const parsePromises: Promise[] = []; const mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; - const extensionsPacks: Map = {}; + const extensionsPacks: Record = {}; const errors: any[] = []; return through(function (this: ThroughStream, xlf: File) { const project = path.basename(path.dirname(path.dirname(xlf.relative))); const resource = path.basename(xlf.relative, '.xlf'); const contents = xlf.contents.toString(); log(`Found ${project}: ${resource}`); - const parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + const parsePromise = getL10nFilesFromXlf(contents); parsePromises.push(parsePromise); parsePromise.then( resolvedFiles => { resolvedFiles.forEach(file => { - const path = file.originalFilePath; + const path = file.name; const firstSlash = path.indexOf('/'); if (project === extensionsProject) { @@ -1205,12 +788,12 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT const externalId = externalExtensions[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; + extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } else { - extPack.contents[path] = file.messages; + extPack.contents[path] = getRecordFromL10nJsonFormat(file.messages); } } else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + mainPack.contents[path.substring(firstSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); } }); } @@ -1248,7 +831,7 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT } export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): ThroughStream { - const parsePromises: Promise[] = []; + const parsePromises: Promise[] = []; return through(function (this: ThroughStream, xlf: File) { const stream = this; @@ -1257,7 +840,7 @@ export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): parsePromise.then( resolvedFiles => { resolvedFiles.forEach(file => { - const translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + const translatedFile = createIslFile(file.name, file.messages, language, innoSetupConfig); stream.queue(translatedFile); }); } @@ -1273,13 +856,13 @@ export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): }); } -function createIslFile(originalFilePath: string, messages: Map, language: Language, innoSetup: InnoSetup): File { +function createIslFile(name: string, messages: l10nJsonFormat, language: Language, innoSetup: InnoSetup): File { const content: string[] = []; let originalContent: TextModel; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + if (path.basename(name) === 'Default') { + originalContent = new TextModel(fs.readFileSync(name + '.isl', 'utf8')); } else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + originalContent = new TextModel(fs.readFileSync(name + '.en.isl', 'utf8')); } originalContent.lines.forEach(line => { if (line.length > 0) { @@ -1302,7 +885,7 @@ function createIslFile(originalFilePath: string, messages: Map, language } }); - const basename = path.basename(originalFilePath); + const basename = path.basename(name); const filePath = `${basename}.${language.id}.isl`; const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); @@ -1336,7 +919,3 @@ function encodeEntities(value: string): string { function decodeEntities(value: string): string { return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); } - -function pseudify(message: string) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; -} diff --git a/build/lib/test/i18n.test.js b/build/lib/test/i18n.test.js index 4d339c120a9..3f8015e8c90 100644 --- a/build/lib/test/i18n.test.js +++ b/build/lib/test/i18n.test.js @@ -9,20 +9,20 @@ const i18n = require("../i18n"); suite('XLF Parser Tests', () => { const sampleXlf = 'Key #1Key #2 &'; const sampleTranslatedXlf = 'Key #1Кнопка #1Key #2 &Кнопка #2 &'; - const originalFilePath = 'vs/base/common/keybinding'; + const name = 'vs/base/common/keybinding'; const keys = ['key1', 'key2']; const messages = ['Key #1', 'Key #2 &']; const translatedMessages = { key1: 'Кнопка #1', key2: 'Кнопка #2 &' }; test('Keys & messages to XLF conversion', () => { const xlf = new i18n.XLF('vscode-workbench'); - xlf.addFile(originalFilePath, keys, messages); + xlf.addFile(name, keys, messages); const xlfString = xlf.toString(); assert.strictEqual(xlfString.replace(/\s{2,}/g, ''), sampleXlf); }); test('XLF to keys & messages conversion', () => { i18n.XLF.parse(sampleTranslatedXlf).then(function (resolvedFiles) { assert.deepStrictEqual(resolvedFiles[0].messages, translatedMessages); - assert.strictEqual(resolvedFiles[0].originalFilePath, originalFilePath); + assert.strictEqual(resolvedFiles[0].name, name); }); }); test('JSON file source path to Transifex resource match', () => { diff --git a/build/lib/test/i18n.test.ts b/build/lib/test/i18n.test.ts index ab0924c4350..b8a68323dd7 100644 --- a/build/lib/test/i18n.test.ts +++ b/build/lib/test/i18n.test.ts @@ -9,14 +9,14 @@ import i18n = require('../i18n'); suite('XLF Parser Tests', () => { const sampleXlf = 'Key #1Key #2 &'; const sampleTranslatedXlf = 'Key #1Кнопка #1Key #2 &Кнопка #2 &'; - const originalFilePath = 'vs/base/common/keybinding'; + const name = 'vs/base/common/keybinding'; const keys = ['key1', 'key2']; const messages = ['Key #1', 'Key #2 &']; const translatedMessages = { key1: 'Кнопка #1', key2: 'Кнопка #2 &' }; test('Keys & messages to XLF conversion', () => { const xlf = new i18n.XLF('vscode-workbench'); - xlf.addFile(originalFilePath, keys, messages); + xlf.addFile(name, keys, messages); const xlfString = xlf.toString(); assert.strictEqual(xlfString.replace(/\s{2,}/g, ''), sampleXlf); @@ -25,7 +25,7 @@ suite('XLF Parser Tests', () => { test('XLF to keys & messages conversion', () => { i18n.XLF.parse(sampleTranslatedXlf).then(function (resolvedFiles) { assert.deepStrictEqual(resolvedFiles[0].messages, translatedMessages); - assert.strictEqual(resolvedFiles[0].originalFilePath, originalFilePath); + assert.strictEqual(resolvedFiles[0].name, name); }); }); diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js index 1a689a189ea..9876882a6c4 100644 --- a/build/npm/update-localization-extension.js +++ b/build/npm/update-localization-extension.js @@ -68,7 +68,7 @@ function update(options) { console.log(`Importing translations for ${languageId} form '${location}' to '${translationDataFolder}' ...`); let translationPaths = []; gulp.src(path.join(location, '**', languageId, '*.xlf'), { silent: false }) - .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps')) + .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths)) .on('error', (error) => { console.log(`Error occurred while importing translations:`); translationPaths = undefined; diff --git a/package.json b/package.json index 55394b42987..a4676dc092f 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "@typescript-eslint/eslint-plugin": "^5.39.0", "@typescript-eslint/experimental-utils": "^5.39.0", "@typescript-eslint/parser": "^5.39.0", + "@vscode/l10n-dev": "0.0.15", "@vscode/telemetry-extractor": "^1.9.8", "@vscode/test-web": "^0.0.29", "ansi-colors": "^3.2.3", diff --git a/yarn.lock b/yarn.lock index 86e04612a79..03376126fba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1253,6 +1253,18 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== +"@vscode/l10n-dev@0.0.15": + version "0.0.15" + resolved "https://registry.yarnpkg.com/@vscode/l10n-dev/-/l10n-dev-0.0.15.tgz#677b527987ccd39e32c50956f139736a788061d6" + integrity sha512-zLuo/pa+FtnFrVq/7M8VHshgejNZ6TvnRW9/um1pLkg92PZ9glDgmwXUv1AdpBu5KNzgH9odiMKS4YQDkS12wQ== + dependencies: + deepmerge-json "^1.5.0" + glob "^8.0.3" + pseudo-localization "^2.4.0" + typescript "^4.7.4" + xml2js "^0.4.23" + yargs "^17.5.1" + "@vscode/ripgrep@^1.14.2": version "1.14.2" resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.14.2.tgz#47c0eec2b64f53d8f7e1b5ffd22a62e229191c34" @@ -2781,6 +2793,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -3591,6 +3612,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge-json@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/deepmerge-json/-/deepmerge-json-1.5.0.tgz#6daa3600d53fc1f646604853bc99e95e260fbda0" + integrity sha512-jZRrDmBKjmGcqMFEUJ14FjMJwm05Qaked+1vxaALRtF0UAl7lPU8OLWXFxvoeg3jbQM249VPFVn8g2znaQkEtA== + deepmerge@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.1.0.tgz#a612626ce4803da410d77554bfd80361599c034d" @@ -5025,6 +5051,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-stdin@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" + integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== + get-stream@6.0.1, get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -5172,6 +5203,17 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" + integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-agent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" @@ -7322,7 +7364,7 @@ minimatch@4.2.1: dependencies: brace-expansion "^1.1.7" -minimatch@^5.1.0: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== @@ -8876,6 +8918,16 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= +pseudo-localization@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/pseudo-localization/-/pseudo-localization-2.4.0.tgz#5c19da35bc182ad7fc00d82d33dd42e88005e241" + integrity sha512-ISYMOKY8+f+PmiXMFw2y6KLY74LBrv/8ml/VjjoVEV2k+MS+OJZz7ydciK5ntJwxPrKQPTU1+oXq9Mx2b0zEzg== + dependencies: + flat "^5.0.2" + get-stdin "^7.0.0" + typescript "^4.7.4" + yargs "^17.2.1" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -10050,6 +10102,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.padend@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.1.tgz#824c84265dbac46cade2b957b38b6a5d8d1683c5" @@ -10771,6 +10832,11 @@ typescript@^2.6.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= +typescript@^4.7.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + typescript@^4.9.0-dev.20221011: version "4.9.0-dev.20221011" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.0-dev.20221011.tgz#5c0ccbb7cfc1d8928fec987b7fc490cd664869e3" @@ -11534,7 +11600,7 @@ ws@^7.2.0: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -xml2js@^0.4.17: +xml2js@^0.4.17, xml2js@^0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -11681,6 +11747,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.0.0: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -11738,6 +11809,19 @@ yargs@^15.3.0: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^17.2.1, yargs@^17.5.1: + version "17.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c" + integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yargs@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.1.tgz#67f0ef52e228d4ee0d6311acede8850f53464df6" From 3ddce0580ed69c46c259ca79d51f139ae76b46ee Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 12 Oct 2022 14:19:38 -0700 Subject: [PATCH 542/599] add diff editor navigation tip to aria label (#163368) --- src/vs/editor/browser/widget/diffEditorWidget.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 7a63e5427f3..d98a84f5ed6 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -172,6 +172,8 @@ const diffInsertIcon = registerIcon('diff-insert', Codicon.add, nls.localize('di const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove, nls.localize('diffRemoveIcon', 'Line decoration for removals in the diff editor.')); const ttPolicy = window.trustedTypes?.createPolicy('diffEditorWidget', { createHTML: value => value }); +const ariaNavigationTip = nls.localize('diff-aria-navigation-tip', ' use Shift + F7 to navigate changes'); + export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor { private static readonly ONE_OVERVIEW_WIDTH = 15; @@ -1246,6 +1248,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE if (options.originalAriaLabel) { result.ariaLabel = options.originalAriaLabel; } + result.ariaLabel += ariaNavigationTip; result.readOnly = !this._options.originalEditable; result.dropIntoEditor = { enabled: !result.readOnly }; result.extraEditorClassName = 'original-in-monaco-diff-editor'; @@ -1263,7 +1266,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE if (options.modifiedAriaLabel) { result.ariaLabel = options.modifiedAriaLabel; } - + result.ariaLabel += ariaNavigationTip; result.wordWrapOverride1 = this._options.diffWordWrap; result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; result.scrollbar!.verticalHasArrows = false; From b5542cae84a18a46270e620214f49172d287154d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 15:23:09 -0700 Subject: [PATCH 543/599] Document more of lifecycle.ts (#163482) --- src/vs/base/common/lifecycle.ts | 66 ++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 08e4da78072..d58b2fa2155 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -6,6 +6,8 @@ import { once } from 'vs/base/common/functional'; import { Iterable } from 'vs/base/common/iterator'; +// #region Disposable Tracking + /** * Enables logging of potentially leaked disposables. * @@ -108,14 +110,31 @@ export function markAsSingleton(singleton: T): T { return singleton; } +// #endregion + +/** + * An object that performs a cleanup operation when `.dispose()` is called. + * + * Some examples of how disposables are used: + * + * - An event listener that removes itself when `.dispose()` is called. + * - A resource such as a file system watcher that cleans up the resource when `.dispose()` is called. + * - The return value from registering a provider. When `.dispose()` is called, the provider is unregistered. + */ export interface IDisposable { dispose(): void; } +/** + * Check if `thing` is {@link IDisposable disposable}. + */ export function isDisposable(thing: E): thing is E & IDisposable { return typeof (thing).dispose === 'function' && (thing).dispose.length === 0; } +/** + * Disposes of the value(s) passed in. + */ export function dispose(disposable: T): T; export function dispose(disposable: T | undefined): T | undefined; export function dispose = Iterable>(disposables: A): A; @@ -157,12 +176,18 @@ export function disposeIfDisposable(disposables: return []; } +/** + * Combine multiple disposable values into a single {@link IDisposable}. + */ export function combinedDisposable(...disposables: IDisposable[]): IDisposable { const parent = toDisposable(() => dispose(disposables)); setParentOfDisposables(disposables, parent); return parent; } +/** + * Turn a function that implements dispose into an {@link IDisposable}. + */ export function toDisposable(fn: () => void): IDisposable { const self = trackDisposable({ dispose: once(() => { @@ -173,6 +198,13 @@ export function toDisposable(fn: () => void): IDisposable { return self; } +/** + * Manages a collection of disposable values. + * + * This is the preferred way to manage multiple disposables. A `DisposableStore` is safer to work with than an + * `IDisposable[]` as it considers edge cases, such as registering the same value multiple times or adding an item to a + * store that has already been disposed of. + */ export class DisposableStore implements IDisposable { static DISABLE_DISPOSED_WARNING = false; @@ -200,7 +232,7 @@ export class DisposableStore implements IDisposable { } /** - * Returns `true` if this object has been disposed + * @return `true` if this object has been disposed of. */ public get isDisposed(): boolean { return this._isDisposed; @@ -221,6 +253,9 @@ export class DisposableStore implements IDisposable { } } + /** + * Add a new {@link IDisposable disposable} to the collection. + */ public add(o: T): T { if (!o) { return o; @@ -242,8 +277,18 @@ export class DisposableStore implements IDisposable { } } +/** + * Abstract base class for a {@link IDisposable disposable} object. + * + * Subclasses can {@linkcode _register} disposables that will be automatically cleaned up when this object is disposed of. + */ export abstract class Disposable implements IDisposable { + /** + * A disposable that does nothing when it is disposed of. + * + * TODO: This should not be a static property. + */ static readonly None = Object.freeze({ dispose() { } }); protected readonly _store = new DisposableStore(); @@ -259,6 +304,9 @@ export abstract class Disposable implements IDisposable { this._store.dispose(); } + /** + * Adds `o` to the collection of disposables managed by this object. + */ protected _register(o: T): T { if ((o as unknown as Disposable) === this) { throw new Error('Cannot register a disposable on itself!'); @@ -297,7 +345,10 @@ export class MutableDisposable implements IDisposable { this._value = value; } - clear() { + /** + * Resets the stored value and disposed of the previously stored value. + */ + clear(): void { this.value = undefined; } @@ -456,12 +507,20 @@ export class DisposableMap implements ID trackDisposable(this); } + /** + * Disposes of all stored values and mark this object as disposed. + * + * Trying to use this object after it has been disposed of is an error. + */ dispose(): void { markAsDisposed(this); this._isDisposed = true; this.clearAndDisposeAll(); } + /** + * Disposes of all stored values and clear the map, but DO NOT mark this object as disposed. + */ clearAndDisposeAll(): void { if (!this._store.size) { return; @@ -494,6 +553,9 @@ export class DisposableMap implements ID this._store.set(key, value); } + /** + * Delete the value stored for `key` from this map and also dispose of it. + */ deleteAndDispose(key: K): void { this._store.get(key)?.dispose(); this._store.delete(key); From f5ced8231b65f7939c29e4cf23949951eb1e6596 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 15:38:29 -0700 Subject: [PATCH 544/599] Small clean up for terminal tab list rendering lifecycle (#163485) Small clean up for terminal tab list lifecycle - Reuse the same `DisposableStore` across calls to `renderElement` - Make sure we call `dispose` on the actionbar instead of `clear`. This looks like an oversight --- .../terminal/browser/terminalTabsList.ts | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index 6baeb8f6596..82d9b1747e2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -261,7 +261,8 @@ class TerminalTabsRenderer implements IListRenderer { e.stopImmediatePropagation(); @@ -456,16 +453,14 @@ class TerminalTabsRenderer implements IListRenderer Date: Wed, 12 Oct 2022 15:38:57 -0700 Subject: [PATCH 545/599] add accessibility setting tag (#163358) --- src/vs/editor/common/config/editorOptions.ts | 4 +++- .../workbench/browser/workbench.contribution.ts | 1 + .../audioCues/browser/audioCues.contribution.ts | 9 ++++++--- .../browser/preferences.contribution.ts | 17 +++++++++++++++++ .../preferences/browser/settingsEditor2.ts | 1 + .../terminal/common/terminalConfiguration.ts | 3 ++- .../electron-sandbox/desktop.contribution.ts | 3 ++- 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 6e08c683030..f3ac6a40cf9 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1183,6 +1183,7 @@ class EditorAccessibilitySupport extends BaseEditorOption(ConfigurationExtensions.Con localize('workbench.reduceMotion.auto', "Render with reduced motion based on OS configuration."), ], default: 'auto', + tags: ['accessibility'], enum: ['on', 'off', 'auto'] }, 'workbench.layoutControl.enabled': { diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 74b817d6c1a..4519b93f7e0 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -29,27 +29,30 @@ const audioCueFeatureBase: IConfigurationPropertySchema = { localize('audioCues.enabled.on', "Enable audio cue."), localize('audioCues.enabled.off', "Disable audio cue.") ], + tags: ['accessibility'] }; Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ 'properties': { 'audioCues.enabled': { markdownDeprecationMessage: 'Deprecated. Use the specific setting for each audio cue instead (`audioCues.*`).', + tags: ['accessibility'] }, 'audioCues.volume': { 'description': localize('audioCues.volume', "The volume of the audio cues in percent (0-100)."), 'type': 'number', 'minimum': 0, 'maximum': 100, - 'default': 70 + 'default': 70, + tags: ['accessibility'] }, 'audioCues.lineHasBreakpoint': { 'description': localize('audioCues.lineHasBreakpoint', "Plays a sound when the active line has a breakpoint."), - ...audioCueFeatureBase, + ...audioCueFeatureBase }, 'audioCues.lineHasInlineSuggestion': { 'description': localize('audioCues.lineHasInlineSuggestion', "Plays a sound when the active line has an inline suggestion."), - ...audioCueFeatureBase, + ...audioCueFeatureBase }, 'audioCues.lineHasError': { 'description': localize('audioCues.lineHasError', "Plays a sound when the active line has an error."), diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index e1aab482fb5..2e3ffc352c1 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -422,6 +422,23 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon return accessor.get(IPreferencesService).openWorkspaceSettings(args); } }); + + registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.openAccessibilitySettings', + title: { value: nls.localize('openAccessibilitySettings', "Open Accessibility Settings"), original: 'Open Accessibility Settings' }, + category, + menu: { + id: MenuId.CommandPalette, + when: WorkbenchStateContext.notEqualsTo('empty') + } + }); + } + async run(accessor: ServicesAccessor) { + await accessor.get(IPreferencesService).openSettings({ jsonEditor: false, query: '@tag:accessibility' }); + } + }); registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 69f441beb3d..f12a3672b7b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -114,6 +114,7 @@ export class SettingsEditor2 extends EditorPane { '@tag:sync', '@tag:usesOnlineServices', '@tag:telemetry', + '@tag:accessibility', `@${ID_SETTING_TAG}`, `@${EXTENSION_SETTING_TAG}`, `@${FEATURE_SETTING_TAG}scm`, diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 790e1777020..ed2caa4f5c2 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -186,7 +186,8 @@ const terminalConfiguration: IConfigurationNode = { [TerminalSettingId.MinimumContrastRatio]: { markdownDescription: localize('terminal.integrated.minimumContrastRatio', "When set, the foreground color of each cell will change to try meet the contrast ratio specified. Note that this will not apply to `powerline` characters per #146406. Example values:\n\n- 1: Do nothing and use the standard theme colors.\n- 4.5: [WCAG AA compliance (minimum)](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) (default).\n- 7: [WCAG AAA compliance (enhanced)](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast7.html).\n- 21: White on black or black on white."), type: 'number', - default: 4.5 + default: 4.5, + tags: ['accessibility'] }, [TerminalSettingId.FastScrollSensitivity]: { markdownDescription: localize('terminal.integrated.fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`."), diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 95e31623896..d2a4a62970b 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -170,7 +170,8 @@ import product from 'vs/platform/product/common/product'; 'type': 'number', 'default': 0, 'description': localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity."), - ignoreSync: true + ignoreSync: true, + tags: ['accessibility'] }, 'window.newWindowDimensions': { 'type': 'string', From 07b87405e7a370a90d190891c32768e717bc665e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 12 Oct 2022 16:03:07 -0700 Subject: [PATCH 546/599] Don't depend on typescript protocol.d.ts (#163365) --- .../src/languageFeatures/completions.ts | 2 +- .../src/protocol.d.ts | 16 +++++++++++----- .../src/utils/configuration.ts | 7 ++++--- .../src/utils/tsconfig.ts | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts index a7b1e6c061c..68eb03dd690 100644 --- a/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -521,7 +521,7 @@ class MyCompletionItem extends vscode.CompletionItem { } } -function getScriptKindDetails(tsEntry: protocol.CompletionEntry,): string | undefined { +function getScriptKindDetails(tsEntry: Proto.CompletionEntry,): string | undefined { if (!tsEntry.kindModifiers || tsEntry.kind !== PConst.Kind.script) { return; } diff --git a/extensions/typescript-language-features/src/protocol.d.ts b/extensions/typescript-language-features/src/protocol.d.ts index 7e9e45f2575..1aec9e082ed 100644 --- a/extensions/typescript-language-features/src/protocol.d.ts +++ b/extensions/typescript-language-features/src/protocol.d.ts @@ -1,13 +1,19 @@ -import * as Proto from 'typescript/lib/protocol'; -export = Proto; +import * as ts from 'typescript/lib/tsserverlibrary'; +export = ts.server.protocol; + declare enum ServerType { Syntax = 'syntax', Semantic = 'semantic', } -declare module 'typescript/lib/protocol' { - interface Response { - readonly _serverType?: ServerType; +declare module 'typescript/lib/tsserverlibrary' { + namespace server.protocol { + type TextInsertion = ts.TextInsertion; + type ScriptElementKind = ts.ScriptElementKind; + + interface Response { + readonly _serverType?: ServerType; + } } } diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index efa442a5d0d..d1bfe62f738 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import * as objects from '../utils/objects'; +import * as Proto from '../protocol'; export enum TsServerLogLevel { Off, @@ -112,7 +113,7 @@ export interface TypeScriptServiceConfiguration { readonly enableProjectDiagnostics: boolean; readonly maxTsServerMemory: number; readonly enablePromptUseWorkspaceTsdk: boolean; - readonly watchOptions: protocol.WatchOptions | undefined; + readonly watchOptions: Proto.WatchOptions | undefined; readonly includePackageJsonAutoImports: 'auto' | 'on' | 'off' | undefined; readonly enableTsServerTracing: boolean; } @@ -196,8 +197,8 @@ export abstract class BaseServiceConfigurationProvider implements ServiceConfigu return configuration.get('typescript.tsserver.experimental.enableProjectDiagnostics', false); } - protected readWatchOptions(configuration: vscode.WorkspaceConfiguration): protocol.WatchOptions | undefined { - return configuration.get('typescript.tsserver.watchOptions'); + protected readWatchOptions(configuration: vscode.WorkspaceConfiguration): Proto.WatchOptions | undefined { + return configuration.get('typescript.tsserver.watchOptions'); } protected readIncludePackageJsonAutoImports(configuration: vscode.WorkspaceConfiguration): 'auto' | 'on' | 'off' | undefined { diff --git a/extensions/typescript-language-features/src/utils/tsconfig.ts b/extensions/typescript-language-features/src/utils/tsconfig.ts index baf1d4fd59b..1c71d659126 100644 --- a/extensions/typescript-language-features/src/utils/tsconfig.ts +++ b/extensions/typescript-language-features/src/utils/tsconfig.ts @@ -163,7 +163,7 @@ export async function openProjectConfigForFile( return; } - let res: ServerResponse.Response | undefined; + let res: ServerResponse.Response | undefined; try { res = await client.execute('projectInfo', { file, needFileNameList: false }, nulToken); } catch { From 7cfb34dff428cabc0a96ac223a8381f802dca9d7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 16:47:22 -0700 Subject: [PATCH 547/599] Freeze the notebook kernel context (#163488) This is an API object so it should not be extensible --- .../notebook/browser/view/renderers/webviewPreloads.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 6062c79818c..4533b9a5255 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -235,10 +235,10 @@ async function webviewPreloads(ctx: PreloadContext) { } function createKernelContext(): KernelPreloadContext { - return { + return Object.freeze({ onDidReceiveKernelMessage: onDidReceiveKernelMessage.event, postKernelMessage: (data: unknown) => postNotebookMessage('customKernelMessage', { message: data }), - }; + }); } const invokeSourceWithGlobals = (functionSrc: string, globals: { [name: string]: unknown }) => { From 24a2b8af8c7b99c4ef91b2b7f4ae97d313b7c9e3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 16:49:40 -0700 Subject: [PATCH 548/599] Re-apply: Clean up how the notebook renderer entrypoint is passed around (#163486) Revert "Revert "Clean up how the notebook renderer entrypoint is passed around (#163373)"" This reverts commit a3d8c337610dec6dbd24f4250639715327fb613f. Fixes #163415 --- .../browser/notebookExtensionPoint.ts | 4 +-- .../view/renderers/backLayerWebView.ts | 8 +++-- .../browser/view/renderers/webviewMessages.ts | 3 +- .../browser/view/renderers/webviewPreloads.ts | 8 ++--- .../contrib/notebook/common/notebookCommon.ts | 20 ++++++------ .../notebook/common/notebookOutputRenderer.ts | 31 +++++++------------ 6 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts index 651082499a8..f28fc03d29b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts @@ -6,7 +6,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { NotebookEditorPriority, NotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookEditorPriority, ContributedNotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const NotebookEditorContribution = Object.freeze({ type: 'type', @@ -36,7 +36,7 @@ export interface INotebookRendererContribution { readonly [NotebookRendererContribution.id]?: string; readonly [NotebookRendererContribution.displayName]: string; readonly [NotebookRendererContribution.mimeTypes]?: readonly string[]; - readonly [NotebookRendererContribution.entrypoint]: NotebookRendererEntrypoint; + readonly [NotebookRendererContribution.entrypoint]: ContributedNotebookRendererEntrypoint; readonly [NotebookRendererContribution.hardDependencies]: readonly string[]; readonly [NotebookRendererContribution.optionalDependencies]: readonly string[]; readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index f01090a0561..ba6810f0afb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -403,12 +403,14 @@ export class BackLayerWebView extends Disposable { private getRendererData(): RendererMetadata[] { return this.notebookService.getRenderers().map((renderer): RendererMetadata => { - const entrypoint = this.asWebviewUri(renderer.entrypoint, renderer.extensionLocation).toString(); + const entrypoint = { + extends: renderer.entrypoint.extends, + path: this.asWebviewUri(renderer.entrypoint.path, renderer.extensionLocation).toString() + }; return { id: renderer.id, entrypoint, mimeTypes: renderer.mimeTypes, - extends: renderer.extends, messaging: renderer.messaging !== RendererMessagingSpec.Never, isBuiltin: renderer.isBuiltin }; @@ -923,7 +925,7 @@ var requirejs = (function() { const notebookDir = this.getNotebookBaseUri(); return [ ...this.notebookService.getNotebookProviderResourceRoots(), - ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint)), + ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint.path)), ...workspaceFolders, notebookDir, ...this.getBuiltinLocalResourceRoots() diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 79adc52e51e..8b0902ba129 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -275,9 +275,8 @@ export interface IUpdateControllerPreloadsMessage { export interface RendererMetadata { readonly id: string; - readonly entrypoint: string; + readonly entrypoint: { readonly extends: string | undefined; readonly path: string }; readonly mimeTypes: readonly string[]; - readonly extends: string | undefined; readonly messaging: boolean; readonly isBuiltin: boolean; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 4533b9a5255..4907be7643d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1314,7 +1314,7 @@ async function webviewPreloads(ctx: PreloadContext) { /** Inner function cached in the _loadPromise(). */ private async _load(): Promise { - const module: RendererModule = await __import(this.data.entrypoint); + const module: RendererModule = await __import(this.data.entrypoint.path); if (!module) { return; } @@ -1324,7 +1324,7 @@ async function webviewPreloads(ctx: PreloadContext) { // Load all renderers that extend this renderer await Promise.all( ctx.rendererData - .filter(d => d.extends === this.data.id) + .filter(d => d.entrypoint.extends === this.data.id) .map(async d => { const renderer = renderers.getRenderer(d.id); if (!renderer) { @@ -1436,7 +1436,7 @@ async function webviewPreloads(ctx: PreloadContext) { } private rendererEqual(a: webviewMessages.RendererMetadata, b: webviewMessages.RendererMetadata) { - if (a.entrypoint !== b.entrypoint || a.id !== b.id || a.extends !== b.extends || a.messaging !== b.messaging) { + if (a.id !== b.id || a.entrypoint.path !== b.entrypoint.path || a.entrypoint.extends !== b.entrypoint.extends || a.messaging !== b.messaging) { return false; } @@ -1497,7 +1497,7 @@ async function webviewPreloads(ctx: PreloadContext) { .find((renderer) => renderer.data.id === preferredRendererId); } else { const renderers = Array.from(this._renderers.values()) - .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends); + .filter((renderer) => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.entrypoint.extends); if (renderers.length) { // De-prioritize built-in renderers diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 0e2f1fe9ea6..403a07a082f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -75,7 +75,7 @@ export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap; - extensionLocation: URI; - extensionId: ExtensionIdentifier; - messaging: RendererMessagingSpec; + readonly id: string; + readonly displayName: string; + readonly entrypoint: NotebookRendererEntrypoint; + readonly extensionLocation: URI; + readonly extensionId: ExtensionIdentifier; + readonly messaging: RendererMessagingSpec; readonly mimeTypes: readonly string[]; - readonly dependencies: readonly string[]; - readonly isBuiltin: boolean; matchesWithoutKernel(mimeType: string): NotebookRendererMatch; diff --git a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts index e22c7fd486f..72c2e6ebf3e 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts @@ -8,7 +8,7 @@ import { Iterable } from 'vs/base/common/iterator'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { INotebookRendererInfo, NotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookRendererInfo, ContributedNotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec, NotebookRendererEntrypoint } from 'vs/workbench/contrib/notebook/common/notebookCommon'; class DependencyList { private readonly value: ReadonlySet; @@ -19,10 +19,6 @@ class DependencyList { this.defined = this.value.size > 0; } - public values(): string[] { - return Array.from(this.value); - } - /** Gets whether any of the 'available' dependencies match the ones in this list */ public matches(available: ReadonlyArray) { // For now this is simple, but this may expand to support globs later @@ -34,17 +30,13 @@ class DependencyList { export class NotebookOutputRendererInfo implements INotebookRendererInfo { readonly id: string; - readonly extends?: string; - readonly entrypoint: URI; + readonly entrypoint: NotebookRendererEntrypoint; readonly displayName: string; readonly extensionLocation: URI; readonly extensionId: ExtensionIdentifier; readonly hardDependencies: DependencyList; readonly optionalDependencies: DependencyList; - /** @see RendererMessagingSpec */ readonly messaging: RendererMessagingSpec; - // todo: re-add preloads in pure renderer API - readonly preloads: ReadonlyArray = []; readonly mimeTypes: readonly string[]; private readonly mimeTypeGlobs: glob.ParsedPattern[]; @@ -54,7 +46,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { constructor(descriptor: { readonly id: string; readonly displayName: string; - readonly entrypoint: NotebookRendererEntrypoint; + readonly entrypoint: ContributedNotebookRendererEntrypoint; readonly mimeTypes: readonly string[]; readonly extension: IExtensionDescription; readonly dependencies: readonly string[] | undefined; @@ -67,10 +59,15 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.isBuiltin = descriptor.extension.isBuiltin; if (typeof descriptor.entrypoint === 'string') { - this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint); + this.entrypoint = { + extends: undefined, + path: joinPath(this.extensionLocation, descriptor.entrypoint) + }; } else { - this.extends = descriptor.entrypoint.extends; - this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint.path); + this.entrypoint = { + extends: descriptor.entrypoint.extends, + path: joinPath(this.extensionLocation, descriptor.entrypoint.path) + }; } this.displayName = descriptor.displayName; @@ -81,10 +78,6 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { this.messaging = descriptor.requiresMessaging ?? RendererMessagingSpec.Never; } - public get dependencies(): string[] { - return this.hardDependencies.values(); - } - public matchesWithoutKernel(mimeType: string) { if (!this.matchesMimeTypeOnly(mimeType)) { return NotebookRendererMatch.Never; @@ -118,7 +111,7 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { } private matchesMimeTypeOnly(mimeType: string) { - if (this.extends !== undefined) { + if (this.entrypoint.extends) { // We're extending another renderer return false; } From 5b7233c5e3977662532e77c96a3d0fcad1d25753 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 17:01:38 -0700 Subject: [PATCH 549/599] Use for-of loop instead (#163491) --- .../contrib/webview/browser/webviewElement.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 45e735a28ed..433b3789392 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -545,15 +545,17 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD parent.appendChild(this._webviewFindWidget.getDomNode()); } - [EventType.MOUSE_DOWN, EventType.MOUSE_MOVE, EventType.DROP].forEach(eventName => { + for (const eventName of [EventType.MOUSE_DOWN, EventType.MOUSE_MOVE, EventType.DROP]) { this._register(addDisposableListener(parent, eventName, () => { this.stopBlockingIframeDragEvents(); })); - }); + } - [parent, window].forEach(node => this._register(addDisposableListener(node as HTMLElement, EventType.DRAG_END, () => { - this.stopBlockingIframeDragEvents(); - }))); + for (const node of [parent, window]) { + this._register(addDisposableListener(node, EventType.DRAG_END, () => { + this.stopBlockingIframeDragEvents(); + })); + } parent.appendChild(this.element); } From a5e9b83d6550b3dd6ea749718597203b2e770585 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 12 Oct 2022 17:05:41 -0700 Subject: [PATCH 550/599] ci: fix wrong file in cli tests --- build/azure-pipelines/cli/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/azure-pipelines/cli/test.yml b/build/azure-pipelines/cli/test.yml index d17175e4758..70eb714c1d9 100644 --- a/build/azure-pipelines/cli/test.yml +++ b/build/azure-pipelines/cli/test.yml @@ -7,7 +7,7 @@ parameters: default: stable steps: - - template: ./install-rust.yml + - template: ./install-rust-posix.yml parameters: targets: [] channel: ${{ parameters.VSCODE_CLI_RUST_CHANNEL }} From 2457d9eb469d9fd56ed4ce1ce9887b4b0ef43730 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Wed, 12 Oct 2022 17:08:27 -0700 Subject: [PATCH 551/599] Plumbing for desktop to pick up strings from language packs (#163494) Web will come in the next PR (hence the TODO) Also this includes the smallest translation change which will be the ultimate test that this is all working. --- .../github-authentication/src/githubServer.ts | 2 +- .../languagePacks/browser/languagePacks.ts | 14 +++++++++++ .../languagePacks/common/languagePacks.ts | 4 ++++ .../languagePacks/node/languagePacks.ts | 14 +++++++++++ .../api/browser/mainThreadLocalization.ts | 11 +++++++++ .../workbench/api/common/extHost.protocol.ts | 1 + .../api/common/extHostLocalizationService.ts | 23 ++++++++++--------- 7 files changed, 57 insertions(+), 12 deletions(-) diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index 94ce5429e78..5c6bff905db 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -156,7 +156,7 @@ export class GitHubServer implements IGitHubServer { // Used for showing a friendlier message to the user when the explicitly cancel a flow. let userCancelled: boolean | undefined; - const yes = localize('yes', "Yes"); + const yes = vscode.l10n.t('Yes'); const no = localize('no', "No"); const promptToContinue = async () => { if (userCancelled === undefined) { diff --git a/src/vs/platform/languagePacks/browser/languagePacks.ts b/src/vs/platform/languagePacks/browser/languagePacks.ts index 83b4c051e0f..f7fdae65552 100644 --- a/src/vs/platform/languagePacks/browser/languagePacks.ts +++ b/src/vs/platform/languagePacks/browser/languagePacks.ts @@ -3,9 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { URI } from 'vs/base/common/uri'; import { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks'; export class WebLanguagePacksService extends LanguagePackBaseService { + // TODO: support builtin extensions using unpkg service + // constructor( + // @IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService, + // @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, + // @ILogService private readonly logService: ILogService + // ) { + // super(extensionGalleryService); + // } + + getTranslationsUri(id: string): Promise { + return Promise.resolve(undefined); + } + // Web doesn't have a concept of language packs, so we just return an empty array getInstalledLanguages(): Promise { return Promise.resolve([]); diff --git a/src/vs/platform/languagePacks/common/languagePacks.ts b/src/vs/platform/languagePacks/common/languagePacks.ts index d316ba89c3e..589e8678326 100644 --- a/src/vs/platform/languagePacks/common/languagePacks.ts +++ b/src/vs/platform/languagePacks/common/languagePacks.ts @@ -6,6 +6,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Disposable } from 'vs/base/common/lifecycle'; import { language } from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; import { IQuickPickItem } from 'vs/base/parts/quickinput/common/quickInput'; import { localize } from 'vs/nls'; import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -22,6 +23,7 @@ export interface ILanguagePackService { readonly _serviceBrand: undefined; getAvailableLanguages(): Promise>; getInstalledLanguages(): Promise>; + getTranslationsUri(id: string): Promise; getLocale(extension: IGalleryExtension): string | undefined; } @@ -32,6 +34,8 @@ export abstract class LanguagePackBaseService extends Disposable implements ILan super(); } + abstract getTranslationsUri(id: string): Promise; + abstract getInstalledLanguages(): Promise>; async getAvailableLanguages(): Promise { diff --git a/src/vs/platform/languagePacks/node/languagePacks.ts b/src/vs/platform/languagePacks/node/languagePacks.ts index defe0957b17..f2d2516c9bd 100644 --- a/src/vs/platform/languagePacks/node/languagePacks.ts +++ b/src/vs/platform/languagePacks/node/languagePacks.ts @@ -16,6 +16,8 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens import { ILogService } from 'vs/platform/log/common/log'; import { ILocalizationContribution } from 'vs/platform/extensions/common/extensions'; import { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks'; +import { locale } from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; interface ILanguagePack { hash: string; @@ -48,6 +50,18 @@ export class NativeLanguagePackService extends LanguagePackBaseService { }); } + async getTranslationsUri(id: string): Promise { + const packs = await this.cache.getLanguagePacks(); + const pack = packs[locale!]; + if (!pack) { + this.logService.warn(`No language pack found for ${locale}`); + return undefined; + } + + const translation = pack.translations[id]; + return translation ? URI.file(translation) : undefined; + } + async getInstalledLanguages(): Promise> { const languagePacks = await this.cache.getLanguagePacks(); const languages = Object.keys(languagePacks).map(locale => { diff --git a/src/vs/workbench/api/browser/mainThreadLocalization.ts b/src/vs/workbench/api/browser/mainThreadLocalization.ts index 988fb8ba6c3..c3cdd418461 100644 --- a/src/vs/workbench/api/browser/mainThreadLocalization.ts +++ b/src/vs/workbench/api/browser/mainThreadLocalization.ts @@ -8,6 +8,7 @@ import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/ext import { URI, UriComponents } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; @extHostNamedCustomer(MainContext.MainThreadLocalization) export class MainThreadLocalization extends Disposable implements MainThreadLocalizationShape { @@ -15,10 +16,20 @@ export class MainThreadLocalization extends Disposable implements MainThreadLoca constructor( extHostContext: IExtHostContext, @IFileService private readonly fileService: IFileService, + @ILanguagePackService private readonly languagePackService: ILanguagePackService ) { super(); } + async $fetchBuiltInBundleUri(id: string): Promise { + try { + const uri = await this.languagePackService.getTranslationsUri(id); + return uri; + } catch (e) { + return undefined; + } + } + async $fetchBundleContents(uriComponents: UriComponents): Promise { const contents = await this.fileService.readFile(URI.revive(uriComponents)); return contents.value.toString(); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 3bb8699d408..95ff686a02b 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2144,6 +2144,7 @@ export interface MainThreadThemingShape extends IDisposable { } export interface MainThreadLocalizationShape extends IDisposable { + $fetchBuiltInBundleUri(id: string): Promise; $fetchBundleContents(uriComponents: UriComponents): Promise; } diff --git a/src/vs/workbench/api/common/extHostLocalizationService.ts b/src/vs/workbench/api/common/extHostLocalizationService.ts index e2671689ca6..611add6ffce 100644 --- a/src/vs/workbench/api/common/extHostLocalizationService.ts +++ b/src/vs/workbench/api/common/extHostLocalizationService.ts @@ -60,7 +60,7 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { async initializeLocalizedMessages(extension: IExtensionDescription): Promise { if (this.isDefaultLanguage // TODO: support builtin extensions - || !extension.l10n + || (!extension.l10n && !extension.isBuiltin) ) { return; } @@ -70,16 +70,17 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { } let contents: { [key: string]: string } | undefined; - const bundleLocation = this.getBundleLocation(extension); - if (!bundleLocation) { + const bundleUri = await this.getBundleLocation(extension); + if (!bundleUri) { this.logService.error(`No bundle location found for extension ${extension.identifier.value}`); return; } - const bundleUri = URI.joinPath(bundleLocation, `bundle.l10n.${this.currentLanguage}.json`); try { const response = await this._proxy.$fetchBundleContents(bundleUri); - contents = JSON.parse(response); + const result = JSON.parse(response); + // 'contents.bundle' is a well-known key in the language pack json file that contains the _code_ translations for the extension + contents = extension.isBuiltin ? result.contents?.bundle : result; } catch (e) { this.logService.error(`Failed to load translations for ${extension.identifier.value} from ${bundleUri}: ${e.message}`); return; @@ -93,14 +94,14 @@ export class ExtHostLocalizationService implements ExtHostLocalizationShape { } } - private getBundleLocation(extension: IExtensionDescription): URI | undefined { - // TODO: support builtin extensions using IExtHostInitDataService - // if (extension.isBuiltin && this.initData.nlsBaseUrl) { - // return URI.joinPath(this.initData.nlsBaseUrl, extension.identifier.value, 'main'); - // } + private async getBundleLocation(extension: IExtensionDescription): Promise { + if (extension.isBuiltin) { + const uri = await this._proxy.$fetchBuiltInBundleUri(extension.identifier.value); + return URI.revive(uri); + } return extension.l10n - ? URI.joinPath(extension.extensionLocation, extension.l10n) + ? URI.joinPath(extension.extensionLocation, extension.l10n, `bundle.l10n.${this.currentLanguage}.json`) : undefined; } } From db9f5f9b9bdd06cc037607473513b59d85617082 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 17:12:14 -0700 Subject: [PATCH 552/599] Fix electron webviews not always updating `_webviewKeyboardHandler` when focus changes (#163495) I believe any focus changes should also update the `_webviewKeyboardHandler`. Right now programatic focuses don't --- .../contrib/webview/browser/webviewElement.ts | 18 ++++++++---------- .../electron-sandbox/webviewElement.ts | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 433b3789392..51b3d4db948 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -37,7 +37,7 @@ import { areWebviewContentOptionsEqual, IWebview, WebviewContentOptions, Webview import { WebviewFindDelegate, WebviewFindWidget } from 'vs/workbench/contrib/webview/browser/webviewFindWidget'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -export const enum WebviewMessageChannels { +const enum WebviewMessageChannels { onmessage = 'onmessage', didClickLink = 'did-click-link', didScroll = 'did-scroll', @@ -303,14 +303,14 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this.handleFocusChange(true); })); - this._register(this.on(WebviewMessageChannels.wheel, (event: IMouseWheelEvent) => { - this._onDidWheel.fire(event); - })); - this._register(this.on(WebviewMessageChannels.didBlur, () => { this.handleFocusChange(false); })); + this._register(this.on(WebviewMessageChannels.wheel, (event: IMouseWheelEvent) => { + this._onDidWheel.fire(event); + })); + this._register(this.on(WebviewMessageChannels.didFind, (didFind: boolean) => { this._hasFindResult.fire(didFind); })); @@ -379,7 +379,6 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD })); this._register(Event.runAndSubscribe(webviewThemeDataProvider.onThemeDataChanged, () => this.style())); - this._register(_accessibilityService.onDidChangeReducedMotion(() => this.style())); this._register(_accessibilityService.onDidChangeScreenReaderOptimized(() => this.style())); @@ -468,7 +467,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD return this._send('message', { message, transfer }); } - protected async _send(channel: string, data?: any, transferable: Transferable[] = []): Promise { + private async _send(channel: string, data?: any, transferable: Transferable[] = []): Promise { if (this._state.type === WebviewState.Type.Initializing) { let resolve: (x: boolean) => void; const promise = new Promise(r => resolve = r); @@ -525,7 +524,6 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD params.purpose = options.purpose; } - COI.addSearchParam(params, true, true); const queryString = new URLSearchParams(params).toString(); @@ -598,7 +596,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD return false; } - protected on(channel: WebviewMessageChannels, handler: (data: T, e: MessageEvent) => void): IDisposable { + private on(channel: WebviewMessageChannels, handler: (data: T, e: MessageEvent) => void): IDisposable { let handlers = this._messageHandlers.get(channel); if (!handlers) { handlers = new Set(); @@ -726,7 +724,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this._webviewFindWidget?.updateTheme(this.webviewThemeDataProvider.getTheme()); } - private handleFocusChange(isFocused: boolean): void { + protected handleFocusChange(isFocused: boolean): void { this._focused = isFocused; if (isFocused) { this._onDidFocus.fire(); diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts index c119358978c..bdc676cff07 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts @@ -23,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITunnelService } from 'vs/platform/tunnel/common/tunnel'; import { FindInFrameOptions, IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; -import { WebviewElement, WebviewInitInfo, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { WebviewElement, WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { WindowIgnoreMenuShortcutsManager } from 'vs/workbench/contrib/webview/electron-sandbox/windowIgnoreMenuShortcutsManager'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -68,14 +68,6 @@ export class ElectronWebviewElement extends WebviewElement { this._webviewMainService = ProxyChannel.toService(mainProcessService.getChannel('webview')); - this._register(this.on(WebviewMessageChannels.didFocus, () => { - this._webviewKeyboardHandler.didFocus(); - })); - - this._register(this.on(WebviewMessageChannels.didBlur, () => { - this._webviewKeyboardHandler.didBlur(); - })); - if (initInfo.options.enableFindWidget) { this._register(this.onDidHtmlChange((newContent) => { if (this._findStarted && this._cachedHtmlContent !== newContent) { @@ -167,4 +159,13 @@ export class ElectronWebviewElement extends WebviewElement { }); this._onDidStopFind.fire(); } + + protected override handleFocusChange(isFocused: boolean): void { + super.handleFocusChange(isFocused); + if (isFocused) { + this._webviewKeyboardHandler.didFocus(); + } else { + this._webviewKeyboardHandler.didBlur(); + } + } } From a8108049ab61b970f2ec1839dfb753054e07395e Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Wed, 12 Oct 2022 17:28:34 -0700 Subject: [PATCH 553/599] Allow extensions to use new API and it get included in Language Packs (#163493) * Allow extensions to use new API and it get included in Language Packs This leverages the l10n-dev package to analyze ts files for `l10n.t` calls. * delete console.logs --- build/lib/i18n.js | 38 +++++++++++++++--- build/lib/i18n.ts | 46 ++++++++++++++++++---- build/npm/update-localization-extension.js | 2 +- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 2d407ad6f1f..30c75e7c1c3 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; +exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.XLF = exports.Line = exports.extraLanguages = exports.defaultLanguages = void 0; const path = require("path"); const fs = require("fs"); const event_stream_1 = require("event-stream"); @@ -37,7 +37,7 @@ exports.extraLanguages = [ { id: 'tr', folderName: 'trk' } ]; // non built-in extensions also that are transifex and need to be part of the language packs -exports.externalExtensionsWithTranslations = { +const externalExtensionsWithTranslations = { 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', 'vscode-node-debug': 'ms-vscode.node-debug', 'vscode-node-debug2': 'ms-vscode.node-debug2' @@ -508,6 +508,28 @@ function createXlfFilesForCoreBundle() { }); } exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; +function createL10nBundleForExtension(extensionName) { + const result = (0, event_stream_1.through)(); + gulp.src([ + `extensions/${extensionName}/src/**/*.ts`, + ]).pipe((0, event_stream_1.writeArray)((err, files) => { + if (err) { + result.emit('error', err); + return; + } + const json = (0, l10n_dev_1.getL10nJson)(files.map(file => { + return file.contents.toString('utf8'); + })); + if (Object.keys(json)) { + result.emit('data', new File({ + path: `${extensionName}/bundle.l10n.json`, + contents: Buffer.from(JSON.stringify(json), 'utf8') + })); + } + result.emit('end'); + })); + return result; +} function createXlfFilesForExtensions() { let counter = 0; let folderStreamEnded = false; @@ -530,7 +552,7 @@ function createXlfFilesForExtensions() { } return _l10nMap; } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe((0, event_stream_1.through)(function (file) { + (0, event_stream_1.merge)(gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }), createL10nBundleForExtension(extensionName)).pipe((0, event_stream_1.through)(function (file) { if (file.isBuffer()) { const buffer = file.contents; const basename = path.basename(file.path); @@ -554,6 +576,10 @@ function createXlfFilesForExtensions() { getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } } + else if (basename === 'bundle.l10n.json') { + const json = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/bundle`, json); + } else { this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); return; @@ -664,7 +690,7 @@ function getRecordFromL10nJsonFormat(l10nJsonFormat) { } return record; } -function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths) { +function prepareI18nPackFiles(resultingTranslationPaths) { const parsePromises = []; const mainPack = { version: i18nPackVersion, contents: {} }; const extensionsPacks = {}; @@ -685,7 +711,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths) { if (!extPack) { extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; } - const externalId = externalExtensions[resource]; + const externalId = externalExtensionsWithTranslations[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); @@ -713,7 +739,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths) { for (const extension in extensionsPacks) { const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; + const externalExtensionId = externalExtensionsWithTranslations[extension]; if (externalExtensionId) { resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); } diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 0045bb64fcf..f5510eda4d7 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as fs from 'fs'; -import { through, ThroughStream } from 'event-stream'; +import { merge, through, ThroughStream, writeArray } from 'event-stream'; import * as File from 'vinyl'; import * as Is from 'is'; import * as xml2js from 'xml2js'; @@ -14,7 +14,7 @@ import * as gulp from 'gulp'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as iconv from '@vscode/iconv-lite-umd'; -import { l10nJsonFormat, getL10nXlf, l10nJsonDetails, getL10nFilesFromXlf } from '@vscode/l10n-dev'; +import { l10nJsonFormat, getL10nXlf, l10nJsonDetails, getL10nFilesFromXlf, getL10nJson } from '@vscode/l10n-dev'; function log(message: any, ...rest: any[]): void { fancyLog(ansiColors.green('[i18n]'), message, ...rest); @@ -50,7 +50,7 @@ export const extraLanguages: Language[] = [ ]; // non built-in extensions also that are transifex and need to be part of the language packs -export const externalExtensionsWithTranslations = { +const externalExtensionsWithTranslations: Record = { 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', 'vscode-node-debug': 'ms-vscode.node-debug', 'vscode-node-debug2': 'ms-vscode.node-debug2' @@ -586,6 +586,32 @@ export function createXlfFilesForCoreBundle(): ThroughStream { }); } +function createL10nBundleForExtension(extensionName: string): ThroughStream { + const result = through(); + gulp.src([ + `extensions/${extensionName}/src/**/*.ts`, + ]).pipe(writeArray((err, files: File[]) => { + if (err) { + result.emit('error', err); + return; + } + + const json = getL10nJson(files.map(file => { + return file.contents.toString('utf8'); + })); + + if (Object.keys(json)) { + result.emit('data', new File({ + path: `${extensionName}/bundle.l10n.json`, + contents: Buffer.from(JSON.stringify(json), 'utf8') + })); + } + result.emit('end'); + })); + + return result; +} + export function createXlfFilesForExtensions(): ThroughStream { let counter: number = 0; let folderStreamEnded: boolean = false; @@ -608,7 +634,10 @@ export function createXlfFilesForExtensions(): ThroughStream { } return _l10nMap; } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { + merge( + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }), + createL10nBundleForExtension(extensionName) + ).pipe(through(function (file: File) { if (file.isBuffer()) { const buffer: Buffer = file.contents as Buffer; const basename = path.basename(file.path); @@ -631,6 +660,9 @@ export function createXlfFilesForExtensions(): ThroughStream { } getL10nMap().set(`extensions/${extensionName}/${relPath}/${file}`, info); } + } else if (basename === 'bundle.l10n.json') { + const json: l10nJsonFormat = JSON.parse(buffer.toString('utf8')); + getL10nMap().set(`extensions/${extensionName}/bundle`, json); } else { this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); return; @@ -762,7 +794,7 @@ function getRecordFromL10nJsonFormat(l10nJsonFormat: l10nJsonFormat): Record, resultingTranslationPaths: TranslationPath[]): NodeJS.ReadWriteStream { +export function prepareI18nPackFiles(resultingTranslationPaths: TranslationPath[]): NodeJS.ReadWriteStream { const parsePromises: Promise[] = []; const mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; const extensionsPacks: Record = {}; @@ -785,7 +817,7 @@ export function prepareI18nPackFiles(externalExtensions: Record, if (!extPack) { extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; } - const externalId = externalExtensions[resource]; + const externalId = externalExtensionsWithTranslations[resource]; if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent const secondSlash = path.indexOf('/', firstSlash + 1); extPack.contents[path.substring(secondSlash + 1)] = getRecordFromL10nJsonFormat(file.messages); @@ -814,7 +846,7 @@ export function prepareI18nPackFiles(externalExtensions: Record, const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; + const externalExtensionId = externalExtensionsWithTranslations[extension]; if (externalExtensionId) { resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); } else { diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js index 9876882a6c4..b78674a7099 100644 --- a/build/npm/update-localization-extension.js +++ b/build/npm/update-localization-extension.js @@ -68,7 +68,7 @@ function update(options) { console.log(`Importing translations for ${languageId} form '${location}' to '${translationDataFolder}' ...`); let translationPaths = []; gulp.src(path.join(location, '**', languageId, '*.xlf'), { silent: false }) - .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths)) + .pipe(i18n.prepareI18nPackFiles(translationPaths)) .on('error', (error) => { console.log(`Error occurred while importing translations:`); translationPaths = undefined; From 8991187c38c6a12505321c1d582f03acc2e2c7f2 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 12 Oct 2022 22:39:57 -0700 Subject: [PATCH 554/599] cli: apply lint fixes --- cli/src/desktop/version_manager.rs | 2 +- cli/src/util/command.rs | 2 +- cli/src/util/sync.rs | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cli/src/desktop/version_manager.rs b/cli/src/desktop/version_manager.rs index 7dc32bf7ded..03e37f0d4ad 100644 --- a/cli/src/desktop/version_manager.rs +++ b/cli/src/desktop/version_manager.rs @@ -418,7 +418,7 @@ mod tests { .to_string_lossy() .to_string(); assert_eq!( - RequestedVersion::try_from((&exe).as_str()).unwrap(), + RequestedVersion::try_from(exe.as_str()).unwrap(), RequestedVersion::Path(exe), ); } diff --git a/cli/src/util/command.rs b/cli/src/util/command.rs index 25b2116268b..7a7795e1590 100644 --- a/cli/src/util/command.rs +++ b/cli/src/util/command.rs @@ -26,7 +26,7 @@ where e, format!( "failed to execute command '{}'", - (&command_str).as_ref().to_string_lossy() + command_str.as_ref().to_string_lossy() ), ) }) diff --git a/cli/src/util/sync.rs b/cli/src/util/sync.rs index 6e069215e74..5f33419488a 100644 --- a/cli/src/util/sync.rs +++ b/cli/src/util/sync.rs @@ -19,9 +19,7 @@ where /// Waits for the barrier to be closed, returning a value if one was sent. pub async fn wait(&mut self) -> Result { loop { - if let Err(e) = self.0.changed().await { - return Err(e); - } + self.0.changed().await?; if let Some(v) = *(self.0.borrow()) { return Ok(v); From 65270235646614cd51f2152ea15da576ba83a1c3 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 13 Oct 2022 18:02:35 +1100 Subject: [PATCH 555/599] Additional test for handling stream outputs in notebooks (#163502) * Additional test for nb stream output handling * test --- .../api/test/browser/extHostNotebook.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/vs/workbench/api/test/browser/extHostNotebook.test.ts b/src/vs/workbench/api/test/browser/extHostNotebook.test.ts index 60f453ec1f3..0a9c0def137 100644 --- a/src/vs/workbench/api/test/browser/extHostNotebook.test.ts +++ b/src/vs/workbench/api/test/browser/extHostNotebook.test.ts @@ -605,6 +605,24 @@ suite('NotebookCell#Document', function () { assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout'); assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'foobarbaz'); }); + test('Compress multiple stdout stream output items (with support for terminal escape code -> \u001b[A)', async function () { + await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('\nfoo') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`${String.fromCharCode(27)}[Abar`) }]); + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar'); + }); + test('Compress multiple stdout stream output items (with support for terminal escape code -> \r character)', async function () { + await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString('foo') }]); + await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stdout', valueBytes: VSBuffer.fromString(`\rbar`) }]); + + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items.length, 1); + assert.strictEqual(notebook.apiNotebook.cellAt(1).outputs[0].items[0].mime, 'application/vnd.code.notebook.stdout'); + assert.strictEqual(VSBuffer.wrap(notebook.apiNotebook.cellAt(1).outputs[0].items[0].data).toString(), 'bar'); + }); test('Compress multiple stderr stream output items', async function () { await replaceOutputs(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('foo') }]); await appendOutputItem(1, '1', [{ mime: 'application/vnd.code.notebook.stderr', valueBytes: VSBuffer.fromString('bar') }]); From a78f7af399ba21dee48e7b7c9fb6141fed6aca4b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 13 Oct 2022 12:19:27 +0200 Subject: [PATCH 556/599] Adresses #159178 (#163535) --- .../contrib/audioCues/browser/audioCues.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 4519b93f7e0..dc4693613a8 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { registerAction2 } from 'vs/platform/actions/common/actions'; import { Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { AudioCueLineDebuggerContribution } from 'vs/workbench/contrib/audioCues/browser/audioCueDebuggerContribution'; @@ -15,7 +15,7 @@ import { AudioCueService, IAudioCueService } from 'vs/workbench/contrib/audioCue import { ShowAudioCueHelp } from 'vs/workbench/contrib/audioCues/browser/commands'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -registerSingleton(IAudioCueService, AudioCueService, false); +registerSingleton(IAudioCueService, AudioCueService, InstantiationType.Delayed); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineFeatureContribution, LifecyclePhase.Restored); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineDebuggerContribution, LifecyclePhase.Restored); From 894aa9a7a789bdb66e5b5c2154097ea2d9533a24 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 13 Oct 2022 12:48:52 +0200 Subject: [PATCH 557/599] Log improvements (#163532) * - expose log level in the proposed api - ability to set log level per logger * fix tests --- extensions/vscode-api-tests/package.json | 3 +- .../sharedProcess/sharedProcessMain.ts | 6 +- src/vs/code/electron-main/app.ts | 2 +- src/vs/code/electron-main/main.ts | 6 +- src/vs/platform/log/common/fileLog.ts | 6 +- src/vs/platform/log/common/log.ts | 90 +++++++++++++++---- src/vs/platform/log/common/logIpc.ts | 19 ++-- src/vs/platform/log/node/loggerService.ts | 15 +--- .../test/common/telemetryLogAppender.test.ts | 6 ++ src/vs/platform/terminal/node/ptyHostMain.ts | 13 ++- src/vs/server/node/serverServices.ts | 17 ++-- .../api/browser/mainThreadLogService.ts | 26 ++++-- .../workbench/api/common/extHost.api.impl.ts | 13 ++- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLoggerService.ts | 18 ++-- src/vs/workbench/api/common/extHostOutput.ts | 31 +++++-- src/vs/workbench/browser/web.main.ts | 15 ++-- .../contrib/logs/browser/logs.contribution.ts | 4 + .../contrib/logs/common/logConstants.ts | 4 +- .../contrib/logs/common/logLevelService.ts | 55 ++++++++++++ .../contrib/logs/common/logsActions.ts | 58 ++++++++++-- .../logs/electron-sandbox/logLevelService.ts | 50 +++++++++++ .../electron-sandbox/logs.contribution.ts | 5 ++ .../remote/common/remote.contribution.ts | 12 +-- .../browser/webWorkerExtensionHost.ts | 4 +- .../services/extensions/common/extensions.ts | 3 + .../extensions/common/remoteExtensionHost.ts | 4 +- .../localProcessExtensionHost.ts | 4 +- src/vs/workbench/workbench.web.main.ts | 4 +- .../vscode.proposed.extensionLog.d.ts | 35 ++++++++ 30 files changed, 421 insertions(+), 109 deletions(-) create mode 100644 src/vs/workbench/contrib/logs/common/logLevelService.ts create mode 100644 src/vs/workbench/contrib/logs/electron-sandbox/logLevelService.ts diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 36b444e2301..b38c61cd6d2 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -33,7 +33,7 @@ "taskPresentationGroup", "terminalDataWriteEvent", "terminalDimensions", - "tunnels", + "tunnels", "envShellEvent", "testCoverage", "testObserver", @@ -44,6 +44,7 @@ "treeViewReveal", "workspaceTrust", "telemetry", + "extensionLog", "localization" ], "private": true, diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 5d99003793a..973fa4beb0c 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -49,7 +49,7 @@ import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; import { ConsoleLogger, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; -import { FollowerLogService, LoggerChannelClient, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +import { FollowerLogService, LoggerChannelClient, LogLevelChannel, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -368,6 +368,10 @@ class SharedProcessMain extends Disposable { private initChannels(accessor: ServicesAccessor): void { + // Log Level + const logLevelChannel = new LogLevelChannel(accessor.get(ILogService), accessor.get(ILoggerService)); + this.server.registerChannel('logLevel', logLevelChannel); + // Extensions Management const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null); this.server.registerChannel('extensions', channel); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index ff67487cd1c..b8e21690c1e 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -816,7 +816,7 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel); // Log Level (main & shared process) - const logLevelChannel = new LogLevelChannel(accessor.get(ILogService)); + const logLevelChannel = new LogLevelChannel(accessor.get(ILogService), accessor.get(ILoggerService)); mainProcessElectronServer.registerChannel('logLevel', logLevelChannel); sharedProcessClient.then(client => client.registerChannel('logLevel', logLevelChannel)); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index e358efbb545..ca1cdec6ac2 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -47,7 +47,6 @@ import { ILifecycleMainService, LifecycleMainService } from 'vs/platform/lifecyc import { BufferLogService } from 'vs/platform/log/common/bufferLog'; import { ConsoleMainLogger, getLogLevel, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; import { LoggerService } from 'vs/platform/log/node/loggerService'; -import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol'; @@ -117,6 +116,7 @@ class CodeMain { const logService = accessor.get(ILogService); const lifecycleMainService = accessor.get(ILifecycleMainService); const fileService = accessor.get(IFileService); + const loggerService = accessor.get(ILoggerService); // Create the main IPC server by trying to be the server // If this throws an error it means we are not the first @@ -129,7 +129,7 @@ class CodeMain { }); // Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906) - bufferLogService.logger = new SpdLogLogger('main', join(environmentMainService.logsPath, 'main.log'), true, false, bufferLogService.getLevel()); + bufferLogService.logger = loggerService.createLogger(URI.file(join(environmentMainService.logsPath, 'main.log')), { name: 'main' }); // Lifecycle once(lifecycleMainService.onWillShutdown)(evt => { @@ -177,7 +177,7 @@ class CodeMain { services.set(IUriIdentityService, uriIdentityService); // Logger - services.set(ILoggerService, new LoggerService(logService, fileService)); + services.set(ILoggerService, new LoggerService(logService)); // State const stateMainService = new StateMainService(environmentMainService, logService, fileService); diff --git a/src/vs/platform/log/common/fileLog.ts b/src/vs/platform/log/common/fileLog.ts index dbb5c57cc98..4e346d74d0f 100644 --- a/src/vs/platform/log/common/fileLog.ts +++ b/src/vs/platform/log/common/fileLog.ts @@ -8,7 +8,6 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { basename, dirname, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ByteSize, FileOperationError, FileOperationResult, IFileService, whenProviderRegistered } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { BufferLogService } from 'vs/platform/log/common/bufferLog'; import { AbstractLogger, AbstractLoggerService, format, ILogger, ILoggerOptions, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -146,15 +145,14 @@ export class FileLoggerService extends AbstractLoggerService implements ILoggerS constructor( @ILogService logService: ILogService, - @IInstantiationService private readonly instantiationService: IInstantiationService, @IFileService private readonly fileService: IFileService, ) { - super(logService.getLevel(), logService.onDidChangeLogLevel); + super(logService.getLevel(), logService.onDidChangeLogLevel, []); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { const logger = new BufferLogService(logLevel); - whenProviderRegistered(resource, this.fileService).then(() => (logger).logger = this.instantiationService.createInstance(FileLogger, options?.name || basename(resource), resource, logger.getLevel(), !!options?.donotUseFormatters)); + whenProviderRegistered(resource, this.fileService).then(() => (logger).logger = new FileLogger(options?.name || basename(resource), resource, logger.getLevel(), !!options?.donotUseFormatters, this.fileService)); return logger; } } diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 88cc084a202..8a6d33c5c4a 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -6,6 +6,7 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ResourceMap } from 'vs/base/common/map'; import { isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -111,12 +112,28 @@ export interface ILoggerService { /** * Creates a logger, or gets one if it already exists. */ - createLogger(file: URI, options?: ILoggerOptions): ILogger; + createLogger(resource: URI, options?: ILoggerOptions): ILogger; /** * Gets an existing logger, if any. */ - getLogger(file: URI): ILogger | undefined; + getLogger(resource: URI): ILogger | undefined; + + /** + * Set log level for a logger. + */ + setLevel(resource: URI, level: LogLevel | undefined): void; + + /** + * Get log level for a logger. + */ + getLogLevel(resource: URI): LogLevel | undefined; + + /** + * Get default log level for a logger with given name. + * @param name logger name + */ + getDefaultLogLevel(name: string): LogLevel; } export abstract class AbstractLogger extends Disposable { @@ -504,44 +521,79 @@ export class LogService extends Disposable implements ILogService { } } +interface ILoggerItem { + readonly logger: ILogger; + logLevel: LogLevel | undefined; +} + export abstract class AbstractLoggerService extends Disposable implements ILoggerService { declare readonly _serviceBrand: undefined; - private readonly loggers = new Map(); - private readonly logLevelChangeableLoggers: ILogger[] = []; + private readonly loggerItems = new ResourceMap(); constructor( private logLevel: LogLevel, onDidChangeLogLevel: Event, + private readonly defaultLogLevels: [string, LogLevel][] ) { super(); - this._register(onDidChangeLogLevel(logLevel => { - this.logLevel = logLevel; - this.logLevelChangeableLoggers.forEach(logger => logger.setLevel(logLevel)); - })); + this._register(onDidChangeLogLevel(logLevel => this.setLevel(logLevel))); } - getLogger(resource: URI) { - return this.loggers.get(resource.toString()); + getLoggers(): ILogger[] { + return [...this.loggerItems.values()].map(({ logger }) => logger); + } + + getLogger(resource: URI): ILogger | undefined { + return this.loggerItems.get(resource)?.logger; } createLogger(resource: URI, options?: ILoggerOptions): ILogger { - let logger = this.loggers.get(resource.toString()); + let logger = this.loggerItems.get(resource)?.logger; if (!logger) { - logger = this.doCreateLogger(resource, options?.always ? LogLevel.Trace : this.logLevel, options); - this.loggers.set(resource.toString(), logger); - if (!options?.always) { - this.logLevelChangeableLoggers.push(logger); - } + const logLevel = options?.always ? LogLevel.Trace : undefined; + logger = this.doCreateLogger(resource, logLevel ?? (options?.name ? this.getDefaultLogLevel(options?.name) : this.logLevel), options); + this.loggerItems.set(resource, { logger, logLevel }); } return logger; } + setLevel(logLevel: LogLevel): void; + setLevel(resource: URI, logLevel: LogLevel): void; + setLevel(arg1: any, arg2?: any): void { + const resource = URI.isUri(arg1) ? arg1 : undefined; + const logLevel = resource ? arg2 : arg1; + + if (resource) { + const logger = this.loggerItems.get(resource); + if (logger && logger.logLevel !== logLevel) { + logger.logLevel = logLevel; + logger.logger.setLevel(logLevel); + } + } else { + this.logLevel = logLevel; + this.loggerItems.forEach(({ logLevel, logger }) => { + if (logLevel === undefined) { + logger.setLevel(this.logLevel); + } + }); + } + + } + + getLogLevel(resource: URI): LogLevel | undefined { + const logger = this.loggerItems.get(resource); + return logger?.logLevel; + } + + getDefaultLogLevel(name: string): LogLevel { + return this.defaultLogLevels.find(([loggerName]) => loggerName === name)?.[1] ?? this.logLevel; + } + override dispose(): void { - this.logLevelChangeableLoggers.splice(0, this.logLevelChangeableLoggers.length); - this.loggers.forEach(logger => logger.dispose()); - this.loggers.clear(); + this.loggerItems.forEach(({ logger }) => logger.dispose()); + this.loggerItems.clear(); super.dispose(); } diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index 8783df9cbb7..a5ef50d8493 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -12,8 +12,11 @@ export class LogLevelChannel implements IServerChannel { onDidChangeLogLevel: Event; - constructor(private service: ILogService) { - this.onDidChangeLogLevel = Event.buffer(service.onDidChangeLogLevel, true); + constructor( + private readonly logService: ILogService, + private readonly loggerService: ILoggerService + ) { + this.onDidChangeLogLevel = Event.buffer(logService.onDidChangeLogLevel, true); } listen(_: unknown, event: string): Event { @@ -26,7 +29,7 @@ export class LogLevelChannel implements IServerChannel { async call(_: unknown, command: string, arg?: any): Promise { switch (command) { - case 'setLevel': return this.service.setLevel(arg); + case 'setLevel': return arg[1] ? this.loggerService.setLevel(URI.revive(arg[1]), arg[0]) : this.logService.setLevel(arg[0]); } throw new Error(`Call not found: ${command}`); @@ -42,12 +45,12 @@ export class LogLevelChannelClient { return this.channel.listen('onDidChangeLogLevel'); } - setLevel(level: LogLevel): void { - LogLevelChannelClient.setLevel(this.channel, level); + setLevel(level: LogLevel, resource?: URI): void { + LogLevelChannelClient.setLevel(this.channel, level, resource); } - public static setLevel(channel: IChannel, level: LogLevel): Promise { - return channel.call('setLevel', level); + public static setLevel(channel: IChannel, level: LogLevel, resource?: URI): Promise { + return channel.call('setLevel', [level, resource]); } } @@ -108,7 +111,7 @@ export class LoggerChannel implements IServerChannel { export class LoggerChannelClient extends AbstractLoggerService implements ILoggerService { constructor(logLevel: LogLevel, onDidChangeLogLevel: Event, private readonly channel: IChannel) { - super(logLevel, onDidChangeLogLevel); + super(logLevel, onDidChangeLogLevel, []); } createConsoleMainLogger(): ILogger { diff --git a/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts index 8ad7ad94f48..a7cc23f9e86 100644 --- a/src/vs/platform/log/node/loggerService.ts +++ b/src/vs/platform/log/node/loggerService.ts @@ -3,30 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Schemas } from 'vs/base/common/network'; -import { basename } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; -import { IFileService } from 'vs/platform/files/common/files'; -import { FileLogger } from 'vs/platform/log/common/fileLog'; import { AbstractLoggerService, ILogger, ILoggerOptions, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; export class LoggerService extends AbstractLoggerService implements ILoggerService { constructor( - @ILogService logService: ILogService, - @IFileService private readonly fileService: IFileService + @ILogService logService: ILogService ) { - super(logService.getLevel(), logService.onDidChangeLogLevel); + super(logService.getLevel(), logService.onDidChangeLogLevel, []); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { - if (resource.scheme === Schemas.file) { - return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel); - } else { - return new FileLogger(options?.name ?? basename(resource), resource, logLevel, !!options?.donotUseFormatters, this.fileService); - } + return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel); } } diff --git a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts index c43b0e06b7c..e39dd7c0576 100644 --- a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts +++ b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { Event } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { AbstractLogger, DEFAULT_LOG_LEVEL, ILogger, ILoggerService, LogLevel } from 'vs/platform/log/common/log'; @@ -75,6 +76,11 @@ class TestTelemetryLoggerService implements ILoggerService { return this.logger; } + + onDidChangeLogLevel = Event.None; + setLevel(): void { } + getLogLevel() { return undefined; } + getDefaultLogLevel() { return this.logLevel; } } suite('TelemetryLogAdapter', () => { diff --git a/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts index a1fa938db10..da8071c9084 100644 --- a/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -4,13 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { join } from 'vs/base/common/path'; +import { URI } from 'vs/base/common/uri'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { ConsoleLogger, getLogLevel, LogService, MultiplexLogService } from 'vs/platform/log/common/log'; +import { BufferLogService } from 'vs/platform/log/common/bufferLog'; +import { ConsoleLogger, LogService, MultiplexLogService } from 'vs/platform/log/common/log'; import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; -import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; +import { LoggerService } from 'vs/platform/log/node/loggerService'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { IReconnectConstants, TerminalIpcChannels, TerminalLogConstants } from 'vs/platform/terminal/common/terminal'; @@ -25,11 +27,14 @@ delete process.env.VSCODE_LAST_PTY_ID; // Logging const productService: IProductService = { _serviceBrand: undefined, ...product }; const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService); +const bufferLogService = new BufferLogService(); const logService = new LogService(new MultiplexLogService([ new ConsoleLogger(), - new SpdLogLogger(TerminalLogConstants.FileName, join(environmentService.logsPath, `${TerminalLogConstants.FileName}.log`), true, false, getLogLevel(environmentService)) + bufferLogService ])); -const logLevelChannel = new LogLevelChannel(logService); +const loggerService = new LoggerService(logService); +bufferLogService.logger = loggerService.createLogger(URI.file(join(environmentService.logsPath, `${TerminalLogConstants.FileName}.log`)), { name: TerminalLogConstants.FileName }); +const logLevelChannel = new LogLevelChannel(logService, loggerService); server.registerChannel(TerminalIpcChannels.Log, logLevelChannel); const heartbeatService = new HeartbeatService(); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 0dc354e378b..c2517797d58 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -37,9 +37,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; -import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILogService, LogLevel, LogService, MultiplexLogService } from 'vs/platform/log/common/log'; +import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILogService, LogLevel, MultiplexLogService } from 'vs/platform/log/common/log'; import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; -import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; @@ -73,6 +72,9 @@ import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } fro import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { NullPolicyService } from 'vs/platform/policy/common/policy'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; +import { LoggerService } from 'vs/platform/log/node/loggerService'; +import { URI } from 'vs/base/common/uri'; +import { BufferLogService } from 'vs/platform/log/common/bufferLog'; const eventPrefix = 'monacoworkbench'; @@ -87,15 +89,18 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(IEnvironmentService, environmentService); services.set(INativeEnvironmentService, environmentService); - const spdLogService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, false, getLogLevel(environmentService))); - const logService = new MultiplexLogService([new ServerLogService(getLogLevel(environmentService)), spdLogService]); + const bufferLogService = new BufferLogService(); + const logService = new MultiplexLogService([new ServerLogService(getLogLevel(environmentService)), bufferLogService]); services.set(ILogService, logService); setTimeout(() => cleanupOlderLogs(environmentService.logsPath).then(null, err => logService.error(err)), 10000); + const loggerService = new LoggerService(logService); + bufferLogService.logger = loggerService.createLogger(URI.file(path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`)), { name: RemoteExtensionLogFileName }); + logService.trace(`Remote configuration data at ${REMOTE_DATA_FOLDER}`); logService.trace('process arguments:', environmentService.args); if (Array.isArray(productService.serverGreeting)) { - spdLogService.info(`\n\n${productService.serverGreeting.join('\n')}\n\n`); + logService.info(`\n\n${productService.serverGreeting.join('\n')}\n\n`); } // ExtensionHost Debug broadcast service @@ -103,7 +108,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken // TODO: @Sandy @Joao need dynamic context based router const router = new StaticRouter(ctx => ctx.clientId === 'renderer'); - socketServer.registerChannel('logger', new LogLevelChannel(logService)); + socketServer.registerChannel('logger', new LogLevelChannel(logService, loggerService)); // Files const fileService = disposables.add(new FileService(logService)); diff --git a/src/vs/workbench/api/browser/mainThreadLogService.ts b/src/vs/workbench/api/browser/mainThreadLogService.ts index d48722ba5cf..3d350071c5f 100644 --- a/src/vs/workbench/api/browser/mainThreadLogService.ts +++ b/src/vs/workbench/api/browser/mainThreadLogService.ts @@ -5,29 +5,41 @@ import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { ILoggerOptions, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainThreadLoggerShape, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { UriComponents, URI } from 'vs/base/common/uri'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ILogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; +import { IOutputService } from 'vs/workbench/services/output/common/output'; +import { localExtHostLog, remoteExtHostLog, webWorkerExtHostLog } from 'vs/workbench/services/extensions/common/extensions'; @extHostNamedCustomer(MainContext.MainThreadLogger) export class MainThreadLoggerService implements MainThreadLoggerShape { - private readonly _logListener: IDisposable; + private readonly disposables = new DisposableStore(); constructor( extHostContext: IExtHostContext, @ILogService logService: ILogService, - @ILoggerService private readonly _loggerService: ILoggerService, + @ILoggerService private readonly loggerService: ILoggerService, + @ILogLevelService extensionLoggerService: ILogLevelService, + @IOutputService outputService: IOutputService, ) { const proxy = extHostContext.getProxy(ExtHostContext.ExtHostLogLevelServiceShape); - this._logListener = logService.onDidChangeLogLevel(level => proxy.$setLevel(level)); + this.disposables.add(logService.onDidChangeLogLevel(level => proxy.$setLevel(level))); + this.disposables.add(extensionLoggerService.onDidChangeLogLevel(({ id, logLevel }) => { + const channel = outputService.getChannelDescriptor(id); + const resource = channel?.log ? channel.file : undefined; + if (resource && (channel?.extensionId || id === localExtHostLog || id === remoteExtHostLog || id === webWorkerExtHostLog)) { + proxy.$setLevel(logLevel, resource); + } + })); } $log(file: UriComponents, messages: [LogLevel, string][]): void { - const logger = this._loggerService.getLogger(URI.revive(file)); + const logger = this.loggerService.getLogger(URI.revive(file)); if (!logger) { throw new Error('Create the logger before logging'); } @@ -37,11 +49,11 @@ export class MainThreadLoggerService implements MainThreadLoggerShape { } async $createLogger(file: UriComponents, options?: ILoggerOptions): Promise { - this._loggerService.createLogger(URI.revive(file), options); + this.loggerService.createLogger(URI.revive(file), options); } dispose(): void { - this._logListener.dispose(); + this.disposables.dispose(); } } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index d11207c6384..22e084f52e1 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -59,7 +59,7 @@ import { IExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations' import { IExtHostTask } from 'vs/workbench/api/common/extHostTask'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; -import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; @@ -364,6 +364,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, get uiKind() { return initData.uiKind; + }, + get logLevel() { + checkProposedApiEnabled(extension, 'extensionLog'); + return extHostLogService.getLevel(); + }, + get onDidChangeLogLevel() { + checkProposedApiEnabled(extension, 'extensionLog'); + return extHostLogService.onDidChangeLogLevel; } }; if (!initData.environment.extensionTestsLocationURI) { @@ -1383,7 +1391,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I TabInputWebview: extHostTypes.WebviewEditorTabInput, TabInputTerminal: extHostTypes.TerminalEditorTabInput, TabInputInteractiveWindow: extHostTypes.InteractiveWindowInput, - TerminalExitReason: extHostTypes.TerminalExitReason + TerminalExitReason: extHostTypes.TerminalExitReason, + LogLevel: LogLevel, }; }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 95ff686a02b..adb51a10a0f 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1944,7 +1944,7 @@ export interface ExtHostWindowShape { } export interface ExtHostLogLevelServiceShape { - $setLevel(level: LogLevel): void; + $setLevel(level: LogLevel, resource?: UriComponents): void; } export interface MainThreadLoggerShape { diff --git a/src/vs/workbench/api/common/extHostLoggerService.ts b/src/vs/workbench/api/common/extHostLoggerService.ts index 6501df99bf0..b994b3cf890 100644 --- a/src/vs/workbench/api/common/extHostLoggerService.ts +++ b/src/vs/workbench/api/common/extHostLoggerService.ts @@ -7,27 +7,29 @@ import { ILogger, ILoggerOptions, AbstractMessageLogger, LogLevel, AbstractLogge import { MainThreadLoggerShape, MainContext, ExtHostLogLevelServiceShape as ExtHostLogLevelServiceShape } from 'vs/workbench/api/common/extHost.protocol'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -import { URI } from 'vs/base/common/uri'; -import { Emitter } from 'vs/base/common/event'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { Event } from 'vs/base/common/event'; +import { isUndefined } from 'vs/base/common/types'; export class ExtHostLoggerService extends AbstractLoggerService implements ExtHostLogLevelServiceShape { declare readonly _serviceBrand: undefined; - private readonly _onDidChangeLogLevel: Emitter; private readonly _proxy: MainThreadLoggerShape; constructor( @IExtHostRpcService rpc: IExtHostRpcService, @IExtHostInitDataService initData: IExtHostInitDataService, ) { - const emitter = new Emitter(); - super(initData.logLevel, emitter.event); + super(initData.logLevel, Event.None, []); this._proxy = rpc.getProxy(MainContext.MainThreadLogger); - this._onDidChangeLogLevel = this._register(emitter); } - $setLevel(level: LogLevel): void { - this._onDidChangeLogLevel.fire(level); + $setLevel(level: LogLevel, resource?: UriComponents): void { + if (resource) { + this.setLevel(URI.revive(resource), level); + } else if (!isUndefined(level)) { + this.setLevel(level); + } } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 09741ef4a3c..ac01aeb7bce 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { AbstractMessageLogger, ILogger, ILoggerService, log, LogLevel } from 'vs/platform/log/common/log'; +import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log'; import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output'; import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; @@ -18,6 +18,9 @@ import { toLocalISOString } from 'vs/base/common/date'; import { VSBuffer } from 'vs/base/common/buffer'; import { isString } from 'vs/base/common/types'; import { FileSystemProviderErrorCode, toFileSystemProviderErrorCode } from 'vs/platform/files/common/files'; +import { Emitter } from 'vs/base/common/event'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOutputChannel { @@ -38,6 +41,10 @@ class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOu this._register(logger.onDidChangeLogLevel(level => this.setLevel(level))); } + get logLevel(): LogLevel { + return this.logger.getLevel(); + } + appendLine(value: string): void { this.append(value + '\n'); } @@ -118,6 +125,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { @IExtHostConsumerFileSystem private readonly extHostFileSystem: IExtHostConsumerFileSystem, @IExtHostFileSystemInfo private readonly extHostFileSystemInfo: IExtHostFileSystemInfo, @ILoggerService private readonly loggerService: ILoggerService, + @ILogService private readonly logService: ILogService, ) { this.proxy = extHostRpc.getProxy(MainContext.MainThreadOutputService); this.outputsLocation = this.extHostFileSystemInfo.extUri.joinPath(initData.logsLocation, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); @@ -136,6 +144,9 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { throw new Error('illegal argument `name`. must not be falsy'); } const log = typeof options === 'object' && options.log; + if (log) { + checkProposedApiEnabled(extension, 'extensionLog'); + } const languageId = isString(options) ? options : undefined; if (isString(languageId) && !languageId.trim()) { throw new Error('illegal argument `languageId`. must not be empty'); @@ -226,14 +237,25 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { } private createExtHostLogOutputChannel(name: string, channelPromise: Promise): vscode.LogOutputChannel { - let disposed = false; + const disposables = new DisposableStore(); const validate = () => { - if (disposed) { + if (disposables.isDisposed) { throw new Error('Channel has been closed'); } }; + let logLevel = this.logService.getLevel(); + const onDidChangeLogLevel = disposables.add(new Emitter()); + channelPromise.then(channel => { + disposables.add(channel); + disposables.add(channel.onDidChangeLogLevel(e => { + logLevel = e; + onDidChangeLogLevel.fire(e); + })); + }); return { ...this.createExtHostOutputChannel(name, channelPromise), + get logLevel() { return logLevel; }, + onDidChangeLogLevel: onDidChangeLogLevel.event, trace(value: string, ...args: any[]): void { validate(); channelPromise.then(channel => channel.trace(value, ...args)); @@ -255,8 +277,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { channelPromise.then(channel => channel.error(value, ...args)); }, dispose(): void { - disposed = true; - channelPromise.then(channel => channel.dispose()); + disposables.dispose(); } }; } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 11806254df3..e4e95239bba 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -6,7 +6,7 @@ import { mark } from 'vs/base/common/performance'; import { domContentLoaded, detectFullscreen, getCookieValue } from 'vs/base/browser/dom'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILogService, ConsoleLogger, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log'; +import { ILogService, ConsoleLogger, MultiplexLogService, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; import { ConsoleLogInAutomationLogger } from 'vs/platform/log/browser/log'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { BrowserWorkbenchEnvironmentService, IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -35,7 +35,7 @@ import { IWorkbenchConstructionOptions, IWorkbench, ITunnel } from 'vs/workbench import { BrowserStorageService } from 'vs/workbench/services/storage/browser/storageService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { FileLogger } from 'vs/platform/log/common/fileLog'; +import { FileLoggerService } from 'vs/platform/log/common/fileLog'; import { toLocalISOString } from 'vs/base/common/date'; import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/window/common/window'; import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; @@ -268,7 +268,12 @@ export class BrowserMain extends Disposable { // Files const fileService = this._register(new FileService(logService)); serviceCollection.set(IWorkbenchFileService, fileService); - await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, logService, logsPath); + + // Logger + const loggerService = new FileLoggerService(logService, fileService); + serviceCollection.set(ILoggerService, loggerService); + + await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, logService, loggerService, logsPath); // URI Identity const uriIdentityService = new UriIdentityService(fileService); @@ -374,7 +379,7 @@ export class BrowserMain extends Disposable { return { serviceCollection, configurationService, logService }; } - private async registerFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IWorkbenchFileService, remoteAgentService: IRemoteAgentService, logService: BufferLogService, logsPath: URI): Promise { + private async registerFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IWorkbenchFileService, remoteAgentService: IRemoteAgentService, logService: BufferLogService, loggerService: ILoggerService, logsPath: URI): Promise { // IndexedDB is used for logging and user data let indexedDB: IndexedDB | undefined; @@ -401,7 +406,7 @@ export class BrowserMain extends Disposable { logService.logger = new MultiplexLogService(coalesce([ new ConsoleLogger(logService.getLevel()), - new FileLogger('window', environmentService.logFile, logService.getLevel(), false, fileService), + loggerService.createLogger(environmentService.logFile, { name: 'window' }), // Extension development test CLI: forward everything to test runner environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI ? new ConsoleLogInAutomationLogger(logService.getLevel()) : undefined ])); diff --git a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts index 23f019bac51..b42615bdd09 100644 --- a/src/vs/workbench/contrib/logs/browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/browser/logs.contribution.ts @@ -12,6 +12,10 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { LogsDataCleaner } from 'vs/workbench/contrib/logs/common/logsDataCleaner'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILogLevelService, LogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; + +registerSingleton(ILogLevelService, LogLevelService, InstantiationType.Delayed); class WebLogOutputChannels extends Disposable implements IWorkbenchContribution { diff --git a/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts index 0224f0d95e2..a9869d06fc7 100644 --- a/src/vs/workbench/contrib/logs/common/logConstants.ts +++ b/src/vs/workbench/contrib/logs/common/logConstants.ts @@ -6,10 +6,12 @@ export const mainLogChannelId = 'mainLog'; export const sharedLogChannelId = 'sharedLog'; export const rendererLogChannelId = 'rendererLog'; -export const extHostLogChannelId = 'extHostLog'; export const telemetryLogChannelId = 'telemetryLog'; export const extensionTelemetryLogChannelId = 'extensionTelemetryLog'; export const userDataSyncLogChannelId = 'userDataSyncLog'; export const editSessionsLogChannelId = 'editSessionsSyncLog'; +export const remoteServerLog = 'remoteServerLog'; +export const remotePtyHostLog = 'remotePtyHostLog'; + export const showWindowLogActionId = 'workbench.action.showWindowLog'; diff --git a/src/vs/workbench/contrib/logs/common/logLevelService.ts b/src/vs/workbench/contrib/logs/common/logLevelService.ts new file mode 100644 index 00000000000..51e60fc9e0d --- /dev/null +++ b/src/vs/workbench/contrib/logs/common/logLevelService.ts @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILoggerService, LogLevel } from 'vs/platform/log/common/log'; +import { Emitter, Event } from 'vs/base/common/event'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IOutputService } from 'vs/workbench/services/output/common/output'; + +export const ILogLevelService = createDecorator('ILogLevelService'); +export interface ILogLevelService { + readonly _serviceBrand: undefined; + readonly onDidChangeLogLevel: Event<{ readonly id: string; logLevel: LogLevel }>; + setLogLevel(id: string, logLevel: LogLevel): void; + getLogLevel(id: string): LogLevel | undefined; +} + +export class LogLevelService extends Disposable implements ILogLevelService { + readonly _serviceBrand: undefined; + + private readonly _onDidChangeLogLevel = this._register(new Emitter<{ readonly id: string; logLevel: LogLevel }>()); + readonly onDidChangeLogLevel = this._onDidChangeLogLevel.event; + + private readonly logLevels = new Map(); + + constructor( + @IOutputService protected readonly outputService: IOutputService, + @ILoggerService private readonly loggerService: ILoggerService + ) { + super(); + } + + getLogLevel(id: string): LogLevel | undefined { + return this.logLevels.get(id); + } + + setLogLevel(id: string, logLevel: LogLevel): boolean { + if (this.getLogLevel(id) === logLevel) { + return false; + } + + this.logLevels.set(id, logLevel); + const channel = this.outputService.getChannelDescriptor(id); + const resource = channel?.log ? channel.file : undefined; + if (resource) { + this.loggerService.setLevel(resource, logLevel); + } + this._onDidChangeLogLevel.fire({ id, logLevel }); + return true; + } + +} + diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index b5b49b6c12b..3d4ee6058e2 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -6,12 +6,16 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log'; -import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IOutputService } from 'vs/workbench/services/output/common/output'; +import { isUndefined } from 'vs/base/common/types'; +import { ILogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; +import { extensionTelemetryLogChannelId, telemetryLogChannelId } from 'vs/workbench/contrib/logs/common/logConstants'; export class SetLogLevelAction extends Action { @@ -20,13 +24,50 @@ export class SetLogLevelAction extends Action { constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @ILogLevelService private readonly logLevelService: ILogLevelService, + @IOutputService private readonly outputService: IOutputService ) { super(id, label); } - override run(): Promise { - const current = this.logService.getLevel(); + override async run(): Promise { + const logger = await this.selectLogger(); + if (!isUndefined(logger)) { + await this.selectLogLevel(logger); + } + } + + private async selectLogger(): Promise { + const extensionLogs = [], logs = []; + for (const channel of this.outputService.getChannelDescriptors()) { + if (!channel.log || channel.id === telemetryLogChannelId || channel.id === extensionTelemetryLogChannelId) { + continue; + } + if (channel.extensionId) { + extensionLogs.push(channel); + } else { + logs.push(channel); + } + } + const entries: ({ id?: string; label: string } | IQuickPickSeparator)[] = []; + entries.push({ label: nls.localize('all', "All") }); + entries.push({ type: 'separator', label: nls.localize('loggers', "Logs") }); + for (const { id, label } of logs.sort((a, b) => a.label.localeCompare(b.label))) { + entries.push({ id, label }); + } + if (extensionLogs.length && logs.length) { + entries.push({ type: 'separator', label: nls.localize('extensionLogs', "Extension Logs") }); + } + for (const { id, label } of extensionLogs.sort((a, b) => a.label.localeCompare(b.label))) { + entries.push({ id, label }); + } + const entry = await this.quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") }); + return entry ? entry.id ?? null : undefined; + } + + private async selectLogLevel(logger: string | null): Promise { + const current = (logger ? this.logLevelService.getLogLevel(logger) : undefined) ?? this.logService.getLevel(); const entries = [ { label: nls.localize('trace', "Trace"), level: LogLevel.Trace, description: this.getDescription(LogLevel.Trace, current) }, { label: nls.localize('debug', "Debug"), level: LogLevel.Debug, description: this.getDescription(LogLevel.Debug, current) }, @@ -37,11 +78,14 @@ export class SetLogLevelAction extends Action { { label: nls.localize('off', "Off"), level: LogLevel.Off, description: this.getDescription(LogLevel.Off, current) }, ]; - return this.quickInputService.pick(entries, { placeHolder: nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.logService.getLevel()] }).then(entry => { - if (entry) { + const entry = await this.quickInputService.pick(entries, { placeHolder: logger ? nls.localize('selectLogLevelFor', " {0}: Select log level", this.outputService.getChannelDescriptor(logger)?.label) : nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.logService.getLevel()] }); + if (entry) { + if (logger) { + this.logLevelService.setLogLevel(logger, entry.level); + } else { this.logService.setLevel(entry.level); } - }); + } } private getDescription(level: LogLevel, current: LogLevel): string | undefined { diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logLevelService.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logLevelService.ts new file mode 100644 index 00000000000..de269ec1db2 --- /dev/null +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logLevelService.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILoggerService, LogLevel } from 'vs/platform/log/common/log'; +import { IOutputService } from 'vs/workbench/services/output/common/output'; +import { IMainProcessService, ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; +import { LogLevelService as CommonLogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; +import { remotePtyHostLog, remoteServerLog, sharedLogChannelId, userDataSyncLogChannelId } from 'vs/workbench/contrib/logs/common/logConstants'; +import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; + +export class LogLevelService extends CommonLogLevelService { + + constructor( + @IOutputService outputService: IOutputService, + @ILoggerService loggerService: ILoggerService, + @ISharedProcessService private readonly sharedProcessService: ISharedProcessService, + @IMainProcessService private readonly mainProcessService: IMainProcessService, + @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService, + ) { + super(outputService, loggerService); + } + + override setLogLevel(id: string, logLevel: LogLevel): boolean { + if (!super.setLogLevel(id, logLevel)) { + return false; + } + + const channel = this.outputService.getChannelDescriptor(id); + const resource = channel?.log ? channel.file : undefined; + + LogLevelChannelClient.setLevel(this.mainProcessService.getChannel('logLevel'), logLevel, resource); + if (id === sharedLogChannelId || id === userDataSyncLogChannelId) { + LogLevelChannelClient.setLevel(this.sharedProcessService.getChannel('logLevel'), logLevel, resource); + return true; + } + + const connection = this.remoteAgentService.getConnection(); + if ((id === remoteServerLog || id === remotePtyHostLog) && connection) { + connection.withChannel('logger', (channel) => LogLevelChannelClient.setLevel(channel, logLevel, resource)); + return true; + } + + return true; + } + +} + diff --git a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts index 5066dfcfe34..57f5dadd802 100644 --- a/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts @@ -20,6 +20,11 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { registerLogChannel } from 'vs/workbench/services/output/common/output'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; +import { LogLevelService } from 'vs/workbench/contrib/logs/electron-sandbox/logLevelService'; + +registerSingleton(ILogLevelService, LogLevelService, InstantiationType.Delayed); class NativeLogOutputChannels extends Disposable implements IWorkbenchContribution { diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index a65fefa0da1..d95a33548dc 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -10,7 +10,7 @@ import { ILabelService, ResourceLabelFormatting } from 'vs/platform/label/common import { OperatingSystem, isWeb, OS } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { LogLevelChannel, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/services/output/common/output'; import { localize } from 'vs/nls'; @@ -33,6 +33,7 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; import { timeout } from 'vs/base/common/async'; import { TerminalLogConstants } from 'vs/platform/terminal/common/terminal'; +import { remotePtyHostLog, remoteServerLog } from 'vs/workbench/contrib/logs/common/logConstants'; export class LabelContribution implements IWorkbenchContribution { constructor( @@ -71,7 +72,8 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib constructor( @ILogService logService: ILogService, @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @IDownloadService downloadService: IDownloadService + @IDownloadService downloadService: IDownloadService, + @ILoggerService loggerService: ILoggerService, ) { super(); const updateRemoteLogLevel = () => { @@ -86,7 +88,7 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib const connection = remoteAgentService.getConnection(); if (connection) { connection.registerChannel('download', new DownloadServiceChannel(downloadService)); - connection.registerChannel('logger', new LogLevelChannel(logService)); + connection.registerChannel('logger', new LogLevelChannel(logService, loggerService)); } } } @@ -99,8 +101,8 @@ class RemoteLogOutputChannels implements IWorkbenchContribution { remoteAgentService.getEnvironment().then(remoteEnv => { if (remoteEnv) { const outputChannelRegistry = Registry.as(OutputExt.OutputChannels); - outputChannelRegistry.registerChannel({ id: 'remoteExtensionLog', label: localize('remoteExtensionLog', "Remote Server"), file: joinPath(remoteEnv.logsPath, `${RemoteExtensionLogFileName}.log`), log: true }); - outputChannelRegistry.registerChannel({ id: 'remotePtyHostLog', label: localize('remotePtyHostLog', "Remote Pty Host"), file: joinPath(remoteEnv.logsPath, `${TerminalLogConstants.FileName}.log`), log: true }); + outputChannelRegistry.registerChannel({ id: remoteServerLog, label: localize('remoteExtensionLog', "Remote Server"), file: joinPath(remoteEnv.logsPath, `${RemoteExtensionLogFileName}.log`), log: true }); + outputChannelRegistry.registerChannel({ id: remotePtyHostLog, label: localize('remotePtyHostLog', "Remote Pty Host"), file: joinPath(remoteEnv.logsPath, `${TerminalLogConstants.FileName}.log`), log: true }); } }); } diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 0b6d5e5e3d1..e0f225e9490 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -16,7 +16,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio import * as platform from 'vs/base/common/platform'; import * as dom from 'vs/base/browser/dom'; import { URI } from 'vs/base/common/uri'; -import { IExtensionHost, ExtensionHostLogFileName, LocalWebWorkerRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionHost, ExtensionHostLogFileName, LocalWebWorkerRunningLocation, ExtensionHostExtensions, webWorkerExtHostLog } from 'vs/workbench/services/extensions/common/extensions'; import { IProductService } from 'vs/platform/product/common/productService'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { joinPath } from 'vs/base/common/resources'; @@ -251,7 +251,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost } // Register log channel for web worker exthost log - Registry.as(Extensions.OutputChannels).registerChannel({ id: 'webWorkerExtHostLog', label: localize('name', "Worker Extension Host"), file: this._extensionHostLogFile, log: true }); + Registry.as(Extensions.OutputChannels).registerChannel({ id: webWorkerExtHostLog, label: localize('name', "Worker Extension Host"), file: this._extensionHostLogFile, log: true }); return protocol; } diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 269ad124f08..2bcb79c3e67 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -404,6 +404,9 @@ export class ExtensionPointContribution { } export const ExtensionHostLogFileName = 'exthost'; +export const localExtHostLog = 'extHostLog'; +export const remoteExtHostLog = 'remoteExtHostLog'; +export const webWorkerExtHostLog = 'webWorkerExtHostLog'; export interface IWillActivateEvent { readonly event: string; diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index ae69e5945ea..5105a62c15e 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -27,7 +27,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; import { createMessageOfType, isMessageOfType, MessageType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; -import { ExtensionHostExtensions, ExtensionHostLogFileName, IExtensionHost, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionHostExtensions, ExtensionHostLogFileName, IExtensionHost, remoteExtHostLog, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; import { Extensions, IOutputChannelRegistry } from 'vs/workbench/services/output/common/output'; export interface IRemoteExtensionHostInitData { @@ -171,7 +171,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { disposable.dispose(); // Register log channel for remote exthost log - Registry.as(Extensions.OutputChannels).registerChannel({ id: 'remoteExtHostLog', label: localize('remote extension host Log', "Remote Extension Host"), file: logFile, log: true }); + Registry.as(Extensions.OutputChannels).registerChannel({ id: remoteExtHostLog, label: localize('remote extension host Log', "Remote Extension Host"), file: logFile, log: true }); // release this promise this._protocol = protocol; diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index b5df3055356..c69beb282c9 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -28,7 +28,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio import { parseExtensionDevOptions } from '../common/extensionDevOptions'; import { VSBuffer } from 'vs/base/common/buffer'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; -import { IExtensionHost, ExtensionHostLogFileName, LocalProcessRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionHost, ExtensionHostLogFileName, LocalProcessRunningLocation, ExtensionHostExtensions, localExtHostLog } from 'vs/workbench/services/extensions/common/extensions'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { joinPath } from 'vs/base/common/resources'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -417,7 +417,7 @@ export class SandboxLocalProcessExtensionHost implements IExtensionHost { disposable.dispose(); // Register log channel for exthost log - Registry.as(Extensions.OutputChannels).registerChannel({ id: 'extHostLog', label: nls.localize('extension host Log', "Extension Host"), file: this._extensionHostLogFile, log: true }); + Registry.as(Extensions.OutputChannels).registerChannel({ id: localExtHostLog, label: nls.localize('extension host Log', "Extension Host"), file: this._extensionHostLogFile, log: true }); // release this promise resolve(); diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index c1dee216d10..1462d032fe5 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -73,8 +73,7 @@ import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/ex import { ExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService'; import { IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; -import { ILoggerService, LogLevel } from 'vs/platform/log/common/log'; -import { FileLoggerService } from 'vs/platform/log/common/fileLog'; +import { LogLevel } from 'vs/platform/log/common/log'; import { UserDataSyncMachinesService, IUserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataAutoSyncService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; @@ -95,7 +94,6 @@ import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/langu registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed); registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed); registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed); -registerSingleton(ILoggerService, FileLoggerService, InstantiationType.Delayed); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed); registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed); registerSingleton(IUserDataSyncBackupStoreService, UserDataSyncBackupStoreService, InstantiationType.Delayed); diff --git a/src/vscode-dts/vscode.proposed.extensionLog.d.ts b/src/vscode-dts/vscode.proposed.extensionLog.d.ts index e575defff20..12d7689ec57 100644 --- a/src/vscode-dts/vscode.proposed.extensionLog.d.ts +++ b/src/vscode-dts/vscode.proposed.extensionLog.d.ts @@ -5,10 +5,45 @@ declare module 'vscode' { + export enum LogLevel { + Trace = 0, + Debug = 1, + Info = 2, + Warning = 3, + Error = 4, + Critical = 5, + Off = 6 + } + + export namespace env { + + /** + * The current log level of the application. + */ + export const logLevel: LogLevel; + + /** + * An {@link Event} which fires when the log level of the application changes. + */ + export const onDidChangeLogLevel: Event; + + } + /** * A channel for containing log output. */ export interface LogOutputChannel extends OutputChannel { + + /** + * The current log level of the channel. + */ + readonly logLevel: LogLevel; + + /** + * An {@link Event} which fires when the log level of the channel changes. + */ + readonly onDidChangeLogLevel: Event; + /** * Log the given trace message to the channel. * From 1e9295c90899eb7c54c9f44f05e664200a60d371 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 13 Oct 2022 14:56:33 +0200 Subject: [PATCH 558/599] Fix #163313 (#163542) --- .../services/configuration/browser/configurationService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index ea97c694c87..025115b840b 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -562,7 +562,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat if (!this.localUserConfiguration.hasTasksLoaded) { // Reload local user configuration again to load user tasks - this._register(runWhenIdle(() => this.reloadLocalUserConfiguration(), 5000)); + this._register(runWhenIdle(() => this.reloadLocalUserConfiguration())); } } From 17c7a089622017e35d9b062f3c0e1b896ed80311 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 13 Oct 2022 15:02:42 +0200 Subject: [PATCH 559/599] Add cli & command to run the code server on the desktop (#163546) Add cli & command to run the code server on the desktop --- build/lib/i18n.resources.json | 4 + package.json | 2 +- product.json | 1 + src/vs/base/common/product.ts | 4 +- .../sharedProcess/sharedProcessMain.ts | 30 +- src/vs/code/node/cli.ts | 34 +- src/vs/platform/environment/common/argv.ts | 12 + src/vs/platform/environment/node/argv.ts | 128 ++++-- .../platform/environment/node/argvHelper.ts | 40 +- .../environment/test/node/argv.test.ts | 94 ++++- .../sharedProcessLifecycleService.ts | 76 ++++ .../remoteTunnel/common/remoteTunnel.ts | 33 ++ .../electron-browser/remoteTunnelService.ts | 199 +++++++++ .../electron-sandbox/remoteTunnelService.ts | 9 + src/vs/server/node/server.cli.ts | 2 +- .../server/node/serverEnvironmentService.ts | 2 +- .../remoteTunnel.contribution.ts | 382 ++++++++++++++++++ src/vs/workbench/workbench.desktop.main.ts | 4 + 18 files changed, 997 insertions(+), 59 deletions(-) create mode 100644 src/vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService.ts create mode 100644 src/vs/platform/remoteTunnel/common/remoteTunnel.ts create mode 100644 src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts create mode 100644 src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts create mode 100644 src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index dd949e618f2..5b51df074b5 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -306,6 +306,10 @@ "name": "vs/workbench/contrib/offline", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/remoteTunnel", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/actions", "project": "vscode-workbench" diff --git a/package.json b/package.json index a4676dc092f..6a5bbde783b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.73.0", - "distro": "33ffc394a05e9cb3e9ac1fe2a72ab75610cf0d7e", + "distro": "cac14b226f101a8186316eb3dc74f1de73c0a5be", "author": { "name": "Microsoft Corporation" }, diff --git a/product.json b/product.json index 6e124afcf90..c76943372f1 100644 --- a/product.json +++ b/product.json @@ -11,6 +11,7 @@ "serverLicensePrompt": "", "serverApplicationName": "code-server-oss", "serverDataFolderName": ".vscode-server-oss", + "tunnelApplicationName": "code-tunnel-oss", "win32DirName": "Microsoft Code OSS", "win32NameVersion": "Microsoft Code OSS", "win32RegValueName": "CodeOSS", diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index e07695c9363..c7c8587b9da 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -130,6 +130,9 @@ export interface IProductConfiguration { readonly serverApplicationName: string; readonly serverDataFolderName?: string; + readonly tunnelApplicationName?: string; + readonly tunnelApplicationConfig?: { authenticationProviders: IStringDictionary<{ scopes: string[] }> }; + readonly npsSurveyUrl?: string; readonly cesSurveyUrl?: string; readonly surveys?: readonly ISurveyData[]; @@ -155,7 +158,6 @@ export interface IProductConfiguration { readonly 'configurationSync.store'?: ConfigurationSyncStore; readonly 'editSessions.store'?: Omit; - readonly darwinUniversalAssetId?: string; // experimental diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 973fa4beb0c..091c36d4f28 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -108,6 +108,9 @@ import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/elect import { SharedProcessRequestService } from 'vs/platform/request/electron-browser/sharedProcessRequestService'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { UserDataProfilesCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner'; +import { RemoteTunnelService } from 'vs/platform/remoteTunnel/electron-browser/remoteTunnelService'; +import { IRemoteTunnelService } from 'vs/platform/remoteTunnel/common/remoteTunnel'; +import { ISharedProcessLifecycleService, SharedProcessLifecycleService } from 'vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService'; class SharedProcessMain extends Disposable { @@ -115,6 +118,8 @@ class SharedProcessMain extends Disposable { private sharedProcessWorkerService: ISharedProcessWorkerService | undefined = undefined; + private lifecycleService: SharedProcessLifecycleService | undefined = undefined;; + constructor(private configuration: ISharedProcessConfiguration) { super(); @@ -124,7 +129,14 @@ class SharedProcessMain extends Disposable { private registerListeners(): void { // Shared process lifecycle - const onExit = () => this.dispose(); + const onExit = async () => { + if (this.lifecycleService) { + await this.lifecycleService.fireOnWillShutdown(); + this.lifecycleService.dispose(); + this.lifecycleService = undefined; + } + this.dispose(); + }; process.once('exit', onExit); ipcRenderer.once('vscode:electron-main->shared-process=exit', onExit); @@ -180,6 +192,8 @@ class SharedProcessMain extends Disposable { private async initServices(): Promise { const services = new ServiceCollection(); + // Lifecycle + // Product const productService = { _serviceBrand: undefined, ...product }; services.set(IProductService, productService); @@ -211,6 +225,10 @@ class SharedProcessMain extends Disposable { const logService = this._register(new FollowerLogService(logLevelClient, multiplexLogger)); services.set(ILogService, logService); + // Lifecycle + this.lifecycleService = new SharedProcessLifecycleService(logService); + services.set(ISharedProcessLifecycleService, this.lifecycleService); + // Worker this.sharedProcessWorkerService = new SharedProcessWorkerService(logService); services.set(ISharedProcessWorkerService, this.sharedProcessWorkerService); @@ -342,6 +360,8 @@ class SharedProcessMain extends Disposable { services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService, undefined, false /* Initializes the Sync State */)); services.set(IUserDataSyncProfilesStorageService, new SyncDescriptor(UserDataSyncProfilesStorageService, undefined, true)); + // Terminal + const ptyHostService = new PtyHostService({ graceTime: LocalReconnectConstants.GraceTime, shortGraceTime: LocalReconnectConstants.ShortGraceTime, @@ -353,7 +373,6 @@ class SharedProcessMain extends Disposable { ); ptyHostService.initialize(); - // Terminal services.set(ILocalPtyService, this._register(ptyHostService)); // Signing @@ -363,6 +382,9 @@ class SharedProcessMain extends Disposable { services.set(ISharedTunnelsService, new SyncDescriptor(SharedTunnelsService)); services.set(ISharedProcessTunnelService, new SyncDescriptor(SharedProcessTunnelService)); + // Remote Tunnel + services.set(IRemoteTunnelService, new SyncDescriptor(RemoteTunnelService)); + return new InstantiationService(services); } @@ -430,6 +452,10 @@ class SharedProcessMain extends Disposable { const sharedProcessWorkerChannel = ProxyChannel.fromService(accessor.get(ISharedProcessWorkerService)); this.server.registerChannel(ipcSharedProcessWorkerChannelName, sharedProcessWorkerChannel); + // Remote Tunnel + const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService)); + this.server.registerChannel('remoteTunnel', remoteTunnelChannel); + } private registerErrorHandler(logService: ILogService): void { diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index e427bd7c6fb..297b2cf012e 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -8,7 +8,7 @@ import { chmodSync, existsSync, readFileSync, statSync, truncateSync, unlinkSync import { homedir, release, tmpdir } from 'os'; import type { ProfilingSession, Target } from 'v8-inspect-profiler'; import { Event } from 'vs/base/common/event'; -import { isAbsolute, resolve, join } from 'vs/base/common/path'; +import { isAbsolute, resolve, join, dirname } from 'vs/base/common/path'; import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform'; import { randomPort } from 'vs/base/common/ports'; import { isString } from 'vs/base/common/types'; @@ -24,7 +24,6 @@ import product from 'vs/platform/product/common/product'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { randomPath } from 'vs/base/common/extpath'; import { Utils } from 'vs/platform/profiling/common/profiling'; -import { dirname } from 'vs/base/common/resources'; import { FileAccess } from 'vs/base/common/network'; function shouldSpawnCliProcess(argv: NativeParsedArgs): boolean { @@ -50,6 +49,31 @@ export async function main(argv: string[]): Promise { return; } + if (args.tunnel) { + if (!product.tunnelApplicationName) { + console.error(`'tunnel' command not supported in ${product.applicationName}`); + return; + } + return new Promise((resolve, reject) => { + let tunnelProcess; + if (process.env['VSCODE_DEV']) { + tunnelProcess = spawn('cargo', ['run', '--bin', 'code-tunnel', ...argv.slice(5)], { cwd: join(getAppRoot(), 'cli') }); + } else { + const tunnelCommand = join(dirname(process.execPath), 'bin', `${product.tunnelApplicationName}${isWindows ? '.exe' : ''}`); + const tunnelArgs = argv.slice(3); + tunnelProcess = spawn(tunnelCommand, tunnelArgs); + } + tunnelProcess.stdout.on('data', data => { + console.log(data.toString()); + }); + tunnelProcess.stderr.on('data', data => { + console.error(data.toString()); + }); + tunnelProcess.on('exit', resolve); + tunnelProcess.on('error', reject); + }); + } + // Help if (args.help) { const executable = `${product.applicationName}${isWindows ? '.exe' : ''}`; @@ -75,7 +99,7 @@ export async function main(argv: string[]): Promise { case 'fish': file = 'shellIntegration.fish'; break; default: throw new Error('Error using --locate-shell-integration-path: Invalid shell type'); } - console.log(join(dirname(FileAccess.asFileUri('', require)).fsPath, 'out', 'vs', 'workbench', 'contrib', 'terminal', 'browser', 'media', file)); + console.log(join(getAppRoot(), 'out', 'vs', 'workbench', 'contrib', 'terminal', 'browser', 'media', file)); } // Extensions Management @@ -467,6 +491,10 @@ export async function main(argv: string[]): Promise { } } +function getAppRoot() { + return dirname(FileAccess.asFileUri('', require).fsPath); +} + function eventuallyExit(code: number): void { setTimeout(() => process.exit(code), 0); } diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index b72a87576f6..9d6f717b64e 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -7,6 +7,18 @@ * A list of command line arguments we support natively. */ export interface NativeParsedArgs { + // subcommands + tunnel?: { + 'cli-data-dir'?: string; + 'disable-telemetry'?: boolean; + 'telemetry-level'?: string; + user: { + login: { + 'access-token'?: string; + 'provider'?: string; + }; + }; + }; _: string[]; 'folder-uri'?: string[]; // undefined or array of 1 or more 'file-uri'?: string[]; // undefined or array of 1 or more diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 15be1bcf6f6..0e5502fb67a 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -26,20 +26,47 @@ export interface Option { deprecationMessage?: string; allowEmptyValue?: boolean; cat?: keyof typeof helpCategories; + global?: boolean; +} + +export interface Subcommand { + type: 'subcommand'; + description?: string; + deprecationMessage?: string; + options: OptionDescriptions>; } export type OptionDescriptions = { - [P in keyof T]: Option>; + [P in keyof T]: + T[P] extends boolean ? Option<'boolean'> : + T[P] extends string ? Option<'string'> : + T[P] extends string[] ? Option<'string[]'> : + Subcommand }; -type OptionTypeName = - T extends boolean ? 'boolean' : - T extends string ? 'string' : - T extends string[] ? 'string[]' : - T extends undefined ? 'undefined' : - 'unknown'; - export const OPTIONS: OptionDescriptions> = { + 'tunnel': { + type: 'subcommand', + description: 'Make the current machine accessible from vscode.dev or other machines through a secure tunnel', + options: { + 'cli-data-dir': { type: 'string', args: 'dir', description: localize('cliDataDir', "Directory where CLI metadata should be stored.") }, + 'disable-telemetry': { type: 'boolean' }, + 'telemetry-level': { type: 'string' }, + user: { + type: 'subcommand', + options: { + login: { + type: 'subcommand', + options: { + provider: { type: 'string' }, + 'access-token': { type: 'string' } + } + } + } + } + } + }, + 'diff': { type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], description: localize('diff', "Compare two files with each other.") }, 'merge': { type: 'boolean', cat: 'o', alias: 'm', args: ['path1', 'path2', 'base', 'result'], description: localize('merge', "Perform a three-way merge by providing paths for two modified versions of a file, the common origin of both modified versions and the output file to save merge results.") }, 'add': { type: 'boolean', cat: 'o', alias: 'a', args: 'folder', description: localize('add', "Add folder(s) to the last active window.") }, @@ -65,8 +92,8 @@ export const OPTIONS: OptionDescriptions> = { 'enable-proposed-api': { type: 'string[]', allowEmptyValue: true, cat: 'e', args: 'ext-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, 'version': { type: 'boolean', cat: 't', alias: 'v', description: localize('version', "Print version.") }, - 'verbose': { type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, - 'log': { type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, + 'verbose': { type: 'boolean', cat: 't', global: true, description: localize('verbose', "Print verbose output (implies --wait).") }, + 'log': { type: 'string', cat: 't', args: 'level', global: true, description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, 'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup.") }, 'prof-append-timers': { type: 'string' }, @@ -80,7 +107,7 @@ export const OPTIONS: OptionDescriptions> = { 'inspect-extensions': { type: 'string', allowEmptyValue: true, deprecates: ['debugPluginHost'], args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, 'inspect-brk-extensions': { type: 'string', allowEmptyValue: true, deprecates: ['debugBrkPluginHost'], args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, 'disable-gpu': { type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, - 'ms-enable-electron-run-as-node': { type: 'boolean' }, + 'ms-enable-electron-run-as-node': { type: 'boolean', global: true }, 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes)."), args: 'memory' }, 'telemetry': { type: 'boolean', cat: 't', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, @@ -167,9 +194,11 @@ export interface ErrorReporter { onMultipleValues(id: string, usedValue: string): void; onEmptyValue(id: string): void; onDeprecatedOption(deprecatedId: string, message: string): void; + + getSubcommandReporter?(commmand: string): ErrorReporter; } -const ignoringReporter: ErrorReporter = { +const ignoringReporter = { onUnknownOption: () => { }, onMultipleValues: () => { }, onEmptyValue: () => { }, @@ -177,27 +206,54 @@ const ignoringReporter: ErrorReporter = { }; export function parseArgs(args: string[], options: OptionDescriptions, errorReporter: ErrorReporter = ignoringReporter): T { + const firstArg = args.find(a => a.length > 0 && a[0] !== '-'); + const alias: { [key: string]: string } = {}; const string: string[] = ['_']; const boolean: string[] = []; + const globalOptions: OptionDescriptions = {}; + let command: Subcommand | undefined = undefined; for (const optionId in options) { const o = options[optionId]; - if (o.alias) { - alias[optionId] = o.alias; - } - - if (o.type === 'string' || o.type === 'string[]') { - string.push(optionId); - if (o.deprecates) { - string.push(...o.deprecates); + if (o.type === 'subcommand') { + if (optionId === firstArg) { + command = o; } - } else if (o.type === 'boolean') { - boolean.push(optionId); - if (o.deprecates) { - boolean.push(...o.deprecates); + } else { + if (o.alias) { + alias[optionId] = o.alias; + } + + if (o.type === 'string' || o.type === 'string[]') { + string.push(optionId); + if (o.deprecates) { + string.push(...o.deprecates); + } + } else if (o.type === 'boolean') { + boolean.push(optionId); + if (o.deprecates) { + boolean.push(...o.deprecates); + } + } + if (o.global) { + globalOptions[optionId] = o; } } } + if (command && firstArg) { + const options = globalOptions; + for (const optionId in command.options) { + options[optionId] = command.options[optionId]; + } + const newArgs = args.filter(a => a !== firstArg); + const reporter = errorReporter.getSubcommandReporter ? errorReporter.getSubcommandReporter(firstArg) : undefined; + const subcommandOptions = parseArgs(newArgs, options, reporter); + return { + [firstArg]: subcommandOptions + }; + } + + // remove aliases to avoid confusion const parsedArgs = minimist(args, { string, boolean, alias }); @@ -211,6 +267,9 @@ export function parseArgs(args: string[], options: OptionDescriptions, err for (const optionId in options) { const o = options[optionId]; + if (o.type === 'subcommand') { + continue; + } if (o.alias) { delete remainingArgs[o.alias]; } @@ -284,14 +343,17 @@ function formatUsage(optionId: string, option: Option) { // exported only for testing export function formatOptions(options: OptionDescriptions, columns: number): string[] { - let maxLength = 0; const usageTexts: [string, string][] = []; for (const optionId in options) { const o = options[optionId]; const usageText = formatUsage(optionId, o); - maxLength = Math.max(maxLength, usageText.length); usageTexts.push([usageText, o.description!]); } + return formatUsageTexts(usageTexts, columns); +} + +function formatUsageTexts(usageTexts: [string, string][], columns: number) { + const maxLength = usageTexts.reduce((previous, e) => Math.max(previous, e[0].length), 12); const argLength = maxLength + 2/*left padding*/ + 1/*right padding*/; if (columns - argLength < 25) { // Use a condensed version on narrow terminals @@ -343,9 +405,14 @@ export function buildHelpMessage(productName: string, executableName: string, ve help.push(''); } const optionsByCategory: { [P in keyof typeof helpCategories]?: OptionDescriptions } = {}; + const subcommands: { command: string; description: string }[] = []; for (const optionId in options) { const o = options[optionId]; - if (o.description && o.cat) { + if (o.type === 'subcommand') { + if (o.description) { + subcommands.push({ command: optionId, description: o.description }); + } + } else if (o.description && o.cat) { let optionsByCat = optionsByCategory[o.cat]; if (!optionsByCat) { optionsByCategory[o.cat] = optionsByCat = {}; @@ -364,6 +431,13 @@ export function buildHelpMessage(productName: string, executableName: string, ve help.push(''); } } + + if (subcommands.length) { + help.push(localize('subcommands', "Subcommands")); + help.push(...formatUsageTexts(subcommands.map(s => [s.command, s.description]), columns)); + help.push(''); + } + return help.join('\n'); } diff --git a/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts index fcf94639485..610ba3d774a 100644 --- a/src/vs/platform/environment/node/argvHelper.ts +++ b/src/vs/platform/environment/node/argvHelper.ts @@ -12,19 +12,34 @@ import { ErrorReporter, OPTIONS, parseArgs } from 'vs/platform/environment/node/ const MIN_MAX_MEMORY_SIZE_MB = 2048; function parseAndValidate(cmdLineArgs: string[], reportWarnings: boolean): NativeParsedArgs { + const onMultipleValues = (id: string, val: string) => { + console.warn(localize('multipleValues', "Option '{0}' is defined more than once. Using value '{1}'.", id, val)); + }; + const onEmptyValue = (id: string) => { + console.warn(localize('emptyValue', "Option '{0}' requires a non empty value. Ignoring the option.", id)); + }; + const onDeprecatedOption = (deprecatedOption: string, message: string) => { + console.warn(localize('deprecatedArgument', "Option '{0}' is deprecated: {1}", deprecatedOption, message)); + }; + const getSubcommandReporter = (command: string) => ({ + onUnknownOption: (id: string) => { + if (command !== 'tunnel') { + console.warn(localize('unknownSubCommandOption', "Warning: '{0}' is not in the list of known options for subcommand '{1}'", id, command)); + } + }, + onMultipleValues, + onEmptyValue, + onDeprecatedOption, + getSubcommandReporter: command !== 'tunnel' ? getSubcommandReporter : undefined + }); const errorReporter: ErrorReporter = { onUnknownOption: (id) => { console.warn(localize('unknownOption', "Warning: '{0}' is not in the list of known options, but still passed to Electron/Chromium.", id)); }, - onMultipleValues: (id, val) => { - console.warn(localize('multipleValues', "Option '{0}' is defined more than once. Using value '{1}'.", id, val)); - }, - onEmptyValue: (id) => { - console.warn(localize('emptyValue', "Option '{0}' requires a non empty value. Ignoring the option.", id)); - }, - onDeprecatedOption: (deprecatedOption: string, message: string) => { - console.warn(localize('deprecatedArgument', "Option '{0}' is deprecated: {1}", deprecatedOption, message)); - } + onMultipleValues, + onEmptyValue, + onDeprecatedOption, + getSubcommandReporter }; const args = parseArgs(cmdLineArgs, OPTIONS, reportWarnings ? errorReporter : undefined); @@ -68,7 +83,12 @@ export function parseMainProcessArgv(processArgv: string[]): NativeParsedArgs { * Use this to parse raw code CLI process.argv such as: `Electron cli.js . --verbose --wait` */ export function parseCLIProcessArgv(processArgv: string[]): NativeParsedArgs { - const [, , ...args] = processArgv; // remove the first non-option argument: it's always the app location + let [, , ...args] = processArgv; // remove the first non-option argument: it's always the app location + + // If dev, remove the first non-option argument: it's the app location + if (process.env['VSCODE_DEV']) { + args = stripAppPath(args) || []; + } return parseAndValidate(args, true); } diff --git a/src/vs/platform/environment/test/node/argv.test.ts b/src/vs/platform/environment/test/node/argv.test.ts index 7d1439125d2..fc182805893 100644 --- a/src/vs/platform/environment/test/node/argv.test.ts +++ b/src/vs/platform/environment/test/node/argv.test.ts @@ -4,23 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { formatOptions, Option } from 'vs/platform/environment/node/argv'; +import { formatOptions, Option, OptionDescriptions, Subcommand, parseArgs, ErrorReporter } from 'vs/platform/environment/node/argv'; import { addArg } from 'vs/platform/environment/node/argvHelper'; -suite('formatOptions', () => { +function o(description: string, type: 'boolean' | 'string' | 'string[]' = 'string'): Option { + return { + description, type + }; +} +function c(description: string, options: OptionDescriptions): Subcommand { + return { + description, type: 'subcommand', options + }; +} - function o(description: string): Option { - return { - description, type: 'string' - }; - } +suite('formatOptions', () => { test('Text should display small columns correctly', () => { assert.deepStrictEqual( formatOptions({ 'add': o('bar') }, 80), - [' --add bar'] + [' --add bar'] ); assert.deepStrictEqual( formatOptions({ @@ -29,9 +34,9 @@ suite('formatOptions', () => { 'trace': o('b') }, 80), [ - ' --add bar', - ' --wait ba', - ' --trace b' + ' --add bar', + ' --wait ba', + ' --trace b' ]); }); @@ -41,8 +46,8 @@ suite('formatOptions', () => { 'add': o(('bar ').repeat(9)) }, 40), [ - ' --add bar bar bar bar bar bar bar bar', - ' bar' + ' --add bar bar bar bar bar bar', + ' bar bar bar' ]); }); @@ -65,4 +70,67 @@ suite('formatOptions', () => { assert.deepStrictEqual(addArg(['--wait', '--', '--foo'], 'bar'), ['--wait', 'bar', '--', '--foo']); assert.deepStrictEqual(addArg(['--', '--foo'], 'bar'), ['bar', '--', '--foo']); }); + + test('subcommands', () => { + assert.deepStrictEqual( + formatOptions({ + 'testcmd': c('A test command', { add: o('A test command option') }) + }, 30), + [ + ' --testcmd', + ' A test command' + ]); + }); +}); + +suite('parseArgs', () => { + function newErrorReporter(result: string[] = [], command = ''): ErrorReporter & { result: string[] } { + const commandPrefix = command ? command + '-' : ''; + return { + onDeprecatedOption: (deprecatedId) => result.push(`${commandPrefix}onDeprecatedOption ${deprecatedId}`), + onUnknownOption: (id) => result.push(`${commandPrefix}onUnknownOption ${id}`), + onEmptyValue: (id) => result.push(`${commandPrefix}onEmptyValue ${id}`), + onMultipleValues: (id, usedValue) => result.push(`${commandPrefix}onMultipleValues ${id} ${usedValue}`), + getSubcommandReporter: (c) => newErrorReporter(result, commandPrefix + c), + result + }; + } + + function assertParse(options: OptionDescriptions, input: string[], expected: T, expectedErrors: string[]) { + const errorReporter = newErrorReporter(); + assert.deepStrictEqual(parseArgs(input, options, errorReporter), expected); + assert.deepStrictEqual(errorReporter.result, expectedErrors); + } + + test('subcommands', () => { + const options1 = { + 'testcmd': c('A test command', { + testArg: o('A test command option') + }) + }; + assertParse( + options1, + ['testcmd', '--testArg=foo'], + { testcmd: { testArg: 'foo', '_': [] } }, + [] + ); + assertParse( + options1, + ['testcmd', '--testArg=foo', '--testX'], + { testcmd: { testArg: 'foo', '_': [] } }, + ['testcmd-onUnknownOption testX'] + ); + const options2 = { + 'testcmd': c('A test command', { + testArg: o('A test command option') + }), + testX: { global: true } + }; + assertParse( + options2, + ['testcmd', '--testArg=foo', '--testX'], + { testcmd: { testArg: 'foo', testX: true, '_': [] } }, + [] + ); + }); }); diff --git a/src/vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService.ts b/src/vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService.ts new file mode 100644 index 00000000000..ebcc62825c1 --- /dev/null +++ b/src/vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService.ts @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Promises } from 'vs/base/common/async'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; + +export const ISharedProcessLifecycleService = createDecorator('lifecycleSharedProcessService'); + +export interface ISharedProcessLifecycleService { + readonly _serviceBrand: undefined; + + /** + * An event that fires after after no window has vetoed the shutdown sequence. At + * this point listeners are ensured that the application will quit without veto. + */ + readonly onWillShutdown: Event; +} + +export interface ShutdownEvent { + + /** + * Allows to join the shutdown. The promise can be a long running operation but it + * will block the application from closing. + */ + join(promise: Promise): void; +} + +export class SharedProcessLifecycleService extends Disposable implements ISharedProcessLifecycleService { + + declare readonly _serviceBrand: undefined; + + private pendingWillShutdownPromise: Promise | undefined = undefined; + + private readonly _onWillShutdown = this._register(new Emitter()); + readonly onWillShutdown = this._onWillShutdown.event; + + constructor( + @ILogService private readonly logService: ILogService + ) { + super(); + } + + public fireOnWillShutdown(): Promise { + if (this.pendingWillShutdownPromise) { + return this.pendingWillShutdownPromise; // shutdown is already running + } + + this.logService.trace('Lifecycle#onWillShutdown.fire()'); + + const joiners: Promise[] = []; + + this._onWillShutdown.fire({ + join(promise) { + joiners.push(promise); + } + }); + + this.pendingWillShutdownPromise = (async () => { + + // Settle all shutdown event joiners + try { + await Promises.settled(joiners); + } catch (error) { + this.logService.error(error); + } + })(); + + return this.pendingWillShutdownPromise; + } + +} diff --git a/src/vs/platform/remoteTunnel/common/remoteTunnel.ts b/src/vs/platform/remoteTunnel/common/remoteTunnel.ts new file mode 100644 index 00000000000..f7c9e2a3609 --- /dev/null +++ b/src/vs/platform/remoteTunnel/common/remoteTunnel.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Event } from 'vs/base/common/event'; + + +export interface IRemoteTunnelAccount { + readonly authenticationProviderId: string; + readonly token: string; +} + +export const IRemoteTunnelService = createDecorator('IRemoteTunnelService'); +export interface IRemoteTunnelService { + readonly _serviceBrand: undefined; + + readonly onDidTokenFailed: Event; + readonly onDidChangeTunnelStatus: Event; + + getAccount(): Promise; + readonly onDidChangeAccount: Event; + updateAccount(account: IRemoteTunnelAccount | undefined): Promise; + +} + +export const enum TunnelStatus { + Uninitialized = 'uninitialized', + Disconnected = 'disconnected', + Connecting = 'connecting', + Connected = 'connected', +} diff --git a/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts new file mode 100644 index 00000000000..5ee3758c59d --- /dev/null +++ b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts @@ -0,0 +1,199 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRemoteTunnelAccount, IRemoteTunnelService, TunnelStatus } from 'vs/platform/remoteTunnel/common/remoteTunnel'; +import { Emitter } from 'vs/base/common/event'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; +import { URI } from 'vs/base/common/uri'; +import { dirname, join } from 'vs/base/common/path'; +import { ChildProcess, spawn } from 'child_process'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { isWindows } from 'vs/base/common/platform'; +import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { ISharedProcessLifecycleService } from 'vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + + +type RemoteTunnelEnablementClassification = { + owner: 'aeschli'; + comment: 'Reporting when Remote Tunnel access is turned on or off'; + enabled?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Flag indicating if Remote Tunnel Access is enabled or not' }; +}; + +type RemoteTunnelEnablementEvent = { + enabled: boolean; +}; + +/** + * This service runs on the shared service. It is running the `code-tunnel` command + * to make the current machine available for remote access. + */ +export class RemoteTunnelService extends Disposable implements IRemoteTunnelService { + + declare readonly _serviceBrand: undefined; + + private readonly _onDidTokenFailedEmitter = new Emitter(); + public readonly onDidTokenFailed = this._onDidTokenFailedEmitter.event; + + private readonly _onDidChangeTunnelStatusEmitter = new Emitter(); + public readonly onDidChangeTunnelStatus = this._onDidChangeTunnelStatusEmitter.event; + + private readonly _onDidChangeAccountEmitter = new Emitter(); + public readonly onDidChangeAccount = this._onDidChangeAccountEmitter.event; + + private readonly _logger: ILogger; + + private _account: IRemoteTunnelAccount | undefined; + private _tunnelProcess: CancelablePromise | undefined; + + private _tunnelStatus: TunnelStatus = TunnelStatus.Disconnected; + + constructor( + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IProductService private readonly productService: IProductService, + @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService, + @ILoggerService loggerService: ILoggerService, + @ISharedProcessLifecycleService sharedProcessLifecycleService: ISharedProcessLifecycleService, + @IConfigurationService configurationService: IConfigurationService + ) { + super(); + const logFileUri = URI.file(join(dirname(environmentService.logsPath), 'remoteTunnel.log')); + this._logger = this._register(loggerService.createLogger(logFileUri, { name: 'remoteTunnel' })); + + this._register(sharedProcessLifecycleService.onWillShutdown(e => { + if (this._tunnelProcess) { + this._tunnelProcess.cancel(); + this._tunnelProcess = undefined; + } + this.dispose(); + })); + } + + async getAccount(): Promise { + return this._account; + } + + async updateAccount(account: IRemoteTunnelAccount | undefined): Promise { + if (account && this._account ? account.token !== this._account.token || account.authenticationProviderId !== this._account.authenticationProviderId : account !== this._account) { + this._account = account; + this._onDidChangeAccountEmitter.fire(account); + + this._logger.info(`Account updated: ${account ? account.authenticationProviderId : 'undefined'}`); + + this.telemetryService.publicLog2('remoteTunnel.enablement', { enabled: !!account }); + + try { + this.updateTunnelProcess(); + } catch (e) { + this._logger.error(e); + } + } + + } + + private async updateTunnelProcess(): Promise { + if (this._tunnelProcess) { + this._tunnelProcess.cancel(); + this._tunnelProcess = undefined; + } + if (!this._account) { + this.setTunnelStatus(TunnelStatus.Disconnected); + return; + } + this.setTunnelStatus(TunnelStatus.Connecting); + const loginProcess = this.runCodeTunneCommand('login', ['user', 'login', '--provider', this._account.authenticationProviderId, '--access-token', this._account.token]); + this._tunnelProcess = loginProcess; + try { + await loginProcess; + } catch (e) { + this._logger.error(e); + this._tunnelProcess = undefined; + this._onDidTokenFailedEmitter.fire(true); + this.setTunnelStatus(TunnelStatus.Disconnected); + } + if (this._tunnelProcess === loginProcess) { + const serveCommand = this.runCodeTunneCommand('tunnel', ['--random-name'], (message: string) => { + }); + this._tunnelProcess = serveCommand; + serveCommand.finally(() => { + if (serveCommand === this._tunnelProcess) { + // process exited unexpectedly + this._logger.info(`tunnel process terminated`); + this._tunnelProcess = undefined; + this._account = undefined; + + this.setTunnelStatus(TunnelStatus.Disconnected); + } + }); + + } + } + + private setTunnelStatus(tunnelStatus: TunnelStatus) { + if (tunnelStatus !== this._tunnelStatus) { + this._tunnelStatus = tunnelStatus; + this._onDidChangeTunnelStatusEmitter.fire(tunnelStatus); + } + } + + + private runCodeTunneCommand(logLabel: string, commandArgs: string[], onOutput: (message: string, isError: boolean) => void = () => { }): CancelablePromise { + return createCancelablePromise(token => { + return new Promise((resolve, reject) => { + if (token.isCancellationRequested) { + resolve(); + } + let tunnelProcess: ChildProcess | undefined; + token.onCancellationRequested(() => { + if (tunnelProcess) { + this._logger.info(`${logLabel} terminating (${tunnelProcess.pid})`); + tunnelProcess.kill(); + } + }); + if (process.env['VSCODE_DEV']) { + this._logger.info(`${logLabel} Spawning: cargo run --bin code-tunnel -- ${commandArgs.join(' ')}`); + tunnelProcess = spawn('cargo', ['run', '--bin', 'code-tunnel', '--', ...commandArgs], { cwd: join(this.environmentService.appRoot, 'cli') }); + } else { + const tunnelCommand = join(dirname(process.execPath), 'bin', `${this.productService.tunnelApplicationName}${isWindows ? '.exe' : ''}`); + this._logger.info(`${logLabel} Spawning: ${tunnelCommand} ${commandArgs.join(' ')}`); + tunnelProcess = spawn(tunnelCommand, commandArgs); + } + + tunnelProcess.stdout!.on('data', data => { + if (tunnelProcess) { + const message = data.toString(); + onOutput(message, false); + this._logger.info(`${logLabel} stdout (${tunnelProcess.pid}): + ${message}`); + } + }); + tunnelProcess.stderr!.on('data', data => { + if (tunnelProcess) { + const message = data.toString(); + onOutput(message, true); + this._logger.info(`${logLabel} stderr (${tunnelProcess.pid}): + ${message}`); + } + }); + tunnelProcess.on('exit', e => { + if (tunnelProcess) { + this._logger.info(`${logLabel} exit (${tunnelProcess.pid}): + ${e}`); + tunnelProcess = undefined; + resolve(); + } + }); + tunnelProcess.on('error', e => { + if (tunnelProcess) { + this._logger.info(`${logLabel} error (${tunnelProcess.pid}): + ${e}`); + tunnelProcess = undefined; + reject(); + } + }); + }); + }); + } + +} diff --git a/src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts b/src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts new file mode 100644 index 00000000000..4d626c9de47 --- /dev/null +++ b/src/vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +import { IRemoteTunnelService } from 'vs/platform/remoteTunnel/common/remoteTunnel'; + +registerSharedProcessRemoteService(IRemoteTunnelService, 'remoteTunnel'); diff --git a/src/vs/server/node/server.cli.ts b/src/vs/server/node/server.cli.ts index d7b1c9b307e..138f6dd8130 100644 --- a/src/vs/server/node/server.cli.ts +++ b/src/vs/server/node/server.cli.ts @@ -94,7 +94,7 @@ export async function main(desc: ProductDescription, args: string[]): Promise = { ...OPTIONS }; + const options: OptionDescriptions> = { ...OPTIONS, gitCredential: { type: 'string' }, openExternal: { type: 'boolean' } }; const isSupported = cliCommand ? isSupportedForCmd : isSupportedForPipe; for (const optionId in OPTIONS) { const optId = optionId; diff --git a/src/vs/server/node/serverEnvironmentService.ts b/src/vs/server/node/serverEnvironmentService.ts index 8c5a3c89cb8..646e3ae2af1 100644 --- a/src/vs/server/node/serverEnvironmentService.ts +++ b/src/vs/server/node/serverEnvironmentService.ts @@ -10,7 +10,7 @@ import { OPTIONS, OptionDescriptions } from 'vs/platform/environment/node/argv'; import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -export const serverOptions: OptionDescriptions = { +export const serverOptions: OptionDescriptions> = { /* ----- server setup ----- */ diff --git a/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts b/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts new file mode 100644 index 00000000000..5572254d5e2 --- /dev/null +++ b/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts @@ -0,0 +1,382 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IRemoteTunnelService, TunnelStatus } from 'vs/platform/remoteTunnel/common/remoteTunnel'; +import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; +import { localize } from 'vs/nls'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { ILocalizedString } from 'vs/platform/action/common/action'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { ILogger, ILoggerService, ILogService } from 'vs/platform/log/common/log'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { URI } from 'vs/base/common/uri'; +import { join } from 'vs/base/common/path'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IStringDictionary } from 'vs/base/common/collections'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; +import { registerLogChannel } from 'vs/workbench/services/output/common/output'; +import { IFileService } from 'vs/platform/files/common/files'; + +export const REMOTE_TUNNEL_CATEGORY: ILocalizedString = { + original: 'Remote Tunnel', + value: localize('remoteTunnel.category', 'Remote Tunnel') +}; + +export const REMOTE_TUNNEL_SIGNED_IN_KEY = 'remoteTunnelSignedIn'; +export const REMOTE_TUNNEL_SIGNED_IN = new RawContextKey(REMOTE_TUNNEL_SIGNED_IN_KEY, false); + +const CACHED_SESSION_STORAGE_KEY = 'remoteTunnelAccountPreference'; + +type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } }; +type IAuthenticationProvider = { id: string; scopes: string[] }; +type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider }; + +export class RemoteTunnelWorkbenchContribution extends Disposable implements IWorkbenchContribution { + + private readonly signedInContext: IContextKey; + + private readonly serverConfiguration: { authenticationProviders: IStringDictionary<{ scopes: string[] }> }; + + private initialized = false; + #authenticationInfo: { sessionId: string; token: string; providerId: string } | undefined; + + private readonly logger: ILogger; + + constructor( + @IAuthenticationService private readonly authenticationService: IAuthenticationService, + @IDialogService private readonly dialogService: IDialogService, + @IExtensionService private readonly extensionService: IExtensionService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IProductService productService: IProductService, + @IStorageService private readonly storageService: IStorageService, + @ILoggerService loggerService: ILoggerService, + @ILogService logService: ILogService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService, + @IRemoteTunnelService private remoteTunnelService: IRemoteTunnelService + ) { + super(); + + const logPathURI = URI.file(join(environmentService.logsPath, 'remoteTunnel.log')); + + this.logger = this._register(loggerService.createLogger(logPathURI, { name: 'remoteTunnel' })); + + const promise = registerLogChannel('remoteTunnel', localize('remoteTunnel.outputTitle', "Remote Tunnel"), logPathURI, fileService, logService); + this._register(toDisposable(() => promise.cancel())); + + this.signedInContext = REMOTE_TUNNEL_SIGNED_IN.bindTo(this.contextKeyService); + + const serverConfiguration = productService.tunnelApplicationConfig; + if (!serverConfiguration || !productService.tunnelApplicationName) { + this.logger.error('Missing \'tunnelApplicationConfig\' or \'tunnelApplicationName\' in product.json. Remote tunneling is not available.'); + this.serverConfiguration = { authenticationProviders: {} }; + return; + } + this.serverConfiguration = serverConfiguration; + + this._register(this.remoteTunnelService.onDidTokenFailed(() => { + this.logger.info('Clearing authentication preference because of successive token failures.'); + this.clearAuthenticationPreference(); + })); + this._register(this.remoteTunnelService.onDidChangeTunnelStatus(status => { + if (status === TunnelStatus.Disconnected) { + this.logger.info('Clearing authentication preference because of tunnel disconnected.'); + this.clearAuthenticationPreference(); + } + })); + + // If the user signs out of the current session, reset our cached auth state in memory and on disk + this._register(this.authenticationService.onDidChangeSessions((e) => this.onDidChangeSessions(e.event))); + + // If another window changes the preferred session storage, reset our cached auth state in memory + this._register(this.storageService.onDidChangeValue(e => this.onDidChangeStorage(e))); + + this.registerTurnOnAction(); + this.registerTurnOffAction(); + + this.signedInContext.set(this.existingSessionId !== undefined); + + if (this.existingSessionId) { + this.initialize(true); + } + + } + + private get existingSessionId() { + return this.storageService.get(CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); + } + + private set existingSessionId(sessionId: string | undefined) { + this.logger.trace(`Saving authentication preference for ID ${sessionId}.`); + if (sessionId === undefined) { + this.storageService.remove(CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); + } else { + this.storageService.store(CACHED_SESSION_STORAGE_KEY, sessionId, StorageScope.APPLICATION, StorageTarget.MACHINE); + } + } + + public async initialize(silent: boolean = false) { + if (this.initialized) { + return true; + } + this.initialized = await this.doInitialize(silent); + this.signedInContext.set(this.initialized); + return this.initialized; + } + + /** + * + * Ensures that the store client is initialized, + * meaning that authentication is configured and it + * can be used to communicate with the remote storage service + */ + private async doInitialize(silent: boolean): Promise { + // Wait for authentication extensions to be registered + await this.extensionService.whenInstalledExtensionsRegistered(); + + // If we already have an existing auth session in memory, use that + if (this.#authenticationInfo !== undefined) { + return true; + } + + const authenticationSession = await this.getAuthenticationSession(silent); + if (authenticationSession !== undefined) { + this.#authenticationInfo = authenticationSession; + this.remoteTunnelService.updateAccount({ token: authenticationSession.token, authenticationProviderId: authenticationSession.providerId }); + } + + return authenticationSession !== undefined; + } + + private async getAuthenticationSession(silent: boolean) { + // If the user signed in previously and the session is still available, reuse that without prompting the user again + if (this.existingSessionId) { + this.logger.info(`Searching for existing authentication session with ID ${this.existingSessionId}`); + const existingSession = await this.getExistingSession(); + if (existingSession) { + this.logger.info(`Found existing authentication session with ID ${existingSession.session.id}`); + return { sessionId: existingSession.session.id, token: existingSession.session.idToken ?? existingSession.session.accessToken, providerId: existingSession.session.providerId }; + } else { + //this._didSignOut.fire(); + } + } + + // If we aren't supposed to prompt the user because + // we're in a silent flow, just return here + if (silent) { + return; + } + + // Ask the user to pick a preferred account + const authenticationSession = await this.getAccountPreference(); + if (authenticationSession !== undefined) { + this.existingSessionId = authenticationSession.id; + return { sessionId: authenticationSession.id, token: authenticationSession.idToken ?? authenticationSession.accessToken, providerId: authenticationSession.providerId }; + } + + return undefined; + } + + private async getAccountPreference(): Promise { + const quickpick = this.quickInputService.createQuickPick(); + quickpick.title = localize('accountPreference.title', 'Enable remote access by signing up to remote tunnels.'); + quickpick.ok = false; + quickpick.placeholder = localize('accountPreference.placeholder', "Select an account to sign in"); + quickpick.ignoreFocusOut = true; + quickpick.items = await this.createQuickpickItems(); + + return new Promise((resolve, reject) => { + quickpick.onDidHide((e) => { + resolve(undefined); + quickpick.dispose(); + }); + + quickpick.onDidAccept(async (e) => { + const selection = quickpick.selectedItems[0]; + const session = 'provider' in selection ? { ...await this.authenticationService.createSession(selection.provider.id, selection.provider.scopes), providerId: selection.provider.id } : ('session' in selection ? selection.session : undefined); + resolve(session); + quickpick.hide(); + }); + + quickpick.show(); + }); + } + + private async createQuickpickItems(): Promise<(ExistingSession | AuthenticationProviderOption | IQuickPickSeparator | IQuickPickItem & { canceledAuthentication: boolean })[]> { + const options: (ExistingSession | AuthenticationProviderOption | IQuickPickSeparator | IQuickPickItem & { canceledAuthentication: boolean })[] = []; + + options.push({ type: 'separator', label: localize('signed in', "Signed In") }); + + const sessions = await this.getAllSessions(); + options.push(...sessions); + + options.push({ type: 'separator', label: localize('others', "Others") }); + + for (const authenticationProvider of (await this.getAuthenticationProviders())) { + const signedInForProvider = sessions.some(account => account.session.providerId === authenticationProvider.id); + if (!signedInForProvider || this.authenticationService.supportsMultipleAccounts(authenticationProvider.id)) { + const providerName = this.authenticationService.getLabel(authenticationProvider.id); + options.push({ label: localize('sign in using account', "Sign in with {0}", providerName), provider: authenticationProvider }); + } + } + + return options; + } + + + private async getExistingSession() { + const accounts = await this.getAllSessions(); + return accounts.find((account) => account.session.id === this.existingSessionId); + } + + private async onDidChangeStorage(e: IStorageValueChangeEvent): Promise { + if (e.key === CACHED_SESSION_STORAGE_KEY && e.scope === StorageScope.APPLICATION) { + const newSessionId = this.existingSessionId; + const previousSessionId = this.#authenticationInfo?.sessionId; + + if (previousSessionId !== newSessionId) { + this.logger.trace(`Resetting authentication state because authentication session ID preference changed from ${previousSessionId} to ${newSessionId}.`); + this.#authenticationInfo = undefined; + this.initialized = false; + } + } + } + + private clearAuthenticationPreference(): void { + this.#authenticationInfo = undefined; + this.initialized = false; + this.existingSessionId = undefined; + this.signedInContext.set(false); + } + + private onDidChangeSessions(e: AuthenticationSessionsChangeEvent): void { + if (this.#authenticationInfo?.sessionId && e.removed.find(session => session.id === this.#authenticationInfo?.sessionId)) { + this.clearAuthenticationPreference(); + } + } + + /** + * + * Returns all authentication sessions available from {@link getAuthenticationProviders}. + */ + private async getAllSessions() { + const authenticationProviders = await this.getAuthenticationProviders(); + const accounts = new Map(); + let currentSession: ExistingSession | undefined; + + for (const provider of authenticationProviders) { + const sessions = await this.authenticationService.getSessions(provider.id, provider.scopes); + + for (const session of sessions) { + const item = { + label: session.account.label, + description: this.authenticationService.getLabel(provider.id), + session: { ...session, providerId: provider.id } + }; + accounts.set(item.session.account.id, item); + if (this.existingSessionId === session.id) { + currentSession = item; + } + } + } + + if (currentSession !== undefined) { + accounts.set(currentSession.session.account.id, currentSession); + } + + return [...accounts.values()]; + } + + /** + * Returns all authentication providers which can be used to authenticate + * to the remote storage service, based on product.json configuration + * and registered authentication providers. + */ + private async getAuthenticationProviders() { + // Get the list of authentication providers configured in product.json + const authenticationProviders = this.serverConfiguration.authenticationProviders; + const configuredAuthenticationProviders = Object.keys(authenticationProviders).reduce((result, id) => { + result.push({ id, scopes: authenticationProviders[id].scopes }); + return result; + }, []); + + // Filter out anything that isn't currently available through the authenticationService + const availableAuthenticationProviders = this.authenticationService.declaredProviders; + + return configuredAuthenticationProviders.filter(({ id }) => availableAuthenticationProviders.some(provider => provider.id === id)); + } + + private registerTurnOnAction() { + const that = this; + this._register(registerAction2(class ShareMachineAction extends Action2 { + constructor() { + super({ + id: 'workbench.remoteTunnel.actions.turnOn', + title: localize('remoteTunnel.turnOn', 'Turn on Remote Tunnel Access...'), + category: REMOTE_TUNNEL_CATEGORY, + precondition: ContextKeyExpr.equals(REMOTE_TUNNEL_SIGNED_IN_KEY, false), + menu: [{ + id: MenuId.CommandPalette, + }, + { + id: MenuId.AccountsContext, + group: '2_remoteTunnel', + when: ContextKeyExpr.equals(REMOTE_TUNNEL_SIGNED_IN_KEY, false), + }] + }); + } + + async run() { + return await that.initialize(false); + } + })); + } + + private registerTurnOffAction() { + const that = this; + this._register(registerAction2(class ResetShareMachineAuthenticationAction extends Action2 { + constructor() { + super({ + id: 'workbench.remoteTunnel.actions.turnOff', + title: localize('remoteTunnel.turnOff', 'Turn off Remote Tunnel Access...'), + category: REMOTE_TUNNEL_CATEGORY, + precondition: ContextKeyExpr.equals(REMOTE_TUNNEL_SIGNED_IN_KEY, true), + menu: [{ + id: MenuId.CommandPalette, + }, + { + id: MenuId.AccountsContext, + group: '2_remoteTunnel', + when: ContextKeyExpr.equals(REMOTE_TUNNEL_SIGNED_IN_KEY, true), + }] + }); + } + + async run() { + const result = await that.dialogService.confirm({ + type: 'info', + message: localize('remoteTunnel.turnOff.confirm', 'Do you want to turn off Remote Tunnel Access?'), + primaryButton: localize('remoteTunnel.turnOff.yesButton', 'Yes'), + }); + if (result.confirmed) { + that.clearAuthenticationPreference(); + that.remoteTunnelService.updateAccount(undefined); + } + } + })); + } + +} + +const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(RemoteTunnelWorkbenchContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 628a581d5a2..ca74c51637b 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -79,6 +79,7 @@ import 'vs/workbench/services/tunnel/electron-sandbox/tunnelService'; import 'vs/platform/diagnostics/electron-sandbox/diagnosticsService'; import 'vs/platform/profiling/electron-sandbox/profilingService'; import 'vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService'; +import 'vs/platform/remoteTunnel/electron-sandbox/remoteTunnelService'; import 'vs/workbench/services/files/electron-sandbox/elevatedFileService'; import 'vs/workbench/services/search/electron-sandbox/searchService'; import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService'; @@ -160,4 +161,7 @@ import 'vs/workbench/contrib/localHistory/electron-sandbox/localHistory.contribu // Merge Editor import 'vs/workbench/contrib/mergeEditor/electron-sandbox/mergeEditor.contribution'; +// Remote Tunnel +import 'vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution'; + //#endregion From 0dd2dc89d21b3e866eeb2b7335b6c7f14ee0e031 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 13 Oct 2022 15:04:08 +0200 Subject: [PATCH 560/599] hook up unhandled extension errors with extension telemetry (#163424) * hook up unhandled extension errors with extension telemetry * fix layering * forward unhandled language provider errors to extension telemetry loggers --- src/vs/base/common/errors.ts | 18 +-- .../workbench/api/common/extHost.api.impl.ts | 2 +- .../api/common/extHostLanguageFeatures.ts | 28 ++--- .../workbench/api/common/extHostTelemetry.ts | 11 +- .../workbench/api/common/extensionHostMain.ts | 110 ++++++++++++------ .../test/browser/extHostApiCommands.test.ts | 3 +- .../browser/extHostLanguageFeatures.test.ts | 3 +- 7 files changed, 110 insertions(+), 65 deletions(-) diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts index 44b25af9e3a..bea757b1ac6 100644 --- a/src/vs/base/common/errors.ts +++ b/src/vs/base/common/errors.ts @@ -123,15 +123,15 @@ export function transformErrorForSerialization(error: any): any { // see https://github.com/v8/v8/wiki/Stack%20Trace%20API#basic-stack-traces export interface V8CallSite { - getThis(): any; - getTypeName(): string; - getFunction(): string; - getFunctionName(): string; - getMethodName(): string; - getFileName(): string; - getLineNumber(): number; - getColumnNumber(): number; - getEvalOrigin(): string; + getThis(): unknown; + getTypeName(): string | null; + getFunction(): Function | undefined; + getFunctionName(): string | null; + getMethodName(): string | null; + getFileName(): string | null; + getLineNumber(): number | null; + getColumnNumber(): number | null; + getEvalOrigin(): string | undefined; isToplevel(): boolean; isEval(): boolean; isNative(): boolean; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 22e084f52e1..f781761bb04 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -167,7 +167,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.remote)); const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService, extHostFileSystemInfo)); const extHostLanguages = rpcProtocol.set(ExtHostContext.ExtHostLanguages, new ExtHostLanguages(rpcProtocol, extHostDocuments, extHostCommands.converter, uriTransformer)); - const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation)); + const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation, extHostTelemetry)); const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors)); const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, createExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands)); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 49384cee4af..dad1a4ff5d1 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -34,6 +34,7 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import { isCancellationError, NotImplementedError } from 'vs/base/common/errors'; import { raceCancellationError } from 'vs/base/common/async'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; // --- adapter @@ -1831,31 +1832,20 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF private static _handlePool: number = 0; - private readonly _uriTransformer: IURITransformer; private readonly _proxy: extHostProtocol.MainThreadLanguageFeaturesShape; - private readonly _documents: ExtHostDocuments; - private readonly _commands: ExtHostCommands; - private readonly _diagnostics: ExtHostDiagnostics; private readonly _adapter = new Map(); - private readonly _logService: ILogService; - private readonly _apiDeprecation: IExtHostApiDeprecationService; constructor( mainContext: extHostProtocol.IMainContext, - uriTransformer: IURITransformer, - documents: ExtHostDocuments, - commands: ExtHostCommands, - diagnostics: ExtHostDiagnostics, - logService: ILogService, - apiDeprecationService: IExtHostApiDeprecationService, + private readonly _uriTransformer: IURITransformer, + private readonly _documents: ExtHostDocuments, + private readonly _commands: ExtHostCommands, + private readonly _diagnostics: ExtHostDiagnostics, + private readonly _logService: ILogService, + private readonly _apiDeprecation: IExtHostApiDeprecationService, + private readonly _extensionTelemetry: IExtHostTelemetry ) { - this._uriTransformer = uriTransformer; this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadLanguageFeatures); - this._documents = documents; - this._commands = commands; - this._diagnostics = diagnostics; - this._logService = logService; - this._apiDeprecation = apiDeprecationService; } private _transformDocumentSelector(selector: vscode.DocumentSelector): Array { @@ -1898,6 +1888,8 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF if (!isCancellationError(err)) { this._logService.error(`[${data.extension.identifier.value}] provider FAILED`); this._logService.error(err); + + this._extensionTelemetry.onExtensionError(data.extension.identifier, err); } }).finally(() => { if (!doNotLog) { diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index 47940f571d5..b0095f90a14 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -10,7 +10,7 @@ import { ExtHostTelemetryShape } from 'vs/workbench/api/common/extHost.protocol' import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; import { cleanData, cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -107,6 +107,15 @@ export class ExtHostTelemetry implements ExtHostTelemetryShape { } this._onDidChangeTelemetryConfiguration.fire(this.getTelemetryDetails()); } + + onExtensionError(extension: ExtensionIdentifier, error: Error): boolean { + const logger = this._telemetryLoggers.get(extension.value); + if (!logger) { + return false; + } + logger.logError(error); + return true; + } } export class ExtHostTelemetryLogger { diff --git a/src/vs/workbench/api/common/extensionHostMain.ts b/src/vs/workbench/api/common/extensionHostMain.ts index a204a569f0e..f621e0af82a 100644 --- a/src/vs/workbench/api/common/extensionHostMain.ts +++ b/src/vs/workbench/api/common/extensionHostMain.ts @@ -11,16 +11,17 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; import { IExtensionHostInitData } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService, ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IURITransformerService, URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostExtensionService, IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; +import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; export interface IExitFn { (code?: number): any; @@ -30,6 +31,75 @@ export interface IConsolePatchFn { (mainThreadConsole: MainThreadConsoleShape): any; } +abstract class ErrorHandler { + + static { + // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) + Error.stackTraceLimit = 100; + } + + static async installEarlyHandler(accessor: ServicesAccessor): Promise { + // does NOT dependent of extension information, can be installed immediately, and simply forwards + // to the log service and main thread errors + const logService = accessor.get(ILogService); + const rpcService = accessor.get(IExtHostRpcService); + const mainThreadErrors = rpcService.getProxy(MainContext.MainThreadErrors); + + errors.setUnexpectedErrorHandler(err => { + logService.error(err); + const data = errors.transformErrorForSerialization(err); + mainThreadErrors.$onUnexpectedError(data); + }); + } + + static async installFullHandler(accessor: ServicesAccessor): Promise { + // uses extension knowledges to correlate errors with extensions + + const logService = accessor.get(ILogService); + const rpcService = accessor.get(IExtHostRpcService); + const extensionService = accessor.get(IExtHostExtensionService); + const extensionTelemetry = accessor.get(IExtHostTelemetry); + + const mainThreadExtensions = rpcService.getProxy(MainContext.MainThreadExtensionService); + const mainThreadErrors = rpcService.getProxy(MainContext.MainThreadErrors); + + const map = await extensionService.getExtensionPathIndex(); + const extensionErrors = new WeakMap(); + + // set the prepareStackTrace-handle and use it as a side-effect to associate errors + // with extensions - this works by looking up callsites in the extension path index + (Error).prepareStackTrace = (error: Error, stackTrace: errors.V8CallSite[]) => { + let stackTraceMessage = ''; + let extension: IExtensionDescription | undefined; + let fileName: string | null; + for (const call of stackTrace) { + stackTraceMessage += `\n\tat ${call.toString()}`; + fileName = call.getFileName(); + if (!extension && fileName) { + extension = map.findSubstr(URI.file(fileName)); + } + } + extensionErrors.set(error, extension?.identifier); + return `${error.name || 'Error'}: ${error.message || ''}${stackTraceMessage}`; + }; + + errors.setUnexpectedErrorHandler(err => { + logService.error(err); + + const data = errors.transformErrorForSerialization(err); + const extension = extensionErrors.get(err); + if (!extension) { + mainThreadErrors.$onUnexpectedError(data); + return; + } + + mainThreadExtensions.$onExtensionRuntimeError(extension, data); + const reported = extensionTelemetry.onExtensionError(extension, err); + logService.trace('forwarded error to extension?', reported, extension); + }); + } +} + export class ExtensionHostMain { private readonly _hostUtils: IHostUtils; @@ -59,6 +129,8 @@ export class ExtensionHostMain { const instaService: IInstantiationService = new InstantiationService(services, true); + instaService.invokeFunction(ErrorHandler.installEarlyHandler); + // ugly self - inject this._logService = instaService.invokeFunction(accessor => accessor.get(ILogService)); @@ -76,38 +148,8 @@ export class ExtensionHostMain { this._extensionService = instaService.invokeFunction(accessor => accessor.get(IExtHostExtensionService)); this._extensionService.initialize(); - // error forwarding and stack trace scanning - Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) - const extensionErrors = new WeakMap(); - this._extensionService.getExtensionPathIndex().then(map => { - (Error).prepareStackTrace = (error: Error, stackTrace: errors.V8CallSite[]) => { - let stackTraceMessage = ''; - let extension: IExtensionDescription | undefined; - let fileName: string; - for (const call of stackTrace) { - stackTraceMessage += `\n\tat ${call.toString()}`; - fileName = call.getFileName(); - if (!extension && fileName) { - extension = map.findSubstr(URI.file(fileName)); - } - - } - extensionErrors.set(error, extension); - return `${error.name || 'Error'}: ${error.message || ''}${stackTraceMessage}`; - }; - }); - - const mainThreadExtensions = this._rpcProtocol.getProxy(MainContext.MainThreadExtensionService); - const mainThreadErrors = this._rpcProtocol.getProxy(MainContext.MainThreadErrors); - errors.setUnexpectedErrorHandler(err => { - const data = errors.transformErrorForSerialization(err); - const extension = extensionErrors.get(err); - if (extension) { - mainThreadExtensions.$onExtensionRuntimeError(extension.identifier, data); - } else { - mainThreadErrors.$onUnexpectedError(data); - } - }); + // install error handler that is extension-aware + instaService.invokeFunction(ErrorHandler.installFullHandler); } async asBrowserUri(uri: URI): Promise { diff --git a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts index 8264a9439a2..a8b3cb85a52 100644 --- a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts +++ b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts @@ -58,6 +58,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService'; import { assertType } from 'vs/base/common/types'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; function assertRejects(fn: () => Promise, message: string = 'Expected rejection') { return fn().then(() => assert.ok(false, message), _err => assert.ok(true)); @@ -167,7 +168,7 @@ suite('ExtHostLanguageFeatureCommands', function () { const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService(), new class extends mock() { }); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); - extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService); + extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService, new class extends mock() { }); rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost); mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, insta.createInstance(MainThreadLanguageFeatures, rpcProtocol)); diff --git a/src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts b/src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts index 17a22143276..69b6f50acc6 100644 --- a/src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts @@ -55,6 +55,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService'; import { CodeActionTriggerSource } from 'vs/editor/contrib/codeAction/browser/types'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; suite('ExtHostLanguageFeatures', function () { @@ -121,7 +122,7 @@ suite('ExtHostLanguageFeatures', function () { const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService(), new class extends mock() { }); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); - extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService); + extHost = new ExtHostLanguageFeatures(rpcProtocol, new URITransformerService(null), extHostDocuments, commands, diagnostics, new NullLogService(), NullApiDeprecationService, new class extends mock() { }); rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost); mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, rpcProtocol)); From f9415ab383a5c688767476271acef8038e68a141 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 13 Oct 2022 06:31:06 -0700 Subject: [PATCH 561/599] Add commented out debug helper for logging an image to the console --- .../terminal/browser/xterm/xtermTerminal.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 63fb42c42a9..553df339e49 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -66,6 +66,40 @@ function getFullBufferLineAsString(lineIndex: number, buffer: IBuffer): { lineDa return { lineData, lineIndex }; } + +// DEBUG: This helper can be used to draw image data to the console, it's commented out as we don't +// want to ship it, but this is very useful for investigating texture atlas issues. +// (console as any).image = (source: ImageData | HTMLCanvasElement, scale: number = 1) => { +// function getBox(width: number, height: number) { +// return { +// string: '+', +// style: 'font-size: 1px; padding: ' + Math.floor(height/2) + 'px ' + Math.floor(width/2) + 'px; line-height: ' + height + 'px;' +// }; +// } +// if (source instanceof HTMLCanvasElement) { +// source = source.getContext('2d')?.getImageData(0, 0, source.width, source.height)!; +// } +// const canvas = document.createElement('canvas'); +// canvas.width = source.width; +// canvas.height = source.height; +// const ctx = canvas.getContext('2d')!; +// ctx.putImageData(source, 0, 0); + +// const sw = source.width * scale; +// const sh = source.height * scale; +// const dim = getBox(sw, sh); +// console.log( +// `Image: ${source.width} x ${source.height}\n%c${dim.string}`, +// `${dim.style}background: url(${canvas.toDataURL()}); background-size: ${sw}px ${sh}px; background-repeat: no-repeat; color: transparent;` +// ); +// console.groupCollapsed('Zoomed'); +// console.log( +// `%c${dim.string}`, +// `${getBox(sw * 10, sh * 10).style}background: url(${canvas.toDataURL()}); background-size: ${sw * 10}px ${sh * 10}px; background-repeat: no-repeat; color: transparent; image-rendering: pixelated;-ms-interpolation-mode: nearest-neighbor;` +// ); +// console.groupEnd(); +// }; + /** * Wraps the xterm object with additional functionality. Interaction with the backing process is out * of the scope of this class. From 73e5ad2edfe1ed6410b6b16e1218461c37ce218a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 13 Oct 2022 15:35:59 +0200 Subject: [PATCH 562/599] avoid using string and boolean as variable name (#163550) --- src/vs/platform/environment/node/argv.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 0e5502fb67a..9f0f6e5bb06 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -209,8 +209,8 @@ export function parseArgs(args: string[], options: OptionDescriptions, err const firstArg = args.find(a => a.length > 0 && a[0] !== '-'); const alias: { [key: string]: string } = {}; - const string: string[] = ['_']; - const boolean: string[] = []; + const stringOptions: string[] = ['_']; + const booleanOptions: string[] = []; const globalOptions: OptionDescriptions = {}; let command: Subcommand | undefined = undefined; for (const optionId in options) { @@ -225,14 +225,14 @@ export function parseArgs(args: string[], options: OptionDescriptions, err } if (o.type === 'string' || o.type === 'string[]') { - string.push(optionId); + stringOptions.push(optionId); if (o.deprecates) { - string.push(...o.deprecates); + stringOptions.push(...o.deprecates); } } else if (o.type === 'boolean') { - boolean.push(optionId); + booleanOptions.push(optionId); if (o.deprecates) { - boolean.push(...o.deprecates); + booleanOptions.push(...o.deprecates); } } if (o.global) { @@ -255,7 +255,7 @@ export function parseArgs(args: string[], options: OptionDescriptions, err // remove aliases to avoid confusion - const parsedArgs = minimist(args, { string, boolean, alias }); + const parsedArgs = minimist(args, { string: stringOptions, boolean: booleanOptions, alias }); const cleanedArgs: any = {}; const remainingArgs: any = parsedArgs; From bf85140dfdb36293e8169d01ce5a3dbeff1d3f6c Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 13 Oct 2022 15:36:42 +0200 Subject: [PATCH 563/599] Fixes #162173 (#163548) --- .../browser/view/conflictActions.ts | 246 +++++++++-------- .../browser/view/fixedZoneWidget.ts | 5 +- .../mergeEditor/browser/view/mergeEditor.ts | 200 +++----------- .../mergeEditor/browser/view/viewZones.ts | 253 ++++++++++++++++++ 4 files changed, 421 insertions(+), 283 deletions(-) create mode 100644 src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts index 5e7cdcc2585..6e5658bee15 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/conflictActions.ts @@ -74,118 +74,32 @@ export class ConflictActionsFactory extends Disposable { }; } - addResultWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange): IDisposable { - function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { - return { - text: title, - action, - tooltip - }; - } - - const items = derived('items', reader => { - const state = viewModel.model.getState(modifiedBaseRange).read(reader); - const model = viewModel.model; - - const result: IContentWidgetAction[] = []; - - - if (state.conflicting) { - result.push({ - text: localize('manualResolution', "Manual Resolution"), - tooltip: localize('manualResolutionTooltip', "This conflict has been resolved manually."), - }); - } else if (state.isEmpty) { - result.push({ - text: localize('noChangesAccepted', 'No Changes Accepted'), - tooltip: localize( - 'noChangesAcceptedTooltip', - 'The current resolution of this conflict equals the common ancestor of both the right and left changes.' - ), - }); - - } else { - const labels = []; - if (state.input1) { - labels.push(model.input1.title); - } - if (state.input2) { - labels.push(model.input2.title); - } - if (state.input2First) { - labels.reverse(); - } - result.push({ - text: `${labels.join(' + ')}` - }); - } - - const stateToggles: IContentWidgetAction[] = []; - if (state.input1) { - result.push(command(localize('remove', "Remove {0}", model.input1.title), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - state.withInputValue(1, false), - true, - tx - ); - }); - }, localize('removeTooltip', "Remove {0} from the result document.", model.input1.title)), - ); - } - if (state.input2) { - result.push(command(localize('remove', "Remove {0}", model.input2.title), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - state.withInputValue(2, false), - true, - tx - ); - }); - }, localize('removeTooltip', "Remove {0} from the result document.", model.input2.title)), - ); - } - if (state.input2First) { - stateToggles.reverse(); - } - result.push(...stateToggles); - - - - if (state.conflicting) { - result.push( - command(localize('resetToBase', "Reset to base"), async () => { - transaction((tx) => { - model.setState( - modifiedBaseRange, - ModifiedBaseRangeState.default, - true, - tx - ); - }); - }, localize('resetToBaseTooltip', "Reset this conflict to the common ancestor of both the right and left changes.")), - ); - } - return result; - }); - + public createWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, items: IObservable, viewZoneIdsToCleanUp: string[]): IDisposable { const layoutInfo = this._getLayoutInfo(); + return new ActionsContentWidget( + this._editor, + viewZoneChangeAccessor, + lineNumber, + layoutInfo.codeLensHeight + 2, + this._styleClassName, + items, + viewZoneIdsToCleanUp, + ); + } +} - return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, layoutInfo.codeLensHeight + 2, this._styleClassName, items); +export class ActionsSource { + constructor( + private readonly viewModel: MergeEditorViewModel, + private readonly modifiedBaseRange: ModifiedBaseRange, + ) { } - addContentWidget(viewZoneChangeAccessor: IViewZoneChangeAccessor, lineNumber: number, viewModel: MergeEditorViewModel, modifiedBaseRange: ModifiedBaseRange, inputNumber: 1 | 2): IDisposable { - function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { - return { - text: title, - action, - tooltip, - }; - } + private getItemsInput(inputNumber: 1 | 2): IObservable { + return derived('items', reader => { + const viewModel = this.viewModel; + const modifiedBaseRange = this.modifiedBaseRange; - const items = derived('items', reader => { if (!viewModel.model.hasBaseRange(modifiedBaseRange)) { return []; } @@ -260,15 +174,120 @@ export class ConflictActionsFactory extends Disposable { } return result; }); - - const layoutInfo = this._getLayoutInfo(); - - return new ActionsContentWidget(this._editor, viewZoneChangeAccessor, lineNumber, layoutInfo.codeLensHeight + 2, this._styleClassName, items); } + + public readonly itemsInput1 = this.getItemsInput(1); + public readonly itemsInput2 = this.getItemsInput(2); + + public readonly resultItems = derived('items', reader => { + const viewModel = this.viewModel; + const modifiedBaseRange = this.modifiedBaseRange; + + const state = viewModel.model.getState(modifiedBaseRange).read(reader); + const model = viewModel.model; + + const result: IContentWidgetAction[] = []; + + + if (state.conflicting) { + result.push({ + text: localize('manualResolution', "Manual Resolution"), + tooltip: localize('manualResolutionTooltip', "This conflict has been resolved manually."), + }); + } else if (state.isEmpty) { + result.push({ + text: localize('noChangesAccepted', 'No Changes Accepted'), + tooltip: localize( + 'noChangesAcceptedTooltip', + 'The current resolution of this conflict equals the common ancestor of both the right and left changes.' + ), + }); + + } else { + const labels = []; + if (state.input1) { + labels.push(model.input1.title); + } + if (state.input2) { + labels.push(model.input2.title); + } + if (state.input2First) { + labels.reverse(); + } + result.push({ + text: `${labels.join(' + ')}` + }); + } + + const stateToggles: IContentWidgetAction[] = []; + if (state.input1) { + result.push(command(localize('remove', "Remove {0}", model.input1.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(1, false), + true, + tx + ); + }); + }, localize('removeTooltip', "Remove {0} from the result document.", model.input1.title)), + ); + } + if (state.input2) { + result.push(command(localize('remove', "Remove {0}", model.input2.title), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + state.withInputValue(2, false), + true, + tx + ); + }); + }, localize('removeTooltip', "Remove {0} from the result document.", model.input2.title)), + ); + } + if (state.input2First) { + stateToggles.reverse(); + } + result.push(...stateToggles); + + + + if (state.conflicting) { + result.push( + command(localize('resetToBase', "Reset to base"), async () => { + transaction((tx) => { + model.setState( + modifiedBaseRange, + ModifiedBaseRangeState.default, + true, + tx + ); + }); + }, localize('resetToBaseTooltip', "Reset this conflict to the common ancestor of both the right and left changes.")), + ); + } + return result; + }); + + public readonly isEmpty = derived('isEmpty', reader => { + return this.itemsInput1.read(reader).length + this.itemsInput2.read(reader).length + this.resultItems.read(reader).length === 0; + }); + + public readonly inputIsEmpty = derived('inputIsEmpty', reader => { + return this.itemsInput1.read(reader).length + this.itemsInput2.read(reader).length === 0; + }); } +function command(title: string, action: () => Promise, tooltip?: string): IContentWidgetAction { + return { + text: title, + action, + tooltip, + }; +} -interface IContentWidgetAction { +export interface IContentWidgetAction { text: string; tooltip?: string; action?: () => Promise; @@ -285,8 +304,9 @@ class ActionsContentWidget extends FixedZoneWidget { className: string, items: IObservable, + viewZoneIdsToCleanUp: string[], ) { - super(editor, viewZoneAccessor, afterLineNumber, height); + super(editor, viewZoneAccessor, afterLineNumber, height, viewZoneIdsToCleanUp); this.widgetDomNode.appendChild(this._domNode); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts index 12c2f930933..e761905679d 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/fixedZoneWidget.ts @@ -24,6 +24,7 @@ export abstract class FixedZoneWidget extends Disposable { viewZoneAccessor: IViewZoneChangeAccessor, afterLineNumber: number, height: number, + viewZoneIdsToCleanUp: string[], ) { super(); @@ -38,6 +39,7 @@ export abstract class FixedZoneWidget extends Disposable { this.widgetDomNode.style.top = `${top}px`; } }); + viewZoneIdsToCleanUp.push(this.viewZoneId); this.widgetDomNode.style.left = this.editor.getLayoutInfo().contentLeft + 'px'; @@ -46,9 +48,6 @@ export abstract class FixedZoneWidget extends Disposable { this._register({ dispose: () => { this.editor.removeOverlayWidget(this.overlayWidget); - this.editor.changeViewZones(accessor => { - accessor.removeZone(this.viewZoneId); - }); }, }); } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index bd4acc11980..6934099796b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -3,10 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, Dimension, reset } from 'vs/base/browser/dom'; +import { Dimension, reset } from 'vs/base/browser/dom'; import { Grid, GridNodeDescriptor, IView, SerializableGrid } from 'vs/base/browser/ui/grid/grid'; import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; -import { CompareResult, lastOrDefault } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Color } from 'vs/base/common/color'; import { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors'; @@ -38,24 +37,20 @@ import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions import { readTransientState, writeTransientState } from 'vs/workbench/contrib/codeEditor/browser/toggleWordWrap'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { IMergeEditorInputModel } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel'; -import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange'; -import { DetailedLineRangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model/mapping'; import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel'; -import { ModifiedBaseRange } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; -import { deepMerge, join, PersistentStore, thenIfNotDisposed } from 'vs/workbench/contrib/mergeEditor/browser/utils'; +import { deepMerge, PersistentStore, thenIfNotDisposed } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { BaseCodeEditorView } from 'vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView'; import { ScrollSynchronizer } from 'vs/workbench/contrib/mergeEditor/browser/view/scrollSynchronizer'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; +import { ViewZoneComputer } from 'vs/workbench/contrib/mergeEditor/browser/view/viewZones'; import { ctxIsMergeEditor, ctxMergeBaseUri, ctxMergeEditorLayout, ctxMergeEditorShowBase, ctxMergeEditorShowBaseAtTop, ctxMergeEditorShowNonConflictingChanges, ctxMergeResultUri, MergeEditorLayoutKind } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorResolverService, MergeEditorInputFactoryFunction, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import './colors'; -import { ConflictActionsFactory } from './conflictActions'; import { InputCodeEditorView } from './editors/inputCodeEditorView'; import { ResultCodeEditorView } from './editors/resultCodeEditorView'; -import { getAlignments } from './lineAlignment'; export class MergeEditor extends AbstractTextEditor { @@ -97,9 +92,11 @@ export class MergeEditor extends AbstractTextEditor { return !!this._configurationService.getValue('mergeEditor.writableInputs'); } - private readonly conflictActionsFactoryInput1 = new ConflictActionsFactory(this.input1View.editor); - private readonly conflictActionsFactoryInput2 = new ConflictActionsFactory(this.input2View.editor); - private readonly conflictActionsFactoryResult = new ConflictActionsFactory(this.inputResultView.editor); + private readonly viewZoneComputer = new ViewZoneComputer( + this.input1View.editor, + this.input2View.editor, + this.inputResultView.editor, + ); protected readonly codeLensesVisible = observableFromEvent( this.configurationService.onDidChangeConfiguration, @@ -351,32 +348,38 @@ export class MergeEditor extends AbstractTextEditor { resultViewZoneAccessor: IViewZoneChangeAccessor, shouldAlignResult: boolean, ): IDisposable { - let input1LinesAdded = 0; - let input2LinesAdded = 0; - let baseLinesAdded = 0; - let resultLinesAdded = 0; - - const model = viewModel.model; - const input1ViewZoneIds: string[] = []; const input2ViewZoneIds: string[] = []; const baseViewZoneIds: string[] = []; const resultViewZoneIds: string[] = []; - const resultDiffs = model.baseResultDiffs.read(reader); - const baseRangeWithStoreAndTouchingDiffs = join( - model.modifiedBaseRanges.read(reader), - resultDiffs, - (baseRange, diff) => - baseRange.baseRange.touches(diff.inputRange) - ? CompareResult.neitherLessOrGreaterThan - : LineRange.compareByStart( - baseRange.baseRange, - diff.inputRange - ) - ); + const viewZones = this.viewZoneComputer.computeViewZones(reader, viewModel, { + codeLensesVisible: this.codeLensesVisible.read(reader), + showNonConflictingChanges: this.showNonConflictingChanges.read(reader), + shouldAlignBase, + shouldAlignResult, + }); const disposableStore = new DisposableStore(); + + if (baseViewZoneAccessor) { + for (const v of viewZones.baseViewZones) { + v.create(baseViewZoneAccessor, baseViewZoneIds, disposableStore); + } + } + + for (const v of viewZones.resultViewZones) { + v.create(resultViewZoneAccessor, resultViewZoneIds, disposableStore); + } + + for (const v of viewZones.input1ViewZones) { + v.create(input1ViewZoneAccessor, input1ViewZoneIds, disposableStore); + } + + for (const v of viewZones.input2ViewZones) { + v.create(input2ViewZoneAccessor, input2ViewZoneIds, disposableStore); + } + disposableStore.add({ dispose: () => { input1Editor.changeViewZones(a => { @@ -402,143 +405,6 @@ export class MergeEditor extends AbstractTextEditor { } }); - const shouldShowCodeLenses = this.codeLensesVisible.read(reader); - const showNonConflictingChanges = this.showNonConflictingChanges.read(reader); - - let lastModifiedBaseRange: ModifiedBaseRange | undefined = undefined; - let lastBaseResultDiff: DetailedLineRangeMapping | undefined = undefined; - for (const m of baseRangeWithStoreAndTouchingDiffs) { - if (shouldShowCodeLenses && m.left && (m.left.isConflicting || showNonConflictingChanges || !model.isHandled(m.left).read(reader))) { - disposableStore.add( - this.conflictActionsFactoryInput1.addContentWidget( - input1ViewZoneAccessor, m.left.input1Range.startLineNumber - 1, viewModel, m.left, this.input1View.inputNumber - ) - ); - disposableStore.add( - this.conflictActionsFactoryInput2.addContentWidget( - input2ViewZoneAccessor, m.left.input2Range.startLineNumber - 1, viewModel, m.left, this.input2View.inputNumber - ) - ); - - const afterLineNumber = m.left.baseRange.startLineNumber + (lastBaseResultDiff?.resultingDeltaFromOriginalToModified ?? 0) - 1; - - disposableStore.add(this.conflictActionsFactoryResult.addResultWidget(resultViewZoneAccessor, afterLineNumber, viewModel, m.left)); - - if (shouldAlignBase && baseViewZoneAccessor) { - baseViewZoneIds.push(baseViewZoneAccessor.addZone({ - afterLineNumber: m.left.baseRange.startLineNumber - 1, - heightInPx: 16, - domNode: $('div.conflict-actions-placeholder'), - })); - } - } - - interface LineAlignment { - baseLine: number; - input1Line?: number; - input2Line?: number; - resultLine?: number; - } - - const lastResultDiff = lastOrDefault(m.rights)!; - if (lastResultDiff) { - lastBaseResultDiff = lastResultDiff; - } - let alignedLines: LineAlignment[]; - if (m.left) { - alignedLines = getAlignments(m.left).map(a => ({ - input1Line: a[0], - baseLine: a[1], - input2Line: a[2], - resultLine: undefined, - })); - - lastModifiedBaseRange = m.left; - // This is a total hack. - alignedLines[alignedLines.length - 1].resultLine = - m.left.baseRange.endLineNumberExclusive - + (lastBaseResultDiff ? lastBaseResultDiff.resultingDeltaFromOriginalToModified : 0); - - } else { - alignedLines = [{ - baseLine: lastResultDiff.inputRange.endLineNumberExclusive, - input1Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input1Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), - input2Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input2Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), - resultLine: lastResultDiff.outputRange.endLineNumberExclusive, - }]; - } - - for (const { input1Line, baseLine, input2Line, resultLine } of alignedLines) { - if (!shouldAlignBase && (input1Line === undefined || input2Line === undefined)) { - continue; - } - - const input1Line_ = - input1Line !== undefined ? input1Line + input1LinesAdded : -1; - const input2Line_ = - input2Line !== undefined ? input2Line + input2LinesAdded : -1; - const baseLine_ = baseLine + baseLinesAdded; - const resultLine_ = resultLine !== undefined ? resultLine + resultLinesAdded : -1; - - const max = Math.max(shouldAlignBase ? baseLine_ : 0, input1Line_, input2Line_, shouldAlignResult ? resultLine_ : 0); - - if (input1Line !== undefined) { - const diffInput1 = max - input1Line_; - if (diffInput1 > 0) { - input1ViewZoneIds.push( - input1ViewZoneAccessor.addZone({ - afterLineNumber: input1Line - 1, - heightInLines: diffInput1, - domNode: $('div.diagonal-fill'), - }) - ); - input1LinesAdded += diffInput1; - } - } - - if (input2Line !== undefined) { - const diffInput2 = max - input2Line_; - if (diffInput2 > 0) { - input2ViewZoneIds.push( - input2ViewZoneAccessor.addZone({ - afterLineNumber: input2Line - 1, - heightInLines: diffInput2, - domNode: $('div.diagonal-fill'), - }) - ); - input2LinesAdded += diffInput2; - } - } - - if (shouldAlignBase && baseViewZoneAccessor) { - const diffBase = max - baseLine_; - if (diffBase > 0) { - baseViewZoneIds.push( - baseViewZoneAccessor.addZone({ - afterLineNumber: baseLine - 1, - heightInLines: diffBase, - domNode: $('div.diagonal-fill'), - }) - ); - baseLinesAdded += diffBase; - } - } - - if (shouldAlignResult && resultViewZoneAccessor && resultLine !== undefined) { - const diffResult = max - resultLine_; - if (diffResult > 0) { - resultViewZoneIds.push( - resultViewZoneAccessor.addZone({ - afterLineNumber: resultLine - 1, - heightInLines: diffResult, - domNode: $('div.diagonal-fill'), - }) - ); - resultLinesAdded += diffResult; - } - } - } - } return disposableStore; } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts new file mode 100644 index 00000000000..ce3ec967375 --- /dev/null +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts @@ -0,0 +1,253 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { $ } from 'vs/base/browser/dom'; +import { CompareResult, lastOrDefault } from 'vs/base/common/arrays'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IObservable, IReader } from 'vs/base/common/observable'; +import { ICodeEditor, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; +import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange'; +import { DetailedLineRangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model/mapping'; +import { ModifiedBaseRange } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; +import { join } from 'vs/workbench/contrib/mergeEditor/browser/utils'; +import { ActionsSource, ConflictActionsFactory, IContentWidgetAction } from 'vs/workbench/contrib/mergeEditor/browser/view/conflictActions'; +import { getAlignments } from 'vs/workbench/contrib/mergeEditor/browser/view/lineAlignment'; +import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; + +export class ViewZoneComputer { + private readonly conflictActionsFactoryInput1 = new ConflictActionsFactory(this.input1Editor); + private readonly conflictActionsFactoryInput2 = new ConflictActionsFactory(this.input2Editor); + private readonly conflictActionsFactoryResult = new ConflictActionsFactory(this.resultEditor); + + constructor( + private readonly input1Editor: ICodeEditor, + private readonly input2Editor: ICodeEditor, + private readonly resultEditor: ICodeEditor, + ) { } + + public computeViewZones( + reader: IReader, + viewModel: MergeEditorViewModel, + options: { + shouldAlignResult: boolean; + shouldAlignBase: boolean; + codeLensesVisible: boolean; + showNonConflictingChanges: boolean; + } + ): MergeEditorViewZones { + let input1LinesAdded = 0; + let input2LinesAdded = 0; + let baseLinesAdded = 0; + let resultLinesAdded = 0; + + const input1ViewZones: MergeEditorViewZone[] = []; + const input2ViewZones: MergeEditorViewZone[] = []; + const baseViewZones: MergeEditorViewZone[] = []; + const resultViewZones: MergeEditorViewZone[] = []; + + const model = viewModel.model; + + const resultDiffs = model.baseResultDiffs.read(reader); + const baseRangeWithStoreAndTouchingDiffs = join( + model.modifiedBaseRanges.read(reader), + resultDiffs, + (baseRange, diff) => + baseRange.baseRange.touches(diff.inputRange) + ? CompareResult.neitherLessOrGreaterThan + : LineRange.compareByStart( + baseRange.baseRange, + diff.inputRange + ) + ); + + const shouldShowCodeLenses = options.codeLensesVisible; + const showNonConflictingChanges = options.showNonConflictingChanges; + + let lastModifiedBaseRange: ModifiedBaseRange | undefined = undefined; + let lastBaseResultDiff: DetailedLineRangeMapping | undefined = undefined; + for (const m of baseRangeWithStoreAndTouchingDiffs) { + if (shouldShowCodeLenses && m.left && (m.left.isConflicting || showNonConflictingChanges || !model.isHandled(m.left).read(reader))) { + const actions = new ActionsSource(viewModel, m.left); + if (options.shouldAlignResult || !actions.inputIsEmpty.read(reader)) { + input1ViewZones.push(new CommandViewZone(this.conflictActionsFactoryInput1, m.left.input1Range.startLineNumber - 1, actions.itemsInput1)); + input2ViewZones.push(new CommandViewZone(this.conflictActionsFactoryInput2, m.left.input2Range.startLineNumber - 1, actions.itemsInput2)); + if (options.shouldAlignBase) { + baseViewZones.push(new Placeholder(m.left.baseRange.startLineNumber - 1, 16)); + } + } + const afterLineNumber = m.left.baseRange.startLineNumber + (lastBaseResultDiff?.resultingDeltaFromOriginalToModified ?? 0) - 1; + resultViewZones.push(new CommandViewZone(this.conflictActionsFactoryResult, afterLineNumber, actions.resultItems)); + + } + + const lastResultDiff = lastOrDefault(m.rights)!; + if (lastResultDiff) { + lastBaseResultDiff = lastResultDiff; + } + let alignedLines: LineAlignment[]; + if (m.left) { + alignedLines = getAlignments(m.left).map(a => ({ + input1Line: a[0], + baseLine: a[1], + input2Line: a[2], + resultLine: undefined, + })); + + lastModifiedBaseRange = m.left; + // This is a total hack. + alignedLines[alignedLines.length - 1].resultLine = + m.left.baseRange.endLineNumberExclusive + + (lastBaseResultDiff ? lastBaseResultDiff.resultingDeltaFromOriginalToModified : 0); + + } else { + alignedLines = [{ + baseLine: lastResultDiff.inputRange.endLineNumberExclusive, + input1Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input1Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), + input2Line: lastResultDiff.inputRange.endLineNumberExclusive + (lastModifiedBaseRange ? (lastModifiedBaseRange.input2Range.endLineNumberExclusive - lastModifiedBaseRange.baseRange.endLineNumberExclusive) : 0), + resultLine: lastResultDiff.outputRange.endLineNumberExclusive, + }]; + } + + for (const { input1Line, baseLine, input2Line, resultLine } of alignedLines) { + if (!options.shouldAlignBase && (input1Line === undefined || input2Line === undefined)) { + continue; + } + + const input1Line_ = + input1Line !== undefined ? input1Line + input1LinesAdded : -1; + const input2Line_ = + input2Line !== undefined ? input2Line + input2LinesAdded : -1; + const baseLine_ = baseLine + baseLinesAdded; + const resultLine_ = resultLine !== undefined ? resultLine + resultLinesAdded : -1; + + const max = Math.max(options.shouldAlignBase ? baseLine_ : 0, input1Line_, input2Line_, options.shouldAlignResult ? resultLine_ : 0); + + if (input1Line !== undefined) { + const diffInput1 = max - input1Line_; + if (diffInput1 > 0) { + input1ViewZones.push(new Spacer(input1Line - 1, diffInput1)); + input1LinesAdded += diffInput1; + } + } + + if (input2Line !== undefined) { + const diffInput2 = max - input2Line_; + if (diffInput2 > 0) { + input2ViewZones.push(new Spacer(input2Line - 1, diffInput2)); + input2LinesAdded += diffInput2; + } + } + + if (options.shouldAlignBase) { + const diffBase = max - baseLine_; + if (diffBase > 0) { + baseViewZones.push(new Spacer(baseLine - 1, diffBase)); + baseLinesAdded += diffBase; + } + } + + if (options.shouldAlignResult && resultLine !== undefined) { + const diffResult = max - resultLine_; + if (diffResult > 0) { + resultViewZones.push(new Spacer(resultLine - 1, diffResult)); + resultLinesAdded += diffResult; + } + } + } + } + + return new MergeEditorViewZones(input1ViewZones, input2ViewZones, baseViewZones, resultViewZones); + } +} + +interface LineAlignment { + baseLine: number; + input1Line?: number; + input2Line?: number; + resultLine?: number; +} + +export class MergeEditorViewZones { + constructor( + public readonly input1ViewZones: readonly MergeEditorViewZone[], + public readonly input2ViewZones: readonly MergeEditorViewZone[], + public readonly baseViewZones: readonly MergeEditorViewZone[], + public readonly resultViewZones: readonly MergeEditorViewZone[], + ) { } +} + +/** + * This is an abstract class to create various editor view zones. +*/ +export abstract class MergeEditorViewZone { + abstract create(viewZoneChangeAccessor: IViewZoneChangeAccessor, viewZoneIdsToCleanUp: string[], disposableStore: DisposableStore): void; +} + +class Spacer extends MergeEditorViewZone { + constructor( + private readonly afterLineNumber: number, + private readonly heightInLines: number + ) { + super(); + } + + override create( + viewZoneChangeAccessor: IViewZoneChangeAccessor, + viewZoneIdsToCleanUp: string[], + disposableStore: DisposableStore + ): void { + viewZoneIdsToCleanUp.push( + viewZoneChangeAccessor.addZone({ + afterLineNumber: this.afterLineNumber, + heightInLines: this.heightInLines, + domNode: $('div.diagonal-fill'), + }) + ); + } +} + +class Placeholder extends MergeEditorViewZone { + constructor( + private readonly afterLineNumber: number, + private readonly heightPx: number + ) { + super(); + } + + override create( + viewZoneChangeAccessor: IViewZoneChangeAccessor, + viewZoneIdsToCleanUp: string[], + disposableStore: DisposableStore + ): void { + viewZoneIdsToCleanUp.push( + viewZoneChangeAccessor.addZone({ + afterLineNumber: this.afterLineNumber, + heightInPx: this.heightPx, + domNode: $('div.conflict-actions-placeholder'), + }) + ); + } +} + +class CommandViewZone extends MergeEditorViewZone { + constructor( + private readonly conflictActionsFactory: ConflictActionsFactory, + private readonly lineNumber: number, + private readonly items: IObservable, + ) { + super(); + } + + override create(viewZoneChangeAccessor: IViewZoneChangeAccessor, viewZoneIdsToCleanUp: string[], disposableStore: DisposableStore): void { + disposableStore.add( + this.conflictActionsFactory.createWidget( + viewZoneChangeAccessor, + this.lineNumber, + this.items, + viewZoneIdsToCleanUp, + ) + ); + } +} From 1436dd71bdc59ac423bf7ccfc1b07132af7fba75 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 13 Oct 2022 16:42:45 +0200 Subject: [PATCH 564/599] Implements #160292: diffing against base (#163553) --- .../browser/mergeEditor.contribution.ts | 5 +++ .../mergeEditor/browser/view/colors.ts | 12 +++++ .../view/editors/baseCodeEditorView.ts | 44 ++++++++++++++++++- .../browser/view/editors/codeEditorView.ts | 5 +++ .../view/editors/inputCodeEditorView.ts | 20 +++++---- .../browser/view/media/mergeEditor.css | 22 ++++++++-- .../mergeEditor/browser/view/viewModel.ts | 10 +++++ 7 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index eb90cc8b867..7218c3cf281 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -50,6 +50,11 @@ Registry.as(Extensions.Configuration).registerConfigurat localize('diffAlgorithm.experimental', "Uses an experimental diffing algorithm."), ] }, + 'mergeEditor.showDeletionMarkers': { + type: 'boolean', + default: true, + description: 'Controls if deletions in base or one of the inputs should be indicated by a vertical bar.', + }, } }); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/colors.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/colors.ts index 6e94f727eb0..78991abe8d6 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/colors.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/colors.ts @@ -18,6 +18,18 @@ export const diffWord = registerColor( localize('mergeEditor.change.word.background', 'The background color for word changes.') ); +export const diffBase = registerColor( + 'mergeEditor.changeBase.background', + { dark: '#4B1818FF', light: '#FFCCCCFF', hcDark: '#4B1818FF', hcLight: '#FFCCCCFF', }, + localize('mergeEditor.changeBase.background', 'The background color for changes in base.') +); + +export const diffWordBase = registerColor( + 'mergeEditor.changeBase.word.background', + { dark: '#6F1313FF', light: '#FFA3A3FF', hcDark: '#6F1313FF', hcLight: '#FFA3A3FF', }, + localize('mergeEditor.changeBase.word.background', 'The background color for word changes in base.') +); + export const conflictBorderUnhandledUnfocused = registerColor( 'mergeEditor.conflict.unhandledUnfocused.border', { dark: '#ffa6007a', light: '#ffa6007a', hcDark: '#ffa6007a', hcLight: '#ffa6007a', }, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts index b4084701ac3..e318c62d385 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { reset } from 'vs/base/browser/dom'; +import { h, reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { BugIndicatingError } from 'vs/base/common/errors'; import { Iterable } from 'vs/base/common/iterator'; @@ -56,6 +56,16 @@ export class BaseCodeEditorView extends CodeEditorView { } this.editor.setModel(vm.model.base); reset(this.htmlElements.title, ...renderLabelWithIcons(localize('base', 'Base'))); + + const baseShowDiffAgainst = vm.baseShowDiffAgainst.read(reader); + + let node: Node | undefined = undefined; + if (baseShowDiffAgainst) { + const label = localize('compareWith', 'Comparing with {0}', baseShowDiffAgainst === 1 ? vm.model.input1.title : vm.model.input2.title); + const tooltip = localize('compareWithTooltip', 'Differences are highlighted with a background color.'); + node = h('span', { title: tooltip }, [label]).root; + } + reset(this.htmlElements.description, ...(node ? [node] : [])); }) ); @@ -72,6 +82,7 @@ export class BaseCodeEditorView extends CodeEditorView { const activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader); const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + const showDeletionMarkers = this.showDeletionMarkers.read(reader); const result: IModelDeltaDecoration[] = []; for (const modifiedBaseRange of model.modifiedBaseRanges.read(reader)) { @@ -95,6 +106,37 @@ export class BaseCodeEditorView extends CodeEditorView { } blockClassNames.push('base'); + const inputToDiffAgainst = viewModel.baseShowDiffAgainst.read(reader); + + if (inputToDiffAgainst) { + for (const diff of modifiedBaseRange.getInputDiffs(inputToDiffAgainst)) { + const range = diff.inputRange.toInclusiveRange(); + if (range) { + result.push({ + range, + options: { + className: `merge-editor-diff base`, + description: 'Merge Editor', + isWholeLine: true, + } + }); + } + + for (const diff2 of diff.rangeMappings) { + if (showDeletionMarkers || !diff2.inputRange.isEmpty()) { + result.push({ + range: diff2.inputRange, + options: { + className: diff2.inputRange.isEmpty() ? `merge-editor-diff-empty-word base` : `merge-editor-diff-word base`, + description: 'Merge Editor', + showIfCollapsed: true, + }, + }); + } + } + } + } + result.push({ range: range.toInclusiveRangeOrEmpty(), options: { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index df40fc8e55c..4ddab3078e0 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -64,6 +64,11 @@ export abstract class CodeEditorView extends Disposable { () => /** @description checkboxesVisible */ this.configurationService.getValue('mergeEditor.showCheckboxes') ?? false ); + protected readonly showDeletionMarkers = observableFromEvent( + this.configurationService.onDidChangeConfiguration, + () => /** @description showDeletionMarkers */ this.configurationService.getValue('mergeEditor.showDeletionMarkers') + ); + public readonly editor = this.instantiationService.createInstance( CodeEditorWidget, this.htmlElements.editor, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index dfb5b90a382..684ec7d9067 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -130,6 +130,7 @@ export class InputCodeEditorView extends CodeEditorView { const result = new Array(); const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + const showDeletionMarkers = this.showDeletionMarkers.read(reader); for (const modifiedBaseRange of model.modifiedBaseRanges.read(reader)) { const range = modifiedBaseRange.getInputRange(this.inputNumber); @@ -148,7 +149,7 @@ export class InputCodeEditorView extends CodeEditorView { if (modifiedBaseRange.isConflicting) { blockClassNames.push('conflicting'); } - const inputClassName = this.inputNumber === 1 ? 'input1' : 'input2'; + const inputClassName = this.inputNumber === 1 ? 'input 1' : 'input 2'; blockClassNames.push(inputClassName); if (!modifiedBaseRange.isConflicting && !showNonConflictingChanges && isHandled) { @@ -190,13 +191,16 @@ export class InputCodeEditorView extends CodeEditorView { if (diff.rangeMappings) { for (const d of diff.rangeMappings) { - result.push({ - range: d.outputRange, - options: { - className: `merge-editor-diff-word ${inputClassName}`, - description: 'Merge Editor' - } - }); + if (showDeletionMarkers || !d.outputRange.isEmpty()) { + result.push({ + range: d.outputRange, + options: { + className: d.outputRange.isEmpty() ? `merge-editor-diff-empty-word ${inputClassName}` : `merge-editor-diff-word ${inputClassName}`, + description: 'Merge Editor', + showIfCollapsed: true, + } + }); + } } } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css index 18d6b104934..63172058846 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css @@ -226,10 +226,6 @@ border: 1px solid var(--vscode-mergeEditor-conflict-unhandledFocused-border); } -.merge-conflict-input-selection { - background-color: red; -} - .merge-editor-conflict-actions { margin: 0px 3px; overflow: hidden; @@ -272,3 +268,21 @@ .fixed-zone-widget { width: 100%; } + +.merge-editor-diff-empty-word.base { + margin-left: 3px; + border-left: solid var(--vscode-mergeEditor-changeBase-word-background) 3px; +} + +.merge-editor-diff-empty-word.input { + margin-left: 3px; + border-left: solid var(--vscode-mergeEditor-change-word-background) 3px; +} + +.merge-editor-diff-word.base { + background-color: var(--vscode-mergeEditor-changeBase-word-background); +} + +.merge-editor-diff.base { + background-color: var(--vscode-mergeEditor-changeBase-background); +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts index b4910bbd219..2e71fba0a29 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts @@ -59,6 +59,16 @@ export class MergeEditorViewModel extends Disposable { return view ? { view, counter: this.counter++ } : lastValue || { view: undefined, counter: this.counter++ }; }); + public readonly baseShowDiffAgainst = derived<1 | 2 | undefined>('baseShowDiffAgainst', reader => { + const lastFocusedEditor = this.lastFocusedEditor.read(reader); + if (lastFocusedEditor.view === this.inputCodeEditorView1) { + return 1; + } else if (lastFocusedEditor.view === this.inputCodeEditorView2) { + return 2; + } + return undefined; + }); + public readonly selectionInBase = derived('selectionInBase', (reader) => { const sourceEditor = this.lastFocusedEditor.read(reader).view; if (!sourceEditor) { From af4b19dd24bb8222255b323d7d112001e74a1f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 13 Oct 2022 07:57:36 -0700 Subject: [PATCH 565/599] make eager service registration explicit (#163558) Related-to: #159178 --- .../services/extensions/browser/extensionUrlHandler.ts | 4 ++-- src/vs/workbench/services/update/browser/updateService.ts | 4 ++-- src/vs/workbench/services/url/electron-sandbox/urlService.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index 13924b49ef0..2ecae8e653c 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -18,7 +18,7 @@ import { IURLHandler, IURLService, IOpenURLOptions } from 'vs/platform/url/commo import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IExtensionService, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -382,7 +382,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } } -registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler, false); +registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler, InstantiationType.Eager); /** * This class handles URLs before `ExtensionUrlHandler` is instantiated. diff --git a/src/vs/workbench/services/update/browser/updateService.ts b/src/vs/workbench/services/update/browser/updateService.ts index 1087a9ce29b..61a3be52e13 100644 --- a/src/vs/workbench/services/update/browser/updateService.ts +++ b/src/vs/workbench/services/update/browser/updateService.ts @@ -5,7 +5,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IUpdateService, State, UpdateType } from 'vs/platform/update/common/update'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -96,4 +96,4 @@ export class BrowserUpdateService extends Disposable implements IUpdateService { } } -registerSingleton(IUpdateService, BrowserUpdateService, false); +registerSingleton(IUpdateService, BrowserUpdateService, InstantiationType.Eager); diff --git a/src/vs/workbench/services/url/electron-sandbox/urlService.ts b/src/vs/workbench/services/url/electron-sandbox/urlService.ts index 7bc2e4723c7..2ae2624e9f3 100644 --- a/src/vs/workbench/services/url/electron-sandbox/urlService.ts +++ b/src/vs/workbench/services/url/electron-sandbox/urlService.ts @@ -9,7 +9,7 @@ import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { IOpenerService, IOpener, matchesScheme } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { NativeURLService } from 'vs/platform/url/common/urlService'; @@ -73,4 +73,4 @@ export class RelayURLService extends NativeURLService implements IURLHandler, IO } } -registerSingleton(IURLService, RelayURLService, false); +registerSingleton(IURLService, RelayURLService, InstantiationType.Eager); From 2b50ab06b1636a38f6bec3dfb2c8f471374a2cba Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 13 Oct 2022 18:21:47 +0200 Subject: [PATCH 566/599] support passing extension log level from cli (#163566) --- src/vs/platform/environment/common/argv.ts | 2 +- .../environment/common/environment.ts | 1 + .../environment/common/environmentService.ts | 17 +++- src/vs/platform/environment/node/argv.ts | 2 +- src/vs/platform/log/common/fileLog.ts | 2 +- src/vs/platform/log/common/log.ts | 19 +---- src/vs/platform/log/common/logIpc.ts | 2 +- src/vs/platform/log/node/loggerService.ts | 2 +- .../server/node/serverEnvironmentService.ts | 2 +- .../api/common/extHostLoggerService.ts | 2 +- src/vs/workbench/api/common/extHostOutput.ts | 25 ++++-- src/vs/workbench/browser/web.api.ts | 5 ++ .../contrib/logs/common/logsActions.ts | 81 +++++++++++-------- .../environment/browser/environmentService.ts | 24 +++++- .../browser/webWorkerExtensionHost.ts | 1 + .../common/extensionHostProtocol.ts | 1 + .../extensions/common/remoteExtensionHost.ts | 3 +- .../localProcessExtensionHost.ts | 1 + 18 files changed, 125 insertions(+), 67 deletions(-) diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index 9d6f717b64e..0ef429408f2 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -48,7 +48,7 @@ export interface NativeParsedArgs { 'trace-category-filter'?: string; 'trace-options'?: string; 'open-devtools'?: boolean; - log?: string; + log?: string[]; logExtensionHostCommunication?: boolean; 'extensions-dir'?: string; 'extensions-download-dir'?: string; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 8ecac574e85..3953e06a708 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -81,6 +81,7 @@ export interface IEnvironmentService { // --- logging logsPath: string; logLevel?: string; + extensionLogLevel?: [string, string][]; verbose: boolean; isBuilt: boolean; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index 8ff58181a62..934a8657683 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -14,6 +14,8 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ExtensionKind, IDebugParams, IExtensionHostDebugParams, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { IProductService } from 'vs/platform/product/common/productService'; +export const EXTENSION_IDENTIFIER_WITH_LOG_REGEX = /^([^.]+\..+):(.+)$/; + export interface INativeEnvironmentPaths { /** @@ -216,7 +218,20 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron get isBuilt(): boolean { return !env['VSCODE_DEV']; } get verbose(): boolean { return !!this.args.verbose; } - get logLevel(): string | undefined { return this.args.log; } + + @memoize + get logLevel(): string | undefined { return this.args.log?.find(entry => !EXTENSION_IDENTIFIER_WITH_LOG_REGEX.test(entry)); } + @memoize + get extensionLogLevel(): [string, string][] | undefined { + const result: [string, string][] = []; + for (const entry of this.args.log || []) { + const matches = EXTENSION_IDENTIFIER_WITH_LOG_REGEX.exec(entry); + if (matches && matches[1] && matches[2]) { + result.push([matches[1], matches[2]]); + } + } + return result.length ? result : undefined; + } @memoize get serviceMachineIdResource(): URI { return joinPath(URI.file(this.userDataPath), 'machineid'); } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 9f0f6e5bb06..9ea98d94eb4 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -93,7 +93,7 @@ export const OPTIONS: OptionDescriptions> = { 'version': { type: 'boolean', cat: 't', alias: 'v', description: localize('version', "Print version.") }, 'verbose': { type: 'boolean', cat: 't', global: true, description: localize('verbose', "Print verbose output (implies --wait).") }, - 'log': { type: 'string', cat: 't', args: 'level', global: true, description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, + 'log': { type: 'string[]', cat: 't', args: 'level', global: true, description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'. You can also configure the log level of an extension by passing extension id and log level in the following format: '${publisher}.${name}:${logLevel}'. For example: 'vscode.csharp:trace'. Can receive one or more such entries.") }, 'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup.") }, 'prof-append-timers': { type: 'string' }, diff --git a/src/vs/platform/log/common/fileLog.ts b/src/vs/platform/log/common/fileLog.ts index 4e346d74d0f..e16363b8b6e 100644 --- a/src/vs/platform/log/common/fileLog.ts +++ b/src/vs/platform/log/common/fileLog.ts @@ -147,7 +147,7 @@ export class FileLoggerService extends AbstractLoggerService implements ILoggerS @ILogService logService: ILogService, @IFileService private readonly fileService: IFileService, ) { - super(logService.getLevel(), logService.onDidChangeLogLevel, []); + super(logService.getLevel(), logService.onDidChangeLogLevel); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 8a6d33c5c4a..47f09907617 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -112,7 +112,7 @@ export interface ILoggerService { /** * Creates a logger, or gets one if it already exists. */ - createLogger(resource: URI, options?: ILoggerOptions): ILogger; + createLogger(resource: URI, options?: ILoggerOptions, logLevel?: LogLevel): ILogger; /** * Gets an existing logger, if any. @@ -128,12 +128,6 @@ export interface ILoggerService { * Get log level for a logger. */ getLogLevel(resource: URI): LogLevel | undefined; - - /** - * Get default log level for a logger with given name. - * @param name logger name - */ - getDefaultLogLevel(name: string): LogLevel; } export abstract class AbstractLogger extends Disposable { @@ -535,7 +529,6 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge constructor( private logLevel: LogLevel, onDidChangeLogLevel: Event, - private readonly defaultLogLevels: [string, LogLevel][] ) { super(); this._register(onDidChangeLogLevel(logLevel => this.setLevel(logLevel))); @@ -549,11 +542,11 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge return this.loggerItems.get(resource)?.logger; } - createLogger(resource: URI, options?: ILoggerOptions): ILogger { + createLogger(resource: URI, options?: ILoggerOptions, logLevel?: LogLevel): ILogger { let logger = this.loggerItems.get(resource)?.logger; if (!logger) { - const logLevel = options?.always ? LogLevel.Trace : undefined; - logger = this.doCreateLogger(resource, logLevel ?? (options?.name ? this.getDefaultLogLevel(options?.name) : this.logLevel), options); + logLevel = options?.always ? LogLevel.Trace : logLevel; + logger = this.doCreateLogger(resource, logLevel ?? this.logLevel, options); this.loggerItems.set(resource, { logger, logLevel }); } return logger; @@ -587,10 +580,6 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge return logger?.logLevel; } - getDefaultLogLevel(name: string): LogLevel { - return this.defaultLogLevels.find(([loggerName]) => loggerName === name)?.[1] ?? this.logLevel; - } - override dispose(): void { this.loggerItems.forEach(({ logger }) => logger.dispose()); this.loggerItems.clear(); diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index a5ef50d8493..84e6b347ddb 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -111,7 +111,7 @@ export class LoggerChannel implements IServerChannel { export class LoggerChannelClient extends AbstractLoggerService implements ILoggerService { constructor(logLevel: LogLevel, onDidChangeLogLevel: Event, private readonly channel: IChannel) { - super(logLevel, onDidChangeLogLevel, []); + super(logLevel, onDidChangeLogLevel); } createConsoleMainLogger(): ILogger { diff --git a/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts index a7cc23f9e86..9e1c2e72581 100644 --- a/src/vs/platform/log/node/loggerService.ts +++ b/src/vs/platform/log/node/loggerService.ts @@ -13,7 +13,7 @@ export class LoggerService extends AbstractLoggerService implements ILoggerServi constructor( @ILogService logService: ILogService ) { - super(logService.getLevel(), logService.onDidChangeLogLevel, []); + super(logService.getLevel(), logService.onDidChangeLogLevel); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { diff --git a/src/vs/server/node/serverEnvironmentService.ts b/src/vs/server/node/serverEnvironmentService.ts index 646e3ae2af1..432344f146a 100644 --- a/src/vs/server/node/serverEnvironmentService.ts +++ b/src/vs/server/node/serverEnvironmentService.ts @@ -147,7 +147,7 @@ export interface ServerParsedArgs { 'disable-telemetry'?: boolean; 'file-watcher-polling'?: string; - 'log'?: string; + 'log'?: string[]; 'logsPath'?: string; 'force-disable-user-env'?: boolean; diff --git a/src/vs/workbench/api/common/extHostLoggerService.ts b/src/vs/workbench/api/common/extHostLoggerService.ts index b994b3cf890..47ec1627609 100644 --- a/src/vs/workbench/api/common/extHostLoggerService.ts +++ b/src/vs/workbench/api/common/extHostLoggerService.ts @@ -20,7 +20,7 @@ export class ExtHostLoggerService extends AbstractLoggerService implements ExtHo @IExtHostRpcService rpc: IExtHostRpcService, @IExtHostInitDataService initData: IExtHostInitDataService, ) { - super(initData.logLevel, Event.None, []); + super(initData.logLevel, Event.None); this._proxy = rpc.getProxy(MainContext.MainThreadLogger); } diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index ac01aeb7bce..3f1de6629f7 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -8,8 +8,8 @@ import type * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel, parseLogLevel } from 'vs/platform/log/common/log'; import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output'; import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; @@ -151,12 +151,13 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { if (isString(languageId) && !languageId.trim()) { throw new Error('illegal argument `languageId`. must not be empty'); } - const extHostOutputChannel = log ? this.doCreateLogOutputChannel(name, extension) : this.doCreateOutputChannel(name, languageId, extension); + const logLevel = this.getDefaultLogLevel(extension); + const extHostOutputChannel = log ? this.doCreateLogOutputChannel(name, logLevel, extension) : this.doCreateOutputChannel(name, languageId, extension); extHostOutputChannel.then(channel => { this.channels.set(channel.id, channel); channel.visible = channel.id === this.visibleChannelId; }); - return log ? this.createExtHostLogOutputChannel(name, >extHostOutputChannel) : this.createExtHostOutputChannel(name, >extHostOutputChannel); + return log ? this.createExtHostLogOutputChannel(name, logLevel, >extHostOutputChannel) : this.createExtHostOutputChannel(name, >extHostOutputChannel); } private async doCreateOutputChannel(name: string, languageId: string | undefined, extension: IExtensionDescription): Promise { @@ -170,14 +171,23 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { return new ExtHostOutputChannel(id, name, logger, this.proxy, extension); } - private async doCreateLogOutputChannel(name: string, extension: IExtensionDescription): Promise { + private async doCreateLogOutputChannel(name: string, logLevel: LogLevel, extension: IExtensionDescription): Promise { const extensionLogDir = await this.createExtensionLogDirectory(extension); const file = this.extHostFileSystemInfo.extUri.joinPath(extensionLogDir, `${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); - const logger = this.loggerService.createLogger(file, { name }); + const logger = this.loggerService.createLogger(file, { name }, logLevel); const id = await this.proxy.$register(name, file, true, undefined, extension.identifier.value); return new ExtHostLogOutputChannel(id, name, logger, this.proxy, extension); } + private getDefaultLogLevel(extension: IExtensionDescription): LogLevel { + let logLevel: LogLevel | undefined; + const logLevelValue = this.initData.environment.extensionLogLevel?.find(([identifier]) => ExtensionIdentifier.equals(extension.identifier, identifier))?.[1]; + if (logLevelValue) { + logLevel = parseLogLevel(logLevelValue); + } + return logLevel ?? this.logService.getLevel(); + } + private createExtensionLogDirectory(extension: IExtensionDescription): Thenable { let extensionLogDirectoryPromise = this.extensionLogDirectoryPromise.get(extension.identifier.value); if (!extensionLogDirectoryPromise) { @@ -236,14 +246,13 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { }; } - private createExtHostLogOutputChannel(name: string, channelPromise: Promise): vscode.LogOutputChannel { + private createExtHostLogOutputChannel(name: string, logLevel: LogLevel, channelPromise: Promise): vscode.LogOutputChannel { const disposables = new DisposableStore(); const validate = () => { if (disposables.isDisposed) { throw new Error('Channel has been closed'); } }; - let logLevel = this.logService.getLevel(); const onDidChangeLogLevel = disposables.add(new Emitter()); channelPromise.then(channel => { disposables.add(channel); diff --git a/src/vs/workbench/browser/web.api.ts b/src/vs/workbench/browser/web.api.ts index 6b8360ae153..3b530fdbf83 100644 --- a/src/vs/workbench/browser/web.api.ts +++ b/src/vs/workbench/browser/web.api.ts @@ -697,6 +697,11 @@ export interface IDevelopmentOptions { */ readonly logLevel?: LogLevel; + /** + * Extension log level. + */ + readonly extensionLogLevel?: [string, LogLevel][]; + /** * Location of a module containing extension tests to run once the workbench is open. */ diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index 3d4ee6058e2..3e9559f30ac 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -5,17 +5,19 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log'; +import { ILogService, LogLevel, getLogLevel, parseLogLevel } from 'vs/platform/log/common/log'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IOutputService } from 'vs/workbench/services/output/common/output'; +import { IOutputChannelDescriptor, IOutputService } from 'vs/workbench/services/output/common/output'; import { isUndefined } from 'vs/base/common/types'; import { ILogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService'; import { extensionTelemetryLogChannelId, telemetryLogChannelId } from 'vs/workbench/contrib/logs/common/logConstants'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; export class SetLogLevelAction extends Action { @@ -26,19 +28,20 @@ export class SetLogLevelAction extends Action { @IQuickInputService private readonly quickInputService: IQuickInputService, @ILogService private readonly logService: ILogService, @ILogLevelService private readonly logLevelService: ILogLevelService, - @IOutputService private readonly outputService: IOutputService + @IOutputService private readonly outputService: IOutputService, + @IEnvironmentService private readonly environmentService: IEnvironmentService, ) { super(id, label); } override async run(): Promise { - const logger = await this.selectLogger(); - if (!isUndefined(logger)) { - await this.selectLogLevel(logger); + const logChannel = await this.selectLogChannel(); + if (!isUndefined(logChannel)) { + await this.selectLogLevel(logChannel); } } - private async selectLogger(): Promise { + private async selectLogChannel(): Promise { const extensionLogs = [], logs = []; for (const channel of this.outputService.getChannelDescriptors()) { if (!channel.log || channel.id === telemetryLogChannelId || channel.id === extensionTelemetryLogChannelId) { @@ -50,55 +53,65 @@ export class SetLogLevelAction extends Action { logs.push(channel); } } - const entries: ({ id?: string; label: string } | IQuickPickSeparator)[] = []; + const entries: ({ label: string; channel?: IOutputChannelDescriptor } | IQuickPickSeparator)[] = []; entries.push({ label: nls.localize('all', "All") }); entries.push({ type: 'separator', label: nls.localize('loggers', "Logs") }); - for (const { id, label } of logs.sort((a, b) => a.label.localeCompare(b.label))) { - entries.push({ id, label }); + for (const channel of logs.sort((a, b) => a.label.localeCompare(b.label))) { + entries.push({ label: channel.label, channel }); } if (extensionLogs.length && logs.length) { entries.push({ type: 'separator', label: nls.localize('extensionLogs', "Extension Logs") }); } - for (const { id, label } of extensionLogs.sort((a, b) => a.label.localeCompare(b.label))) { - entries.push({ id, label }); + for (const channel of extensionLogs.sort((a, b) => a.label.localeCompare(b.label))) { + entries.push({ label: channel.label, channel }); } const entry = await this.quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") }); - return entry ? entry.id ?? null : undefined; + return entry ? entry.channel ?? null : undefined; } - private async selectLogLevel(logger: string | null): Promise { - const current = (logger ? this.logLevelService.getLogLevel(logger) : undefined) ?? this.logService.getLevel(); + private async selectLogLevel(logChannel: IOutputChannelDescriptor | null): Promise { + const defaultLogLevel = this.getDefaultLogLevel(logChannel); + const current = logChannel ? this.logLevelService.getLogLevel(logChannel.id) ?? defaultLogLevel : this.logService.getLevel(); const entries = [ - { label: nls.localize('trace', "Trace"), level: LogLevel.Trace, description: this.getDescription(LogLevel.Trace, current) }, - { label: nls.localize('debug', "Debug"), level: LogLevel.Debug, description: this.getDescription(LogLevel.Debug, current) }, - { label: nls.localize('info', "Info"), level: LogLevel.Info, description: this.getDescription(LogLevel.Info, current) }, - { label: nls.localize('warn', "Warning"), level: LogLevel.Warning, description: this.getDescription(LogLevel.Warning, current) }, - { label: nls.localize('err', "Error"), level: LogLevel.Error, description: this.getDescription(LogLevel.Error, current) }, - { label: nls.localize('critical', "Critical"), level: LogLevel.Critical, description: this.getDescription(LogLevel.Critical, current) }, - { label: nls.localize('off', "Off"), level: LogLevel.Off, description: this.getDescription(LogLevel.Off, current) }, + { label: this.getLabel(nls.localize('trace', "Trace"), LogLevel.Trace, current), level: LogLevel.Trace, description: this.getDescription(LogLevel.Trace, defaultLogLevel) }, + { label: this.getLabel(nls.localize('debug', "Debug"), LogLevel.Debug, current), level: LogLevel.Debug, description: this.getDescription(LogLevel.Debug, defaultLogLevel) }, + { label: this.getLabel(nls.localize('info', "Info"), LogLevel.Info, current), level: LogLevel.Info, description: this.getDescription(LogLevel.Info, defaultLogLevel) }, + { label: this.getLabel(nls.localize('warn', "Warning"), LogLevel.Warning, current), level: LogLevel.Warning, description: this.getDescription(LogLevel.Warning, defaultLogLevel) }, + { label: this.getLabel(nls.localize('err', "Error"), LogLevel.Error, current), level: LogLevel.Error, description: this.getDescription(LogLevel.Error, defaultLogLevel) }, + { label: this.getLabel(nls.localize('critical', "Critical"), LogLevel.Critical, current), level: LogLevel.Critical, description: this.getDescription(LogLevel.Critical, defaultLogLevel) }, + { label: this.getLabel(nls.localize('off', "Off"), LogLevel.Off, current), level: LogLevel.Off, description: this.getDescription(LogLevel.Off, defaultLogLevel) }, ]; - const entry = await this.quickInputService.pick(entries, { placeHolder: logger ? nls.localize('selectLogLevelFor', " {0}: Select log level", this.outputService.getChannelDescriptor(logger)?.label) : nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.logService.getLevel()] }); + const entry = await this.quickInputService.pick(entries, { placeHolder: logChannel ? nls.localize('selectLogLevelFor', " {0}: Select log level", logChannel?.label) : nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.logService.getLevel()] }); if (entry) { - if (logger) { - this.logLevelService.setLogLevel(logger, entry.level); + if (logChannel) { + this.logLevelService.setLogLevel(logChannel.id, entry.level); } else { this.logService.setLevel(entry.level); } } } - private getDescription(level: LogLevel, current: LogLevel): string | undefined { - if (DEFAULT_LOG_LEVEL === level && current === level) { - return nls.localize('default and current', "Default & Current"); + private getLabel(label: string, level: LogLevel, current: LogLevel): string { + if (level === current) { + return `$(check) ${label}`; } - if (DEFAULT_LOG_LEVEL === level) { - return nls.localize('default', "Default"); + return label; + } + + private getDescription(level: LogLevel, defaultLogLevel: LogLevel): string | undefined { + return defaultLogLevel === level ? nls.localize('default', "Default") : undefined; + } + + private getDefaultLogLevel(outputChannel: IOutputChannelDescriptor | null): LogLevel { + let logLevel: LogLevel | undefined; + if (outputChannel?.extensionId) { + const logLevelValue = this.environmentService.extensionLogLevel?.find(([id]) => areSameExtensions({ id }, { id: outputChannel.extensionId! }))?.[1]; + if (logLevelValue) { + logLevel = parseLogLevel(logLevelValue); + } } - if (current === level) { - return nls.localize('current', "Current"); - } - return undefined; + return logLevel ?? getLogLevel(this.environmentService); } } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index b4babc0fae6..2aff66a1e1a 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -18,6 +18,7 @@ import { LogLevelToString } from 'vs/platform/log/common/log'; import { isUndefined } from 'vs/base/common/types'; import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { EXTENSION_IDENTIFIER_WITH_LOG_REGEX } from 'vs/platform/environment/common/environmentService'; export const IBrowserWorkbenchEnvironmentService = refineServiceDecorator(IEnvironmentService); @@ -47,7 +48,28 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi get logsPath(): string { return this.logsHome.path; } @memoize - get logLevel(): string | undefined { return this.payload?.get('logLevel') || (this.options.developmentOptions?.logLevel !== undefined ? LogLevelToString(this.options.developmentOptions?.logLevel) : undefined); } + get logLevel(): string | undefined { + const logLevelFromPayload = this.payload?.get('logLevel'); + if (logLevelFromPayload) { + return logLevelFromPayload.split(',').find(entry => !EXTENSION_IDENTIFIER_WITH_LOG_REGEX.test(entry)); + } + return this.options.developmentOptions?.logLevel !== undefined ? LogLevelToString(this.options.developmentOptions?.logLevel) : undefined; + } + + get extensionLogLevel(): [string, string][] | undefined { + const logLevelFromPayload = this.payload?.get('logLevel'); + if (logLevelFromPayload) { + const result: [string, string][] = []; + for (const entry of logLevelFromPayload.split(',')) { + const matches = EXTENSION_IDENTIFIER_WITH_LOG_REGEX.exec(entry); + if (matches && matches[1] && matches[2]) { + result.push([matches[1], matches[2]]); + } + } + return result.length ? result : undefined; + } + return this.options.developmentOptions?.extensionLogLevel !== undefined ? this.options.developmentOptions?.extensionLogLevel.map(([extension, logLevel]) => ([extension, LogLevelToString(logLevel)])) : undefined; + } @memoize get logFile(): URI { return joinPath(this.logsHome, 'window.log'); } diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index e0f225e9490..b78a21d763e 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -298,6 +298,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._userDataProfilesService.defaultProfile.globalStorageHome, workspaceStorageHome: this._environmentService.workspaceStorageHome, + extensionLogLevel: this._environmentService.extensionLogLevel }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { configuration: workspace.configuration || undefined, diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index 1e854a7f16a..eb9db688f2f 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -54,6 +54,7 @@ export interface IEnvironment { workspaceStorageHome: URI; useHostProxy?: boolean; skipWorkspaceStorageLock?: boolean; + extensionLogLevel?: [string, string][]; } export interface IStaticWorkspaceData { diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 5105a62c15e..1cf2e6448eb 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -226,7 +226,8 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: remoteInitData.globalStorageHome, - workspaceStorageHome: remoteInitData.workspaceStorageHome + workspaceStorageHome: remoteInitData.workspaceStorageHome, + extensionLogLevel: this._environmentService.extensionLogLevel }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { configuration: workspace.configuration, diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index c69beb282c9..08247f4396b 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -450,6 +450,7 @@ export class SandboxLocalProcessExtensionHost implements IExtensionHost { extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._userDataProfilesService.defaultProfile.globalStorageHome, workspaceStorageHome: this._environmentService.workspaceStorageHome, + extensionLogLevel: this._environmentService.extensionLogLevel }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { configuration: withNullAsUndefined(workspace.configuration), From 77d14a47115355d62c23d6981818b4abfda48b7c Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 13 Oct 2022 09:54:57 -0700 Subject: [PATCH 567/599] use size to check if any files were added (#163571) use size --- build/lib/i18n.js | 2 +- build/lib/i18n.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 30c75e7c1c3..9cec875ffcf 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -586,7 +586,7 @@ function createXlfFilesForExtensions() { } } }, function () { - if (_l10nMap) { + if (_l10nMap.size) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), contents: Buffer.from((0, l10n_dev_1.getL10nXlf)(_l10nMap), 'utf8') diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index f5510eda4d7..cc2ffcfbaab 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -669,7 +669,7 @@ export function createXlfFilesForExtensions(): ThroughStream { } } }, function () { - if (_l10nMap) { + if (_l10nMap.size) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), contents: Buffer.from(getL10nXlf(_l10nMap), 'utf8') From 404a282465e30995fe3dadfff9873ea52e8730a6 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 13 Oct 2022 19:21:14 +0200 Subject: [PATCH 568/599] Fixes #163279 (#163573) --- .../mergeEditor/browser/view/viewModel.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts index 2e71fba0a29..570e27015f4 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts @@ -160,11 +160,21 @@ export class MergeEditorViewModel extends Disposable { if (modifiedBaseRange) { const range = this.getRangeOfModifiedBaseRange(editor, modifiedBaseRange, undefined); editor.editor.focus(); + + let startLineNumber = range.startLineNumber; + let endLineNumberExclusive = range.endLineNumberExclusive; + if (range.startLineNumber > editor.editor.getModel()!.getLineCount()) { + transaction(tx => { + this.setActiveModifiedBaseRange(modifiedBaseRange, tx); + }); + startLineNumber = endLineNumberExclusive = editor.editor.getModel()!.getLineCount(); + } + editor.editor.setPosition({ - lineNumber: range.startLineNumber, - column: editor.editor.getModel()!.getLineFirstNonWhitespaceColumn(range.startLineNumber), + lineNumber: startLineNumber, + column: editor.editor.getModel()!.getLineFirstNonWhitespaceColumn(startLineNumber), }); - editor.editor.revealLinesNearTop(range.startLineNumber, range.endLineNumberExclusive, ScrollType.Smooth); + editor.editor.revealLinesNearTop(startLineNumber, endLineNumberExclusive, ScrollType.Smooth); } } From 8d82e91fab3f7b1f7ba260cea3f9c98cceca6075 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 13 Oct 2022 10:30:40 -0700 Subject: [PATCH 569/599] testing: remove dead filter code Refs https://github.com/microsoft/vscode/issues/162304 --- .../testing/browser/testingExplorerFilter.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index e980a313f04..f2de0dbdc97 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -10,21 +10,19 @@ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { Action, IAction, IActionRunner, Separator } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; +import { Emitter } from 'vs/base/common/event'; import { Iterable } from 'vs/base/common/iterator'; import { localize } from 'vs/nls'; -import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { attachSuggestEnabledInputBoxStyler, ContextScopedSuggestEnabledInputWithHistory, SuggestEnabledInputWithHistory, SuggestResultsProvider } from 'vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput'; import { testingFilterIcon } from 'vs/workbench/contrib/testing/browser/icons'; -import { TestCommandId } from 'vs/workbench/contrib/testing/common/constants'; import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue'; -import { denamespaceTestTag } from 'vs/workbench/contrib/testing/common/testTypes'; import { ITestExplorerFilterState, TestFilterTerm } from 'vs/workbench/contrib/testing/common/testExplorerFilterState'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; -import { Emitter } from 'vs/base/common/event'; +import { denamespaceTestTag } from 'vs/workbench/contrib/testing/common/testTypes'; const testFilterDescriptions: { [K in TestFilterTerm]: string } = { [TestFilterTerm.Failed]: localize('testing.filters.showOnlyFailed', "Show Only Failed Tests"), @@ -249,14 +247,3 @@ class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem { this.element!.classList.toggle('checked', this._action.checked); } } - -registerAction2(class extends Action2 { - constructor() { - super({ - _isFakeAction: true, - id: TestCommandId.FilterAction, - title: { value: localize('filter', "Filter"), original: 'Filter' }, - }); - } - async run(): Promise { } -}); From d1104a8b5e450032ba8bfa21c63fe8c94e9f7bed Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:48:53 -0700 Subject: [PATCH 570/599] Add docs for runWhenIdle Had to explain timeout in #163313. Part of #163572 --- src/vs/base/common/async.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index f4f79545b3a..232375b7f10 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1111,7 +1111,22 @@ export interface IdleDeadline { } /** - * Execute the callback the next time the browser is idle + * Execute the callback the next time the browser is idle, returning an + * {@link IDisposable} that will cancel the callback when disposed. This wraps + * [requestIdleCallback] so it will fallback to [setTimeout] if the environment + * doesn't support it. + * + * @param callback The callback to run when idle, this includes an + * [IdleDeadline] that provides the time alloted for the idle callback by the + * browser. Not respecting this deadline will result in a degraded user + * experience. + * @param timeout A timeout at which point to queue no longer wait for an idle + * callback but queue it on the regular event loop (like setTimeout). Typically + * this should not be used. + * + * [IdleDeadline]: https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline + * [requestIdleCallback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback + * [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout */ export let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable; From 4502088b10814b94fa127d2d6e3dcec7b7f4ac17 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 13 Oct 2022 11:01:05 -0700 Subject: [PATCH 571/599] fix empty check for json (#163576) --- build/lib/i18n.js | 4 ++-- build/lib/i18n.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 9cec875ffcf..24e622bc7a8 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -520,7 +520,7 @@ function createL10nBundleForExtension(extensionName) { const json = (0, l10n_dev_1.getL10nJson)(files.map(file => { return file.contents.toString('utf8'); })); - if (Object.keys(json)) { + if (Object.keys(json).length > 0) { result.emit('data', new File({ path: `${extensionName}/bundle.l10n.json`, contents: Buffer.from(JSON.stringify(json), 'utf8') @@ -586,7 +586,7 @@ function createXlfFilesForExtensions() { } } }, function () { - if (_l10nMap.size) { + if (_l10nMap?.size > 0) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), contents: Buffer.from((0, l10n_dev_1.getL10nXlf)(_l10nMap), 'utf8') diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index cc2ffcfbaab..1962ba98926 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -600,7 +600,7 @@ function createL10nBundleForExtension(extensionName: string): ThroughStream { return file.contents.toString('utf8'); })); - if (Object.keys(json)) { + if (Object.keys(json).length > 0) { result.emit('data', new File({ path: `${extensionName}/bundle.l10n.json`, contents: Buffer.from(JSON.stringify(json), 'utf8') @@ -669,7 +669,7 @@ export function createXlfFilesForExtensions(): ThroughStream { } } }, function () { - if (_l10nMap.size) { + if (_l10nMap?.size > 0) { const xlfFile = new File({ path: path.join(extensionsProject, extensionName + '.xlf'), contents: Buffer.from(getL10nXlf(_l10nMap), 'utf8') From 65a9097aa2da4d55318073ca23bc678a2885c461 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 13 Oct 2022 13:15:13 -0700 Subject: [PATCH 572/599] Remove forgoten reference to typescript/lib/protocol (#163585) --- .../src/test/unit/previewer.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/test/unit/previewer.test.ts b/extensions/typescript-language-features/src/test/unit/previewer.test.ts index 2f7af37383b..75a4464610c 100644 --- a/extensions/typescript-language-features/src/test/unit/previewer.test.ts +++ b/extensions/typescript-language-features/src/test/unit/previewer.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import 'mocha'; -import { SymbolDisplayPart } from 'typescript/lib/protocol'; +import { SymbolDisplayPart } from '../../protocol'; import { Uri } from 'vscode'; import { IFilePathToResourceConverter, markdownDocumentation, plainWithLinks, tagsMarkdownPreview } from '../../utils/previewer'; From 186d3415a3d991bcee862f34fea3ee9a9c289d07 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 13 Oct 2022 14:59:35 -0700 Subject: [PATCH 573/599] Use ??= in more places (#163594) --- .../src/languageFeatures/fileReferences.ts | 5 +---- extensions/markdown-language-features/src/logging.ts | 4 +--- .../src/markdownExtensions.ts | 4 +--- extensions/notebook-renderers/src/color.ts | 4 +--- extensions/simple-browser/src/simpleBrowserManager.ts | 4 +--- .../src/languageFeatures/completions.ts | 8 ++------ .../src/languageFeatures/fileReferences.ts | 5 +---- .../src/utils/dependentRegistration.ts | 10 +++------- .../typescript-language-features/src/utils/plugins.ts | 7 +++---- .../src/utils/temp.electron.ts | 4 +--- .../notebook/browser/view/renderers/webviewPreloads.ts | 5 +---- 11 files changed, 16 insertions(+), 44 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts b/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts index b1c06b85f9f..46ed49f3c4b 100644 --- a/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts +++ b/extensions/markdown-language-features/src/languageFeatures/fileReferences.ts @@ -21,10 +21,7 @@ export class FindFileReferencesCommand implements Command { ) { } public async execute(resource?: vscode.Uri) { - if (!resource) { - resource = vscode.window.activeTextEditor?.document.uri; - } - + resource ??= vscode.window.activeTextEditor?.document.uri; if (!resource) { vscode.window.showErrorMessage(localize('error.noResource', "Find file references failed. No resource provided.")); return; diff --git a/extensions/markdown-language-features/src/logging.ts b/extensions/markdown-language-features/src/logging.ts index 2f9a9732d58..d296fed655d 100644 --- a/extensions/markdown-language-features/src/logging.ts +++ b/extensions/markdown-language-features/src/logging.ts @@ -35,9 +35,7 @@ export class VsCodeOutputLogger extends Disposable implements ILogger { private _outputChannel?: vscode.OutputChannel; private get outputChannel() { - if (!this._outputChannel) { - this._outputChannel = this._register(vscode.window.createOutputChannel('Markdown')); - } + this._outputChannel ??= this._register(vscode.window.createOutputChannel('Markdown')); return this._outputChannel; } diff --git a/extensions/markdown-language-features/src/markdownExtensions.ts b/extensions/markdown-language-features/src/markdownExtensions.ts index cd6dfeb4260..0c768d0d48e 100644 --- a/extensions/markdown-language-features/src/markdownExtensions.ts +++ b/extensions/markdown-language-features/src/markdownExtensions.ts @@ -144,9 +144,7 @@ class VSCodeExtensionMarkdownContributionProvider extends Disposable implements public readonly onContributionsChanged = this._onContributionsChanged.event; public get contributions(): MarkdownContributions { - if (!this._contributions) { - this._contributions = this.getCurrentContributions(); - } + this._contributions ??= this.getCurrentContributions(); return this._contributions; } diff --git a/extensions/notebook-renderers/src/color.ts b/extensions/notebook-renderers/src/color.ts index 2c01cae1071..9ad281d35c4 100644 --- a/extensions/notebook-renderers/src/color.ts +++ b/extensions/notebook-renderers/src/color.ts @@ -866,9 +866,7 @@ export class Color { private _toString?: string; toString(): string { - if (!this._toString) { - this._toString = Color.Format.CSS.format(this); - } + this._toString ??= Color.Format.CSS.format(this); return this._toString; } diff --git a/extensions/simple-browser/src/simpleBrowserManager.ts b/extensions/simple-browser/src/simpleBrowserManager.ts index 5cbcc86b342..ef485916411 100644 --- a/extensions/simple-browser/src/simpleBrowserManager.ts +++ b/extensions/simple-browser/src/simpleBrowserManager.ts @@ -35,9 +35,7 @@ export class SimpleBrowserManager { const url = state?.url ?? ''; const view = SimpleBrowserView.restore(this.extensionUri, url, panel); this.registerWebviewListeners(view); - if (!this._activeView) { - this._activeView = view; - } + this._activeView ??= view; } private registerWebviewListeners(view: SimpleBrowserView) { diff --git a/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts index 68eb03dd690..2547b92e044 100644 --- a/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -117,13 +117,9 @@ class MyCompletionItem extends vscode.CompletionItem { if (tsEntry.kindModifiers) { const kindModifiers = parseKindModifier(tsEntry.kindModifiers); if (kindModifiers.has(PConst.KindModifiers.optional)) { - if (!this.insertText) { - this.insertText = this.textLabel; - } + this.insertText ??= this.textLabel; + this.filterText ??= this.textLabel; - if (!this.filterText) { - this.filterText = this.textLabel; - } if (typeof this.label === 'string') { this.label += '?'; } else { diff --git a/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts b/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts index 68685848035..b9e9db47fe5 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts @@ -30,10 +30,7 @@ class FileReferencesCommand implements Command { return; } - if (!resource) { - resource = vscode.window.activeTextEditor?.document.uri; - } - + resource ??= vscode.window.activeTextEditor?.document.uri; if (!resource) { vscode.window.showErrorMessage(localize('error.noResource', "Find file references failed. No resource provided.")); return; diff --git a/extensions/typescript-language-features/src/utils/dependentRegistration.ts b/extensions/typescript-language-features/src/utils/dependentRegistration.ts index 3d97b8a8e7f..c53d553625c 100644 --- a/extensions/typescript-language-features/src/utils/dependentRegistration.ts +++ b/extensions/typescript-language-features/src/utils/dependentRegistration.ts @@ -54,14 +54,10 @@ class ConditionalRegistration { private update() { const enabled = this.conditions.every(condition => condition.value); if (enabled) { - if (!this.registration) { - this.registration = this.doRegister(); - } + this.registration ??= this.doRegister(); } else { - if (this.registration) { - this.registration.dispose(); - this.registration = undefined; - } + this.registration?.dispose(); + this.registration = undefined; } } } diff --git a/extensions/typescript-language-features/src/utils/plugins.ts b/extensions/typescript-language-features/src/utils/plugins.ts index 697e5422445..814f0e12016 100644 --- a/extensions/typescript-language-features/src/utils/plugins.ts +++ b/extensions/typescript-language-features/src/utils/plugins.ts @@ -28,7 +28,7 @@ namespace TypeScriptServerPlugin { export class PluginManager extends Disposable { private readonly _pluginConfigurations = new Map(); - private _plugins: Map> | undefined; + private _plugins?: Map>; constructor() { super(); @@ -37,6 +37,7 @@ export class PluginManager extends Disposable { if (!this._plugins) { return; } + const newPlugins = this.readPlugins(); if (!arrays.equals(Array.from(this._plugins.values()).flat(), Array.from(newPlugins.values()).flat(), TypeScriptServerPlugin.equals)) { this._plugins = newPlugins; @@ -46,9 +47,7 @@ export class PluginManager extends Disposable { } public get plugins(): ReadonlyArray { - if (!this._plugins) { - this._plugins = this.readPlugins(); - } + this._plugins ??= this.readPlugins(); return Array.from(this._plugins.values()).flat(); } diff --git a/extensions/typescript-language-features/src/utils/temp.electron.ts b/extensions/typescript-language-features/src/utils/temp.electron.ts index 84fc21ff885..886c8f014fe 100644 --- a/extensions/typescript-language-features/src/utils/temp.electron.ts +++ b/extensions/typescript-language-features/src/utils/temp.electron.ts @@ -34,9 +34,7 @@ const getRootTempDir = (() => { export const getInstanceTempDir = (() => { let dir: string | undefined; return () => { - if (!dir) { - dir = path.join(getRootTempDir(), makeRandomHexString(20)); - } + dir ??= path.join(getRootTempDir(), makeRandomHexString(20)); if (!fs.existsSync(dir)) { fs.mkdirSync(dir); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 4907be7643d..dfc089fc50d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1305,10 +1305,7 @@ async function webviewPreloads(ctx: PreloadContext) { } private load(): Promise { - if (!this._loadPromise) { - this._loadPromise = this._load(); - } - + this._loadPromise ??= this._load(); return this._loadPromise; } From f55ddeb7dab0df9cca72f45873ab618b6e7470aa Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 14 Oct 2022 00:17:10 +0200 Subject: [PATCH 574/599] clean up logs (#163589) * - log view messages in separate views log - clean up log folders * fix tests --- src/vs/platform/log/common/log.ts | 16 +++++- .../common/outputChannelModelService.ts | 27 ++++------ .../outputChannelModelService.ts | 29 ----------- .../environment/browser/environmentService.ts | 5 +- .../environment/common/environmentService.ts | 1 + .../electron-sandbox/environmentService.ts | 7 ++- .../views/common/viewContainerModel.ts | 52 +++++++++++++++---- .../test/browser/workbenchTestServices.ts | 5 +- src/vs/workbench/workbench.common.main.ts | 1 + src/vs/workbench/workbench.desktop.main.ts | 3 -- src/vs/workbench/workbench.web.main.ts | 3 -- 11 files changed, 81 insertions(+), 68 deletions(-) delete mode 100644 src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 47f09907617..cc0cb8142e9 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -589,8 +589,7 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge protected abstract doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger; } -export class NullLogService implements ILogService { - declare readonly _serviceBrand: undefined; +export class NullLogger implements ILogger { readonly onDidChangeLogLevel: Event = new Emitter().event; setLevel(level: LogLevel): void { } getLevel(): LogLevel { return LogLevel.Info; } @@ -604,6 +603,19 @@ export class NullLogService implements ILogService { flush(): void { } } +export class NullLogService extends NullLogger implements ILogService { + declare readonly _serviceBrand: undefined; +} + +export class NullLoggerService extends AbstractLoggerService { + + constructor() { super(LogLevel.Info, Event.None); } + + protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions | undefined): ILogger { + return new NullLogger(); + } +} + export function getLogLevel(environmentService: IEnvironmentService): LogLevel { if (environmentService.verbose) { return LogLevel.Trace; diff --git a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts index 3c562328b0c..ec25f0df576 100644 --- a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts +++ b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts @@ -8,7 +8,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IFileService } from 'vs/platform/files/common/files'; import { toLocalISOString } from 'vs/base/common/date'; -import { dirname, joinPath } from 'vs/base/common/resources'; +import { joinPath } from 'vs/base/common/resources'; import { DelegatedOutputChannelModel, FileOutputChannelModel, IOutputChannelModel } from 'vs/workbench/contrib/output/common/outputChannelModel'; import { URI } from 'vs/base/common/uri'; import { ILanguageSelection } from 'vs/editor/common/languages/language'; @@ -22,15 +22,19 @@ export interface IOutputChannelModelService { } -export abstract class AbstractOutputChannelModelService { +export class OutputChannelModelService { declare readonly _serviceBrand: undefined; + private readonly outputLocation: URI; + constructor( - private readonly outputLocation: URI, - @IFileService protected readonly fileService: IFileService, - @IInstantiationService protected readonly instantiationService: IInstantiationService - ) { } + @IFileService private readonly fileService: IFileService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + ) { + this.outputLocation = joinPath(environmentService.windowLogsPath, `output_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); + } createOutputChannelModel(id: string, modelUri: URI, language: ILanguageSelection, file?: URI): IOutputChannelModel { return file ? this.instantiationService.createInstance(FileOutputChannelModel, modelUri, language, file) : this.instantiationService.createInstance(DelegatedOutputChannelModel, id, modelUri, language, this.outputDir); @@ -46,15 +50,4 @@ export abstract class AbstractOutputChannelModelService { } -export class OutputChannelModelService extends AbstractOutputChannelModelService implements IOutputChannelModelService { - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileService fileService: IFileService, - ) { - super(joinPath(dirname(environmentService.logFile), toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')), fileService, instantiationService); - } -} - registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts b/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts deleted file mode 100644 index db0b6be79de..00000000000 --- a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts +++ /dev/null @@ -1,29 +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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { join } from 'vs/base/common/path'; -import { URI } from 'vs/base/common/uri'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { toLocalISOString } from 'vs/base/common/date'; -import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { AbstractOutputChannelModelService, IOutputChannelModelService } from 'vs/workbench/contrib/output/common/outputChannelModelService'; - -export class OutputChannelModelService extends AbstractOutputChannelModelService implements IOutputChannelModelService { - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileService fileService: IFileService, - @INativeHostService nativeHostService: INativeHostService - ) { - super(URI.file(join(environmentService.logsPath, `output_${nativeHostService.windowId}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`)), fileService, instantiationService); - } - -} - -registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 2aff66a1e1a..0f3e507ebb0 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -72,7 +72,10 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi } @memoize - get logFile(): URI { return joinPath(this.logsHome, 'window.log'); } + get windowLogsPath(): URI { return this.logsHome; } + + @memoize + get logFile(): URI { return joinPath(this.windowLogsPath, 'window.log'); } @memoize get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.vscodeUserData }); } diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index c922bb63859..a1b4d8341d1 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -24,6 +24,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService { // --- Paths readonly logFile: URI; + readonly windowLogsPath: URI; readonly extHostLogsPath: URI; readonly extHostTelemetryLogFile: URI; diff --git a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts index 1d1498d1c4a..72ee95090af 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts @@ -86,10 +86,13 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment override get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); } @memoize - get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.configuration.windowId}.log`)); } + get windowLogsPath(): URI { return URI.file(join(this.logsPath, `window${this.configuration.windowId}`)); } @memoize - get extHostLogsPath(): URI { return URI.file(join(this.logsPath, `exthost${this.configuration.windowId}`)); } + get logFile(): URI { return joinPath(this.windowLogsPath, `renderer.log`); } + + @memoize + get extHostLogsPath(): URI { return joinPath(this.windowLogsPath, 'exthost'); } @memoize get extHostTelemetryLogFile(): URI { diff --git a/src/vs/workbench/services/views/common/viewContainerModel.ts b/src/vs/workbench/services/views/common/viewContainerModel.ts index 4bbed6f5ffd..850c42b99d2 100644 --- a/src/vs/workbench/services/views/common/viewContainerModel.ts +++ b/src/vs/workbench/services/views/common/viewContainerModel.ts @@ -9,16 +9,40 @@ import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget import { Registry } from 'vs/platform/registry/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { coalesce, move } from 'vs/base/common/arrays'; import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types'; -import { isEqual } from 'vs/base/common/resources'; +import { isEqual, joinPath } from 'vs/base/common/resources'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IStringDictionary } from 'vs/base/common/collections'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; import { localize } from 'vs/nls'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; +import { IOutputChannelRegistry, IOutputService, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; + +function getViewsLogFile(environmentService: IWorkbenchEnvironmentService): URI { return joinPath(environmentService.windowLogsPath, 'views.log'); } + +registerAction2(class extends Action2 { + constructor() { + super({ + id: '_workbench.output.showViewsLog', + title: { value: 'Show Views Log', original: 'Show Views Log' }, + category: Categories.Developer, + f1: true + }); + } + async run(servicesAccessor: ServicesAccessor): Promise { + const outputService = servicesAccessor.get(IOutputService); + const environmentService = servicesAccessor.get(IWorkbenchEnvironmentService); + Registry.as(OutputExtensions.OutputChannels).registerChannel({ id: 'viewsLog', label: localize('views log', "Views"), file: getViewsLogFile(environmentService), log: true }); + outputService.showChannel('viewsLog'); + + } +}); export function getViewsStateStorageId(viewContainerStorageId: string): string { return `${viewContainerStorageId}.hidden`; } @@ -85,14 +109,19 @@ class ViewDescriptorsState extends Disposable { private _onDidChangeStoredState = this._register(new Emitter<{ id: string; visible: boolean }[]>()); readonly onDidChangeStoredState = this._onDidChangeStoredState.event; + private readonly logger: ILogger; + constructor( viewContainerStorageId: string, viewContainerName: string, @IStorageService private readonly storageService: IStorageService, - @ILogService private readonly logService: ILogService, + @ILoggerService loggerService: ILoggerService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(); + this.logger = loggerService.createLogger(getViewsLogFile(workbenchEnvironmentService)); + this.globalViewsStateStorageId = getViewsStateStorageId(viewContainerStorageId); this.workspaceViewsStateStorageId = viewContainerStorageId; this._register(this.storageService.onDidChangeValue(e => this.onDidStorageChange(e))); @@ -165,7 +194,7 @@ class ViewDescriptorsState extends Disposable { if (state) { if (state.visibleGlobal !== !storedState.isHidden) { if (!storedState.isHidden) { - this.logService.info(`View visibility state changed: ${id} is now visible`); + this.logger.info(`View visibility state changed: ${id} is now visible`); } changedStates.push({ id, visible: !storedState.isHidden }); } @@ -349,14 +378,19 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode private _onDidMoveVisibleViewDescriptors = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef }>()); readonly onDidMoveVisibleViewDescriptors: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef }> = this._onDidMoveVisibleViewDescriptors.event; + private readonly logger: ILogger; + constructor( readonly viewContainer: ViewContainer, @IInstantiationService instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @ILogService private readonly logService: ILogService, + @ILoggerService loggerService: ILoggerService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(); + this.logger = loggerService.createLogger(getViewsLogFile(workbenchEnvironmentService)); + this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(() => this.onDidChangeContext())); this.viewDescriptorsState = this._register(instantiationService.createInstance(ViewDescriptorsState, viewContainer.storageId || `${viewContainer.id}.state`, typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.original)); this._register(this.viewDescriptorsState.onDidChangeStoredState(items => this.updateVisibility(items))); @@ -366,7 +400,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode Event.map(this.onDidRemoveVisibleViewDescriptors, removed => `Removed views:${removed.map(v => v.viewDescriptor.id).join(',')}`), Event.map(this.onDidMoveVisibleViewDescriptors, ({ from, to }) => `Moved view ${from.viewDescriptor.id} to ${to.viewDescriptor.id}`)) (message => { - this.logService.info(message); + this.logger.info(message); this.viewDescriptorsState.updateState(this.allViewDescriptors); this.updateContainerInfo(); })); @@ -472,7 +506,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode } else { viewDescriptorItem.state.visibleGlobal = visible; if (visible) { - this.logService.info(`Showing view ${viewDescriptorItem.viewDescriptor.id} in the container ${this.viewContainer.id}`); + this.logger.info(`Showing view ${viewDescriptorItem.viewDescriptor.id} in the container ${this.viewContainer.id}`); } } @@ -545,7 +579,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode const isVisible = state.visibleGlobal; state.visibleGlobal = isUndefinedOrNull(addedViewDescriptorState.visible) ? (isUndefinedOrNull(state.visibleGlobal) ? !viewDescriptor.hideByDefault : state.visibleGlobal) : addedViewDescriptorState.visible; if (state.visibleGlobal && !isVisible) { - this.logService.info(`Added view ${viewDescriptor.id} in the container ${this.viewContainer.id} and showing it`); + this.logger.info(`Added view ${viewDescriptor.id} in the container ${this.viewContainer.id} and showing it`); } } state.collapsed = isUndefinedOrNull(addedViewDescriptorState.collapsed) ? (isUndefinedOrNull(state.collapsed) ? !!viewDescriptor.collapsed : state.collapsed) : addedViewDescriptorState.collapsed; diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index c41b5c65a67..796e5fc4fe3 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -56,7 +56,7 @@ import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, Preferre import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { Dimension, IDimension } from 'vs/base/browser/dom'; -import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService, NullLoggerService, NullLogService } from 'vs/platform/log/common/log'; import { ILabelService } from 'vs/platform/label/common/label'; import { timeout } from 'vs/base/common/async'; import { PaneComposite, PaneCompositeDescriptor } from 'vs/workbench/browser/panecomposite'; @@ -302,6 +302,7 @@ export function workbenchInstantiationService( instantiationService.stub(ITextFileService, overrides?.textFileService ? overrides.textFileService(instantiationService) : disposables.add(instantiationService.createInstance(TestTextFileService))); instantiationService.stub(IHostService, instantiationService.createInstance(TestHostService)); instantiationService.stub(ITextModelService, disposables.add(instantiationService.createInstance(TextModelResolverService))); + instantiationService.stub(ILoggerService, new NullLoggerService()); instantiationService.stub(ILogService, new NullLogService()); const editorGroupService = new TestEditorGroupsService([new TestEditorGroupView(0)]); instantiationService.stub(IEditorGroupsService, editorGroupService); @@ -479,7 +480,7 @@ class TestEnvironmentServiceWithArgs extends BrowserWorkbenchEnvironmentService args = []; } -export const TestEnvironmentService = new TestEnvironmentServiceWithArgs('', undefined!, Object.create(null), TestProductService); +export const TestEnvironmentService = new TestEnvironmentServiceWithArgs('', URI.file('tests').with({ scheme: 'vscode-tests' }), Object.create(null), TestProductService); export class TestProgressService implements IProgressService { diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index bf9f350efe9..01588f36305 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -234,6 +234,7 @@ import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; // Output View +import 'vs/workbench/contrib/output/common/outputChannelModelService'; import 'vs/workbench/contrib/output/browser/output.contribution'; import 'vs/workbench/contrib/output/browser/outputView'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index ca74c51637b..aa0846dcb24 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -133,9 +133,6 @@ import 'vs/workbench/contrib/themes/browser/themes.test.contribution'; // User Data Sync import 'vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution'; -// Output -import 'vs/workbench/contrib/output/electron-sandbox/outputChannelModelService'; - // Tags import 'vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService'; import 'vs/workbench/contrib/tags/electron-sandbox/tags.contribution'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 1462d032fe5..286ab2b2f22 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -112,9 +112,6 @@ registerSingleton(ILanguagePackService, WebLanguagePacksService, InstantiationTy //#region --- workbench contributions -// Output -import 'vs/workbench/contrib/output/common/outputChannelModelService'; - // Logs import 'vs/workbench/contrib/logs/browser/logs.contribution'; From 645129883ed26d5682f0db54d6c7f4158e0b802e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 13 Oct 2022 17:04:24 -0700 Subject: [PATCH 575/599] Add static preloads notebook contribution (#163512) For #163511 --- .../browser/diff/notebookTextDiffEditor.ts | 12 ++-- .../notebook/browser/notebookEditorWidget.ts | 8 +-- .../browser/notebookExtensionPoint.ts | 57 +++++++++++++++---- .../browser/services/notebookServiceImpl.ts | 48 ++++++++++++++-- .../view/renderers/backLayerWebView.ts | 24 +++++--- .../browser/view/renderers/webviewMessages.ts | 4 ++ .../browser/view/renderers/webviewPreloads.ts | 20 ++++--- .../contrib/notebook/common/notebookCommon.ts | 5 ++ .../notebook/common/notebookOutputRenderer.ts | 20 ++++++- .../notebook/common/notebookService.ts | 4 +- .../common/extensionsApiProposals.ts | 1 + ...roposed.contribNotebookStaticPreloads.d.ts | 6 ++ 12 files changed, 168 insertions(+), 41 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index bcab942c8cc..751d6fb5d7c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -410,11 +410,11 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } })); - await this._createOriginalWebview(generateUuid(), this._model.original.resource); + await this._createOriginalWebview(generateUuid(), this._model.original.viewType, this._model.original.resource); if (this._originalWebview) { this._modifiedResourceDisposableStore.add(this._originalWebview); } - await this._createModifiedWebview(generateUuid(), this._model.modified.resource); + await this._createModifiedWebview(generateUuid(), this._model.modified.viewType, this._model.modified.resource); if (this._modifiedWebview) { this._modifiedResourceDisposableStore.add(this._modifiedWebview); } @@ -466,10 +466,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD })); } - private async _createModifiedWebview(id: string, resource: URI): Promise { + private async _createModifiedWebview(id: string, viewType: string, resource: URI): Promise { this._modifiedWebview?.dispose(); - this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { + this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, viewType, resource, { ...this._notebookOptions.computeDiffWebviewOptions(), fontFamily: this._generateFontFamily() }, undefined) as BackLayerWebView; @@ -483,10 +483,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return this._fontInfo?.fontFamily ?? `"SF Mono", Monaco, Menlo, Consolas, "Ubuntu Mono", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace`; } - private async _createOriginalWebview(id: string, resource: URI): Promise { + private async _createOriginalWebview(id: string, viewType: string, resource: URI): Promise { this._originalWebview?.dispose(); - this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { + this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, viewType, resource, { ...this._notebookOptions.computeDiffWebviewOptions(), fontFamily: this._generateFontFamily() }, undefined) as BackLayerWebView; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 892021f8529..e625d88cf97 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1236,7 +1236,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } if (!this._webview) { - this._createWebview(this.getId(), this.textModel.uri); + this._createWebview(this.getId(), this.textModel.viewType, this.textModel.uri); } this._webviewResolvePromise = (async () => { @@ -1273,7 +1273,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD return this._webviewResolvePromise; } - private async _createWebview(id: string, resource: URI): Promise { + private async _createWebview(id: string, viewType: string, resource: URI): Promise { const that = this; this._webview = this.instantiationService.createInstance(BackLayerWebView, { @@ -1294,7 +1294,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD didDropMarkupCell: that._didDropMarkupCell.bind(that), didEndDragMarkupCell: that._didEndDragMarkupCell.bind(that), didResizeOutput: that._didResizeOutput.bind(that) - }, id, resource, { + }, id, viewType, resource, { ...this._notebookOptions.computeWebviewOptions(), fontFamily: this._generateFontFamily() }, this.notebookRendererMessaging.getScoped(this._uuid)); @@ -1306,7 +1306,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } private async _attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined, perf?: NotebookPerfMarks) { - await this._createWebview(this.getId(), textModel.uri); + await this._createWebview(this.getId(), textModel.viewType, textModel.uri); this.viewModel = this.instantiationService.createInstance(NotebookViewModel, textModel.viewType, textModel, this._viewContext, this.getLayoutInfo(), { isReadOnly: this._readOnly }); this._viewContext.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts index f28fc03d29b..4b32dd1539e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts @@ -42,6 +42,16 @@ export interface INotebookRendererContribution { readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec; } +const NotebookPreloadContribution = Object.freeze({ + type: 'type', + entrypoint: 'entrypoint', +}); + +export interface INotebookPreloadContribution { + readonly [NotebookPreloadContribution.type]: string; + readonly [NotebookPreloadContribution.entrypoint]: string; +} + const notebookProviderContribution: IJSONSchema = { description: nls.localize('contributes.notebook.provider', 'Contributes notebook document provider.'), type: 'array', @@ -139,7 +149,6 @@ const notebookRendererContribution: IJSONSchema = { 'optional', 'never', ], - enumDescriptions: [ nls.localize('contributes.notebook.renderer.requiresMessaging.always', 'Messaging is required. The renderer will only be used when it\'s part of an extension that can be run in an extension host.'), nls.localize('contributes.notebook.renderer.requiresMessaging.optional', 'The renderer is better with messaging available, but it\'s not requried.'), @@ -198,14 +207,40 @@ const notebookRendererContribution: IJSONSchema = { } }; -export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint( - { - extensionPoint: 'notebooks', - jsonSchema: notebookProviderContribution - }); +const notebookPreloadContribution: IJSONSchema = { + description: nls.localize('contributes.preload.provider', 'Contributes notebook preloads.'), + type: 'array', + defaultSnippets: [{ body: [{ type: '', entrypoint: '' }] }], + items: { + type: 'object', + required: [ + NotebookPreloadContribution.type, + NotebookPreloadContribution.entrypoint + ], + properties: { + [NotebookPreloadContribution.type]: { + type: 'string', + description: nls.localize('contributes.preload.provider.viewType', 'Type of the notebook.'), + }, + [NotebookPreloadContribution.entrypoint]: { + type: 'string', + description: nls.localize('contributes.preload.entrypoint', 'Path to file loaded in the webview.'), + }, + } + } +}; -export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint( - { - extensionPoint: 'notebookRenderer', - jsonSchema: notebookRendererContribution - }); +export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'notebooks', + jsonSchema: notebookProviderContribution +}); + +export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'notebookRenderer', + jsonSchema: notebookRendererContribution +}); + +export const notebookPreloadExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'notebookPreload', + jsonSchema: notebookPreloadContribution, +}); diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts index 66d21da2abb..4242f322651 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts @@ -23,20 +23,20 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Memento } from 'vs/workbench/common/memento'; -import { INotebookEditorContribution, notebookRendererExtensionPoint, notebooksExtensionPoint } from 'vs/workbench/contrib/notebook/browser/notebookExtensionPoint'; +import { INotebookEditorContribution, notebookPreloadExtensionPoint, notebookRendererExtensionPoint, notebooksExtensionPoint } from 'vs/workbench/contrib/notebook/browser/notebookExtensionPoint'; import { INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/common/notebookDiffEditorInput'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellUri, NotebookSetting, INotebookContributionData, INotebookExclusiveDocumentFilter, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, MimeTypeDisplayOrder, NotebookData, NotebookEditorPriority, NotebookRendererMatch, NOTEBOOK_DISPLAY_ORDER, RENDERER_EQUIVALENT_EXTENSIONS, RENDERER_NOT_AVAILABLE, TransientOptions, NotebookExtensionDescription } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellUri, NotebookSetting, INotebookContributionData, INotebookExclusiveDocumentFilter, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, MimeTypeDisplayOrder, NotebookData, NotebookEditorPriority, NotebookRendererMatch, NOTEBOOK_DISPLAY_ORDER, RENDERER_EQUIVALENT_EXTENSIONS, RENDERER_NOT_AVAILABLE, TransientOptions, NotebookExtensionDescription, INotebookStaticPreloadInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { updateEditorTopPadding } from 'vs/workbench/contrib/notebook/common/notebookOptions'; -import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer'; +import { NotebookOutputRendererInfo, NotebookStaticPreloadInfo as NotebookStaticPreloadInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer'; import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { ComplexNotebookProviderInfo, INotebookContentProvider, INotebookSerializer, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService'; import { DiffEditorInputFactoryFunction, EditorInputFactoryFunction, EditorInputFactoryObject, IEditorResolverService, IEditorType, RegisteredEditorInfo, RegisteredEditorPriority, UntitledEditorInputFactoryFunction } from 'vs/workbench/services/editor/common/editorResolverService'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionService, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; export class NotebookProviderInfoStore extends Disposable { @@ -422,6 +422,9 @@ export class NotebookService extends Disposable implements INotebookService { private readonly _notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore); private readonly _onDidChangeOutputRenderers = this._register(new Emitter()); readonly onDidChangeOutputRenderers = this._onDidChangeOutputRenderers.event; + + private readonly _notebookStaticPreloadInfoStore = new Set(); + private readonly _models = new ResourceMap(); private readonly _onWillAddNotebookDocument = this._register(new Emitter()); @@ -490,6 +493,35 @@ export class NotebookService extends Disposable implements INotebookService { this._onDidChangeOutputRenderers.fire(); }); + notebookPreloadExtensionPoint.setHandler(extensions => { + this._notebookStaticPreloadInfoStore.clear(); + + for (const extension of extensions) { + if (!isProposedApiEnabled(extension.description, 'contribNotebookStaticPreloads')) { + continue; + } + + for (const notebookContribution of extension.value) { + if (!notebookContribution.entrypoint) { // avoid crashing + extension.collector.error(`Notebook preload does not specify entry point`); + continue; + } + + const type = notebookContribution.type; + if (!type) { + extension.collector.error(`Notebook preload does not specify type-property`); + continue; + } + + this._notebookStaticPreloadInfoStore.add(new NotebookStaticPreloadInfo({ + type, + extension: extension.description, + entrypoint: notebookContribution.entrypoint, + })); + } + } + }); + const updateOrder = () => { this._displayOrder = new MimeTypeDisplayOrder( this._configurationService.getValue(NotebookSetting.displayOrder) || [], @@ -671,6 +703,14 @@ export class NotebookService extends Disposable implements INotebookService { return this._notebookRenderersInfoStore.getAll(); } + *getStaticPreloads(viewType: string): Iterable { + for (const preload of this._notebookStaticPreloadInfoStore) { + if (preload.type === viewType) { + yield preload; + } + } + } + // --- notebook documents: create, destory, retrieve, enumerate createNotebookTextModel(viewType: string, uri: URI, data: NotebookData, transientOptions: TransientOptions): NotebookTextModel { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index ba6810f0afb..bbef3bc7abc 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -43,7 +43,7 @@ import { IWebviewElement, IWebviewService, WebviewContentPurpose } from 'vs/work import { WebviewWindowDragMonitor } from 'vs/workbench/contrib/webview/browser/webviewWindowDragMonitor'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { FromWebviewMessage, IAckOutputHeight, IClickedDataUrlMessage, ICodeBlockHighlightRequest, IContentWidgetTopRequest, IControllerPreload, ICreationContent, ICreationRequestMessage, IFindMatch, IMarkupCellInitialization, RendererMetadata, ToWebviewMessage } from './webviewMessages'; +import { FromWebviewMessage, IAckOutputHeight, IClickedDataUrlMessage, ICodeBlockHighlightRequest, IContentWidgetTopRequest, IControllerPreload, ICreationContent, ICreationRequestMessage, IFindMatch, IMarkupCellInitialization, RendererMetadata, StaticPreloadMetadata, ToWebviewMessage } from './webviewMessages'; import { DeferredPromise } from 'vs/base/common/async'; export interface ICachedInset { @@ -121,6 +121,7 @@ export class BackLayerWebView extends Disposable { constructor( public notebookEditor: INotebookDelegateForWebview, public readonly id: string, + public readonly notebookViewType: string, public readonly documentUri: URI, private options: BacklayerWebviewOptions, private readonly rendererMessaging: IScopedRendererMessaging | undefined, @@ -225,10 +226,12 @@ export class BackLayerWebView extends Disposable { private generateContent(coreDependencies: string, baseUrl: string) { const renderersData = this.getRendererData(); + const preloadsData = this.getStaticPreloadsData(); const preloadScript = preloadsScriptStr( this.options, { dragAndDropEnabled: this.options.dragAndDropEnabled }, renderersData, + preloadsData, this.workspaceTrustManagementService.isWorkspaceTrusted(), this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30, this.nonce); @@ -417,6 +420,12 @@ export class BackLayerWebView extends Disposable { }); } + private getStaticPreloadsData(): StaticPreloadMetadata[] { + return Array.from(this.notebookService.getStaticPreloads(this.notebookViewType), preload => { + return { entrypoint: this.asWebviewUri(preload.entrypoint, preload.extensionLocation).toString().toString() }; + }); + } + private asWebviewUri(uri: URI, fromExtension: URI | undefined) { return asWebviewUri(uri, fromExtension?.scheme === Schemas.vscodeRemote ? { isRemote: true, authority: fromExtension.authority } : undefined); } @@ -920,16 +929,17 @@ var requirejs = (function() { return webview; } - private _getResourceRootsCache() { + private _getResourceRootsCache(): URI[] { const workspaceFolders = this.contextService.getWorkspace().folders.map(x => x.uri); const notebookDir = this.getNotebookBaseUri(); return [ - ...this.notebookService.getNotebookProviderResourceRoots(), - ...this.notebookService.getRenderers().map(x => dirname(x.entrypoint.path)), - ...workspaceFolders, + this.notebookService.getNotebookProviderResourceRoots(), + this.notebookService.getRenderers().map(x => dirname(x.entrypoint.path)), + Array.from(this.notebookService.getStaticPreloads(this.notebookViewType), x => dirname(x.entrypoint)), + workspaceFolders, notebookDir, - ...this.getBuiltinLocalResourceRoots() - ]; + this.getBuiltinLocalResourceRoots() + ].flat(); } private initializeWebViewState() { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts index 8b0902ba129..5eea6e550cf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages.ts @@ -281,6 +281,10 @@ export interface RendererMetadata { readonly isBuiltin: boolean; } +export interface StaticPreloadMetadata { + readonly entrypoint: string; +} + export interface IUpdateRenderersMessage { readonly type: 'updateRenderers'; readonly rendererData: readonly RendererMetadata[]; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index dfc089fc50d..9263b6ad49b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -69,6 +69,7 @@ interface PreloadContext { readonly style: PreloadStyles; readonly options: PreloadOptions; readonly rendererData: readonly webviewMessages.RendererMetadata[]; + readonly staticPreloadsData: readonly webviewMessages.StaticPreloadMetadata[]; readonly isWorkspaceTrusted: boolean; readonly lineLimit: number; } @@ -199,7 +200,7 @@ async function webviewPreloads(ctx: PreloadContext) { } }; - async function loadScriptSource(url: string, originalUri = url): Promise { + async function loadScriptSource(url: string, originalUri: string): Promise { const res = await fetch(url); const text = await res.text(); if (!res.ok) { @@ -246,11 +247,11 @@ async function webviewPreloads(ctx: PreloadContext) { return new Function(...args.map(([k]) => k), functionSrc)(...args.map(([, v]) => v)); }; - const runKernelPreload = async (url: string, originalUri: string): Promise => { + const runKernelPreload = async (url: string, originalUri: string, forceLoadAsModule: boolean): Promise => { const text = await loadScriptSource(url, originalUri); const isModule = /\bexport\b.*\bactivate\b/.test(text); try { - if (isModule) { + if (isModule || forceLoadAsModule) { const module: KernelPreloadModule = await __import(url); if (!module.activate) { console.error(`Notebook preload (${url}) looks like a module but does not export an activate function`); @@ -1140,7 +1141,7 @@ async function webviewPreloads(ctx: PreloadContext) { case 'preload': { const resources = event.data.resources; for (const { uri, originalUri } of resources) { - kernelPreloads.load(uri, originalUri); + kernelPreloads.load(uri, originalUri, false); } break; } @@ -1357,9 +1358,9 @@ async function webviewPreloads(ctx: PreloadContext) { * @param uri URI to load from * @param originalUri URI to show in an error message if the preload is invalid. */ - public load(uri: string, originalUri: string) { + public load(uri: string, originalUri: string, forceLoadAsModule: boolean) { const promise = Promise.all([ - runKernelPreload(uri, originalUri), + runKernelPreload(uri, originalUri, forceLoadAsModule), this.waitForAllCurrent(), ]); @@ -2123,6 +2124,10 @@ async function webviewPreloads(ctx: PreloadContext) { type: 'initialized' }); + for (const preload of ctx.staticPreloadsData) { + kernelPreloads.load(preload.entrypoint, preload.entrypoint, true); + } + function postNotebookMessage( type: T['type'], properties: Omit @@ -2352,11 +2357,12 @@ async function webviewPreloads(ctx: PreloadContext) { }(); } -export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderers: readonly webviewMessages.RendererMetadata[], isWorkspaceTrusted: boolean, lineLimit: number, nonce: string) { +export function preloadsScriptStr(styleValues: PreloadStyles, options: PreloadOptions, renderers: readonly webviewMessages.RendererMetadata[], preloads: readonly webviewMessages.StaticPreloadMetadata[], isWorkspaceTrusted: boolean, lineLimit: number, nonce: string) { const ctx: PreloadContext = { style: styleValues, options, rendererData: renderers, + staticPreloadsData: preloads, isWorkspaceTrusted, lineLimit, nonce, diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 403a07a082f..13c5beb2320 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -176,6 +176,11 @@ export interface INotebookRendererInfo { matches(mimeType: string, kernelProvides: ReadonlyArray): NotebookRendererMatch; } +export interface INotebookStaticPreloadInfo { + readonly type: string; + readonly entrypoint: URI; + readonly extensionLocation: URI; +} export interface IOrderedMimeType { mimeType: string; diff --git a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts index 72c2e6ebf3e..8400da97fa0 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts @@ -8,7 +8,7 @@ import { Iterable } from 'vs/base/common/iterator'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { INotebookRendererInfo, ContributedNotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec, NotebookRendererEntrypoint } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookRendererInfo, ContributedNotebookRendererEntrypoint, NotebookRendererMatch, RendererMessagingSpec, NotebookRendererEntrypoint, INotebookStaticPreloadInfo as INotebookStaticPreloadInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; class DependencyList { private readonly value: ReadonlySet; @@ -118,3 +118,21 @@ export class NotebookOutputRendererInfo implements INotebookRendererInfo { return this.mimeTypeGlobs.some(pattern => pattern(mimeType)) || this.mimeTypes.some(pattern => pattern === mimeType); } } + +export class NotebookStaticPreloadInfo implements INotebookStaticPreloadInfo { + + readonly type: string; + readonly entrypoint: URI; + readonly extensionLocation: URI; + + constructor(descriptor: { + readonly type: string; + readonly entrypoint: string; + readonly extension: IExtensionDescription; + }) { + this.type = descriptor.type; + + this.entrypoint = joinPath(descriptor.extension.extensionLocation, descriptor.entrypoint); + this.extensionLocation = descriptor.extension.extensionLocation; + } +} diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index f67d9be987d..d599600383a 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { URI } from 'vs/base/common/uri'; import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { Event } from 'vs/base/common/event'; -import { INotebookRendererInfo, NotebookData, TransientOptions, IOrderedMimeType, IOutputDto, INotebookContributionData, NotebookExtensionDescription } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookRendererInfo, NotebookData, TransientOptions, IOrderedMimeType, IOutputDto, INotebookContributionData, NotebookExtensionDescription, INotebookStaticPreloadInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { CancellationToken } from 'vs/base/common/cancellation'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; @@ -73,6 +73,8 @@ export interface INotebookService { getRendererInfo(id: string): INotebookRendererInfo | undefined; getRenderers(): INotebookRendererInfo[]; + getStaticPreloads(viewType: string): Iterable; + /** Updates the preferred renderer for the given mimetype in the workspace. */ updateMimePreferredRenderer(viewType: string, mimeType: string, rendererId: string, otherMimetypes: readonly string[]): void; saveMimeDisplayOrder(target: ConfigurationTarget): void; diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index facd28600fb..f461c58e37e 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -14,6 +14,7 @@ export const allApiProposals = Object.freeze({ contribLabelFormatterWorkspaceTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLabelFormatterWorkspaceTooltip.d.ts', contribMenuBarHome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMenuBarHome.d.ts', contribMergeEditorMenus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMergeEditorMenus.d.ts', + contribNotebookStaticPreloads: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts', contribRemoteHelp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts', contribShareMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts', contribViewsRemote: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsRemote.d.ts', diff --git a/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts b/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts new file mode 100644 index 00000000000..b01c68ebabb --- /dev/null +++ b/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// empty placeholder declaration for the `notebookPreload` contribution point From 7ef8e6b87a2a5a25ba1ef946bd1640ca3510956c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 13 Oct 2022 17:40:07 -0700 Subject: [PATCH 576/599] Use consistent origin for webview views (#163602) For #132464 --- .../api/browser/mainThreadWebviewPanels.ts | 46 ++----------------- .../browser/parts/views/viewsViewlet.ts | 2 +- .../contrib/webview/browser/webview.ts | 43 +++++++++++++++-- .../webviewView/browser/webviewViewPane.ts | 25 ++++++---- 4 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index d50996eacd1..9f9af56b2d9 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -6,17 +6,14 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -import { Memento, MementoObject } from 'vs/workbench/common/memento'; -import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewOptions, WebviewOriginStore } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; import { WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; import { IWebViewShowOptions, IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; @@ -79,43 +76,6 @@ class WebviewViewTypeTransformer { } } -/** - * Stores the unique origins for webviews. - * - * These are randomly generated, but keyed on extension and webview viewType. - */ -class WebviewOriginStore { - - private readonly memento: Memento; - private readonly state: MementoObject; - - constructor( - storageKey: string, - @IStorageService storageService: IStorageService, - ) { - this.memento = new Memento(storageKey, storageService); - this.state = this.memento.getMemento(StorageScope.APPLICATION, StorageTarget.MACHINE); - } - - public getOrigin(extId: ExtensionIdentifier, viewType: string): string { - const key = this.getKey(extId, viewType); - - const existing = this.state[key]; - if (existing && typeof existing === 'string') { - return existing; - } - - const newOrigin = generateUuid(); - this.state[key] = newOrigin; - this.memento.saveMemento(); - return newOrigin; - } - - private getKey(extId: ExtensionIdentifier, viewType: string): string { - return JSON.stringify([extId.value, viewType]); - } -} - export class MainThreadWebviewPanels extends Disposable implements extHostProtocol.MainThreadWebviewPanelsShape { private readonly webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-'); @@ -198,7 +158,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc } : {}; const extension = reviveWebviewExtension(extensionData); - const origin = this.webviewOriginStore.getOrigin(extension.id, viewType); + const origin = this.webviewOriginStore.getOrigin(viewType, extension.id); const webview = this._webviewWorkbenchService.openWebview({ id: handle, diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 77ec32db719..b99ea671d92 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -19,7 +19,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export interface IViewletViewOptions extends IViewPaneOptions { - fromExtensionId?: ExtensionIdentifier; + readonly fromExtensionId?: ExtensionIdentifier; } export abstract class FilterViewPaneContainer extends ViewPaneContainer { diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index 801cdae6d56..b08829ae769 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -10,10 +10,13 @@ import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IWebviewPortMapping } from 'vs/platform/webview/common/webviewPortMapping'; +import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; /** @@ -85,9 +88,6 @@ export interface WebviewOptions { transformCssVariables?(styles: WebviewStyles): WebviewStyles; } -/** - * - */ export interface WebviewContentOptions { /** * Should the webview allow `acquireVsCodeApi` to be called multiple times? Defaults to false. @@ -272,3 +272,40 @@ export interface IOverlayWebview extends IWebview { */ layoutWebviewOverElement(element: HTMLElement, dimension?: Dimension, clippingContainer?: HTMLElement): void; } + +/** + * Stores the unique origins for a webview. + * + * These are randomly generated, but keyed on extension and webview viewType. + */ +export class WebviewOriginStore { + + private readonly memento: Memento; + private readonly state: MementoObject; + + constructor( + rootStorageKey: string, + @IStorageService storageService: IStorageService, + ) { + this.memento = new Memento(rootStorageKey, storageService); + this.state = this.memento.getMemento(StorageScope.APPLICATION, StorageTarget.MACHINE); + } + + public getOrigin(viewType: string, extId: ExtensionIdentifier | undefined): string { + const key = this.getKey(viewType, extId); + + const existing = this.state[key]; + if (existing && typeof existing === 'string') { + return existing; + } + + const newOrigin = generateUuid(); + this.state[key] = newOrigin; + this.memento.saveMemento(); + return newOrigin; + } + + private getKey(viewType: string, extId: ExtensionIdentifier | undefined): string { + return JSON.stringify({ viewType, extension: extId?.value }); + } +} diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts index d72f98cb736..0ede150e8ce 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts @@ -24,7 +24,7 @@ import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { IViewBadge, IViewDescriptorService, IViewsService } from 'vs/workbench/common/views'; -import { IOverlayWebview, IWebviewService, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; +import { IOverlayWebview, IWebviewService, WebviewContentPurpose, WebviewOriginStore } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewWindowDragMonitor } from 'vs/workbench/contrib/webview/browser/webviewWindowDragMonitor'; import { IWebviewViewService, WebviewView } from 'vs/workbench/contrib/webviewView/browser/webviewViewService'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; @@ -38,6 +38,13 @@ const storageKeys = { export class WebviewViewPane extends ViewPane { + private static _originStore?: WebviewOriginStore; + + private static getOriginStore(storageService: IStorageService): WebviewOriginStore { + this._originStore ??= new WebviewOriginStore('webviewViews.origins', storageService); + return this._originStore; + } + private readonly _webview = this._register(new MutableDisposable()); private readonly _webviewDisposables = this._register(new DisposableStore()); private _activated = false; @@ -58,22 +65,22 @@ export class WebviewViewPane extends ViewPane { constructor( options: IViewletViewOptions, - @IKeybindingService keybindingService: IKeybindingService, - @IContextMenuService contextMenuService: IContextMenuService, @IConfigurationService configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, - @IViewDescriptorService viewDescriptorService: IViewDescriptorService, + @IContextMenuService contextMenuService: IContextMenuService, @IInstantiationService instantiationService: IInstantiationService, + @IKeybindingService keybindingService: IKeybindingService, @IOpenerService openerService: IOpenerService, - @IThemeService themeService: IThemeService, @ITelemetryService telemetryService: ITelemetryService, - @IStorageService storageService: IStorageService, + @IThemeService themeService: IThemeService, + @IViewDescriptorService viewDescriptorService: IViewDescriptorService, + @IActivityService private readonly activityService: IActivityService, @IExtensionService private readonly extensionService: IExtensionService, @IProgressService private readonly progressService: IProgressService, + @IStorageService private readonly storageService: IStorageService, + @IViewsService private readonly viewService: IViewsService, @IWebviewService private readonly webviewService: IWebviewService, @IWebviewViewService private readonly webviewViewService: IWebviewViewService, - @IViewsService private readonly viewService: IViewsService, - @IActivityService private activityService: IActivityService ) { super({ ...options, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); this.extensionId = options.fromExtensionId; @@ -167,8 +174,10 @@ export class WebviewViewPane extends ViewPane { this._activated = true; const webviewId = generateUuid(); + const origin = WebviewViewPane.getOriginStore(this.storageService).getOrigin(this.id, this.extensionId); const webview = this.webviewService.createWebviewOverlay({ id: webviewId, + origin, providedViewType: this.id, options: { purpose: WebviewContentPurpose.WebviewView }, contentOptions: {}, From 493d27bf48037947094e76fa34998eb45fd2381c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 14 Oct 2022 00:05:59 -0700 Subject: [PATCH 577/599] Don't interrupt when deleting pending cells (#163609) Fix #163133 --- .../execute/executionEditorProgress.ts | 2 +- .../browser/controller/executeActions.ts | 2 +- .../notebookExecutionStateServiceImpl.ts | 57 ++++++++++++------- .../notebookEditorWidgetContextKeys.ts | 2 +- .../common/notebookExecutionStateService.ts | 3 +- .../notebookExecutionStateService.test.ts | 39 ++++++++++--- .../test/browser/testNotebookEditor.ts | 15 +++-- 7 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts b/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts index 2aef79dc87b..f60773f10f0 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts @@ -38,7 +38,7 @@ export class ExecutionEditorProgressController extends Disposable implements INo return; } - const executing = this._notebookExecutionStateService.getCellExecutionStatesForNotebook(this._notebookEditor.textModel?.uri) + const executing = this._notebookExecutionStateService.getCellExecutionsForNotebook(this._notebookEditor.textModel?.uri) .filter(exe => exe.state === NotebookCellExecutionState.Executing); const executionIsVisible = (exe: INotebookCellExecution) => { for (const range of this._notebookEditor.visibleRanges) { diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index eefafb7edab..9ba98a19c19 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -618,7 +618,7 @@ registerAction2(class RevealRunningCellAction extends NotebookAction { async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const notebookExecutionStateService = accessor.get(INotebookExecutionStateService); const notebook = context.notebookEditor.textModel.uri; - const executingCells = notebookExecutionStateService.getCellExecutionStatesForNotebook(notebook); + const executingCells = notebookExecutionStateService.getCellExecutionsForNotebook(notebook); if (executingCells[0]) { const cell = context.notebookEditor.getCellByHandle(executingCells[0].cellHandle); if (cell) { diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionStateServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionStateServiceImpl.ts index b1be91749fa..c38f92fe4c4 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionStateServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionStateServiceImpl.ts @@ -7,6 +7,7 @@ import { Emitter } from 'vs/base/common/event'; import { combinedDisposable, Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { isEqual } from 'vs/base/common/resources'; +import { withNullAsUndefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; @@ -14,6 +15,7 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no import { CellEditType, CellUri, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata, NotebookTextModelWillAddRemoveEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellExecutionUpdateType, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, ICellExecutionStateUpdate, IFailedCellInfo, INotebookCellExecution, INotebookExecutionStateService, INotebookFailStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; +import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; export class NotebookExecutionStateService extends Disposable implements INotebookExecutionStateService { @@ -68,11 +70,16 @@ export class NotebookExecutionStateService extends Disposable implements INotebo return undefined; } - getCellExecutionStatesForNotebook(notebook: URI): INotebookCellExecution[] { + getCellExecutionsForNotebook(notebook: URI): INotebookCellExecution[] { const exeMap = this._executions.get(notebook); return exeMap ? Array.from(exeMap.values()) : []; } + getCellExecutionsByHandleForNotebook(notebook: URI): Map | undefined { + const exeMap = this._executions.get(notebook); + return withNullAsUndefined(exeMap); + } + private _onCellExecutionDidChange(notebookUri: URI, cellHandle: number, exe: CellExecution): void { this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebookUri, cellHandle, exe)); } @@ -244,6 +251,7 @@ class NotebookExecutionListeners extends Disposable { constructor( notebook: URI, @INotebookService private readonly _notebookService: INotebookService, + @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, @INotebookExecutionService private readonly _notebookExecutionService: INotebookExecutionService, @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService, @ILogService private readonly _logService: ILogService, @@ -263,7 +271,7 @@ class NotebookExecutionListeners extends Disposable { private cancelAll(): void { this._logService.debug(`NotebookExecutionListeners#cancelAll`); - const exes = this._notebookExecutionStateService.getCellExecutionStatesForNotebook(this._notebookModel.uri); + const exes = this._notebookExecutionStateService.getCellExecutionsForNotebook(this._notebookModel.uri); this._notebookExecutionService.cancelNotebookCellHandles(this._notebookModel, exes.map(exe => exe.cellHandle)); } @@ -273,25 +281,34 @@ class NotebookExecutionListeners extends Disposable { } private onWillAddRemoveCells(e: NotebookTextModelWillAddRemoveEvent): void { - const notebookExes = this._notebookExecutionStateService.getCellExecutionStatesForNotebook(this._notebookModel.uri); - const handles = new Set(notebookExes.map(exe => exe.cellHandle)); - const myDeletedHandles = new Set(); - e.rawEvent.changes.forEach(([start, deleteCount]) => { - if (deleteCount) { - const deletedHandles = this._notebookModel.cells.slice(start, start + deleteCount).map(c => c.handle); - deletedHandles.forEach(h => { - if (handles.has(h)) { - myDeletedHandles.add(h); - } - }); + const notebookExes = this._notebookExecutionStateService.getCellExecutionsByHandleForNotebook(this._notebookModel.uri); + + const executingDeletedHandles = new Set(); + const pendingDeletedHandles = new Set(); + if (notebookExes) { + e.rawEvent.changes.forEach(([start, deleteCount]) => { + if (deleteCount) { + const deletedHandles = this._notebookModel.cells.slice(start, start + deleteCount).map(c => c.handle); + deletedHandles.forEach(h => { + const exe = notebookExes.get(h); + if (exe?.state === NotebookCellExecutionState.Executing) { + executingDeletedHandles.add(h); + } else if (exe) { + pendingDeletedHandles.add(h); + } + }); + } + }); + } + + if (executingDeletedHandles.size || pendingDeletedHandles.size) { + const kernel = this._notebookKernelService.getSelectedOrSuggestedKernel(this._notebookModel); + if (kernel) { + const implementsInterrupt = kernel.implementsInterrupt; + const handlesToCancel = implementsInterrupt ? [...executingDeletedHandles] : [...executingDeletedHandles, ...pendingDeletedHandles]; + this._logService.debug(`NotebookExecution#onWillAddRemoveCells, ${JSON.stringify([...handlesToCancel])}`); + kernel.cancelNotebookCellExecution(this._notebookModel.uri, handlesToCancel); } - - return false; - }); - - if (myDeletedHandles.size) { - this._logService.debug(`NotebookExecution#onWillAddRemoveCells, ${JSON.stringify([...myDeletedHandles])}`); - this._notebookExecutionService.cancelNotebookCellHandles(this._notebookModel, myDeletedHandles); } } } diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts index f8e26930397..7d69d360871 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts @@ -136,7 +136,7 @@ export class NotebookEditorContextKeys { private _updateForCellExecution(): void { if (this._editor.textModel) { - const notebookExe = this._notebookExecutionStateService.getCellExecutionStatesForNotebook(this._editor.textModel.uri); + const notebookExe = this._notebookExecutionStateService.getCellExecutionsForNotebook(this._editor.textModel.uri); this._someCellRunning.set(notebookExe.length > 0); } else { this._someCellRunning.set(false); diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts index 996364b1eb0..19660330113 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts @@ -60,7 +60,8 @@ export interface INotebookExecutionStateService { onDidChangeLastRunFailState: Event; forceCancelNotebookExecutions(notebookUri: URI): void; - getCellExecutionStatesForNotebook(notebook: URI): INotebookCellExecution[]; + getCellExecutionsForNotebook(notebook: URI): INotebookCellExecution[]; + getCellExecutionsByHandleForNotebook(notebook: URI): Map | undefined; getCellExecution(cellUri: URI): INotebookCellExecution | undefined; createCellExecution(notebook: URI, cellHandle: number): INotebookCellExecution; getLastFailedCellForNotebook(notebook: URI): number | undefined; diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts index e8f8a86798b..dd524a0eda0 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts @@ -72,20 +72,22 @@ suite('NotebookExecutionStateService', () => { return _withTestNotebook(cells, (editor, viewModel) => callback(viewModel, viewModel.notebookDocument)); } - test('cancel execution when cell is deleted', async function () { // TODO@roblou Should be a test for NotebookExecutionListeners, which can be a standalone contribution + function testCancelOnDelete(expectedCancels: number, implementsInterrupt: boolean) { return withTestNotebook([], async viewModel => { testNotebookModel = viewModel.notebookDocument; - let didCancel = false; + let cancels = 0; const kernel = new class extends TestNotebookKernel { + implementsInterrupt = implementsInterrupt; + constructor() { super({ languages: ['javascript'] }); } override async executeNotebookCellsRequest(): Promise { } - override async cancelNotebookCellExecution(): Promise { - didCancel = true; + override async cancelNotebookCellExecution(_uri: URI, handles: number[]): Promise { + cancels += handles.length; } }; kernelService.registerKernel(kernel); @@ -93,14 +95,33 @@ suite('NotebookExecutionStateService', () => { const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService); + // Should cancel executing and pending cells, when kernel does not implement interrupt const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); - executionStateService.createCellExecution(viewModel.uri, cell.handle); - assert.strictEqual(didCancel, false); + const cell2 = insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); + const cell3 = insertCellAtIndex(viewModel, 2, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); + insertCellAtIndex(viewModel, 3, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); // Not deleted + const exe = executionStateService.createCellExecution(viewModel.uri, cell.handle); // Executing + exe.confirm(); + exe.update([{ editType: CellExecutionUpdateType.ExecutionState, executionOrder: 1 }]); + const exe2 = executionStateService.createCellExecution(viewModel.uri, cell2.handle); // Pending + exe2.confirm(); + executionStateService.createCellExecution(viewModel.uri, cell3.handle); // Unconfirmed + assert.strictEqual(cancels, 0); viewModel.notebookDocument.applyEdits([{ - editType: CellEditType.Replace, index: 0, count: 1, cells: [] + editType: CellEditType.Replace, index: 0, count: 3, cells: [] }], true, undefined, () => undefined, undefined, false); - assert.strictEqual(didCancel, true); + assert.strictEqual(cancels, expectedCancels); }); + + } + + // TODO@roblou Could be a test just for NotebookExecutionListeners, which can be a standalone contribution + test('cancel execution when cell is deleted', async function () { + return testCancelOnDelete(3, false); + }); + + test('cancel execution when cell is deleted in interrupt-type kernel', async function () { + return testCancelOnDelete(1, true); }); test('fires onDidChangeCellExecution when cell is completed while deleted', async function () { @@ -219,7 +240,7 @@ class TestNotebookKernel implements INotebookKernel { preloadProvides: string[] = []; supportedLanguages: string[] = []; async executeNotebookCellsRequest(): Promise { } - async cancelNotebookCellExecution(): Promise { } + async cancelNotebookCellExecution(uri: URI, cellHandles: number[]): Promise { } constructor(opts?: { languages?: string[]; id?: string }) { this.supportedLanguages = opts?.languages ?? [PLAINTEXT_LANGUAGE_ID]; diff --git a/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts index 718588d06fe..649d20e9001 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/testNotebookEditor.ts @@ -413,11 +413,6 @@ class TestCellExecution implements INotebookCellExecution { } class TestNotebookExecutionStateService implements INotebookExecutionStateService { - - getLastFailedCellForNotebook(notebook: URI): number | undefined { - return; - } - _serviceBrand: undefined; private _executions = new ResourceMap(); @@ -428,7 +423,7 @@ class TestNotebookExecutionStateService implements INotebookExecutionStateServic forceCancelNotebookExecutions(notebookUri: URI): void { } - getCellExecutionStatesForNotebook(notebook: URI): INotebookCellExecution[] { + getCellExecutionsForNotebook(notebook: URI): INotebookCellExecution[] { return []; } @@ -442,4 +437,12 @@ class TestNotebookExecutionStateService implements INotebookExecutionStateServic this._executions.set(CellUri.generate(notebook, cellHandle), exe); return exe; } + + getCellExecutionsByHandleForNotebook(notebook: URI): Map | undefined { + return; + } + + getLastFailedCellForNotebook(notebook: URI): number | undefined { + return; + } } From ac9aff3521c2cbbde4e25ec431a403445c50955e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 14 Oct 2022 01:35:15 -0700 Subject: [PATCH 578/599] reenable terrapin (#163622) * drop npx for terrapin * enable terrapin by default --- .../darwin/product-build-darwin-cli-sign.yml | 6 +- .../darwin/product-build-darwin-sign.yml | 2 +- .../darwin/product-build-darwin-universal.yml | 2 +- .../darwin/product-build-darwin.yml | 330 ++++++++-------- .../linux/product-build-alpine.yml | 2 +- .../linux/product-build-linux-client.yml | 368 +++++++++--------- .../linux/product-build-linux-server.yml | 94 ++--- .../product-build-pr-cache.yml | 2 +- build/azure-pipelines/product-build.yml | 2 +- build/azure-pipelines/product-compile.yml | 116 +++--- build/azure-pipelines/sdl-scan.yml | 5 +- .../azure-pipelines/web/product-build-web.yml | 2 +- .../win32/product-build-win32.yml | 3 +- 13 files changed, 468 insertions(+), 466 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml index 431eb8ec09b..4c29271f35a 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml @@ -18,7 +18,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -40,6 +40,6 @@ steps: parameters: VSCODE_CLI_ARTIFACTS: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - - unsigned_vscode_cli_darwin_x64_cli + - unsigned_vscode_cli_darwin_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - - unsigned_vscode_cli_darwin_arm64_cli + - unsigned_vscode_cli_darwin_arm64_cli diff --git a/build/azure-pipelines/darwin/product-build-darwin-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-sign.yml index a4ac3731104..c58b5ef1bb4 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-sign.yml @@ -69,7 +69,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/darwin/product-build-darwin-universal.yml b/build/azure-pipelines/darwin/product-build-darwin-universal.yml index ebc7104d6ce..393308f99b5 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-universal.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-universal.yml @@ -69,7 +69,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index f8e3e1d2666..7ccd0344d2c 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -14,62 +14,62 @@ parameters: steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - checkout: self - fetchDepth: 1 - retryCountOnTaskFailure: 3 + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 - task: NodeTool@0 inputs: versionSpec: "16.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password,macos-developer-certificate,macos-developer-certificate-key" + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,macos-developer-certificate,macos-developer-certificate-key" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Compilation - path: $(Build.ArtifactStagingDirectory) - displayName: Download compilation output + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output + - script: | + set -e + tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz + displayName: Extract compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro - script: | mkdir -p .build @@ -98,7 +98,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -140,40 +140,40 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration) - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + # This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration) + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build client + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-darwin-$(VSCODE_ARCH)-min-ci + displayName: Build client - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - node build/azure-pipelines/mixin --server - displayName: Mix in server quality + - script: | + set -e + node build/azure-pipelines/mixin --server + displayName: Mix in server quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-darwin-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-darwin-$(VSCODE_ARCH)-min-ci - displayName: Build Server + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-darwin-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-darwin-$(VSCODE_ARCH)-min-ci + displayName: Build Server - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp "transpile-client-swc" "transpile-extensions" - displayName: Transpile + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp "transpile-client-swc" "transpile-extensions" + displayName: Transpile - script: | set -e @@ -183,132 +183,132 @@ steps: displayName: Find application path - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: unsigned_vscode_cli_darwin_arm64_cli - patterns: '**' - path: $(Build.ArtifactStagingDirectory)/cli - displayName: Download VS Code CLI - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_darwin_arm64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - - task: DownloadPipelineArtifact@2 - inputs: - artifact: unsigned_vscode_cli_darwin_x64_cli - patterns: '**' - path: $(Build.ArtifactStagingDirectory)/cli - displayName: Download VS Code CLI - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: unsigned_vscode_cli_darwin_x64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - - script: | - set -e - ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) - unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(APP_PATH)/Contents/Resources/app/bin" - chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" - if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" - fi - displayName: Make CLI executable + - script: | + set -e + ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) + unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(APP_PATH)/Contents/Resources/app/bin" + chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" + if [ "$(VSCODE_QUALITY)" != "stable" ]; then + mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" + fi + displayName: Make CLI executable - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - - template: product-build-darwin-test.yml - parameters: - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} - VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} - VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} + - template: product-build-darwin-test.yml + parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} + VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} + VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - # Setting hardened entitlements is a requirement for: - # * Apple notarization - # * Running tests on Big Sur (because Big Sur has additional security precautions) - - script: | - set -e - security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - security default-keychain -s $(agent.tempdirectory)/buildagent.keychain - security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain - echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 - security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain - VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js - displayName: Set Hardened Entitlements + # Setting hardened entitlements is a requirement for: + # * Apple notarization + # * Running tests on Big Sur (because Big Sur has additional security precautions) + - script: | + set -e + security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + security default-keychain -s $(agent.tempdirectory)/buildagent.keychain + security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain + echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12 + security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain + VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js + displayName: Set Hardened Entitlements - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - script: | - set -e - pushd $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) && zip -r -X -y $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip * && popd - displayName: Archive build + - script: | + set -e + pushd $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) && zip -r -X -y $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip * && popd + displayName: Archive build - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - script: | - set -e + - script: | + set -e - # package Remote Extension Host - pushd .. && mv vscode-reh-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH) && zip -Xry vscode-server-darwin-$(VSCODE_ARCH).zip vscode-server-darwin-$(VSCODE_ARCH) && popd + # package Remote Extension Host + pushd .. && mv vscode-reh-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH) && zip -Xry vscode-server-darwin-$(VSCODE_ARCH).zip vscode-server-darwin-$(VSCODE_ARCH) && popd - # package Remote Extension Host (Web) - pushd .. && mv vscode-reh-web-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH)-web && zip -Xry vscode-server-darwin-$(VSCODE_ARCH)-web.zip vscode-server-darwin-$(VSCODE_ARCH)-web && popd - displayName: Prepare to publish servers + # package Remote Extension Host (Web) + pushd .. && mv vscode-reh-web-darwin-$(VSCODE_ARCH) vscode-server-darwin-$(VSCODE_ARCH)-web && zip -Xry vscode-server-darwin-$(VSCODE_ARCH)-web.zip vscode-server-darwin-$(VSCODE_ARCH)-web && popd + displayName: Prepare to publish servers - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (client) - inputs: - BuildDropPath: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - PackageName: Visual Studio Code + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (client) + inputs: + BuildDropPath: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + PackageName: Visual Studio Code - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (client) - artifact: vscode_client_darwin_$(VSCODE_ARCH)_sbom + - publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (client) + artifact: vscode_client_darwin_$(VSCODE_ARCH)_sbom - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (server) - inputs: - BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) - PackageName: Visual Studio Code Server + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (server) + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (server) - artifact: vscode_server_darwin_$(VSCODE_ARCH)_sbom + - publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (server) + artifact: vscode_server_darwin_$(VSCODE_ARCH)_sbom - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - publish: $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH).zip - artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive - displayName: Publish client archive + - publish: $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH).zip + artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive + displayName: Publish client archive - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH).zip - artifact: vscode_server_darwin_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish server archive + - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH).zip + artifact: vscode_server_darwin_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish server archive - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH)-web.zip - artifact: vscode_web_darwin_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish web server archive + - publish: $(Agent.BuildDirectory)/vscode-server-darwin-$(VSCODE_ARCH)-web.zip + artifact: vscode_web_darwin_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish web server archive - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - task: AzureCLI@2 - inputs: - azureSubscription: "vscode-builds-subscription" - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" + - task: AzureCLI@2 + inputs: + azureSubscription: "vscode-builds-subscription" + scriptType: pscore + scriptLocation: inlineScript + addSpnToEnvironment: true + inlineScript: | + Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" - ${{ if and(eq(parameters.VSCODE_PUBLISH, true), eq(parameters.VSCODE_RUN_UNIT_TESTS, false), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, false), eq(parameters.VSCODE_RUN_SMOKE_TESTS, false)) }}: - - script: | - set -e - AZURE_STORAGE_ACCOUNT="ticino" \ - AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ - AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ - AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - VSCODE_ARCH="$(VSCODE_ARCH)" \ - node build/azure-pipelines/upload-configuration - displayName: Upload configuration (for Bing settings search) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - continueOnError: true + - script: | + set -e + AZURE_STORAGE_ACCOUNT="ticino" \ + AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ + AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ + AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ + VSCODE_ARCH="$(VSCODE_ARCH)" \ + node build/azure-pipelines/upload-configuration + displayName: Upload configuration (for Bing settings search) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + continueOnError: true diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index c60f16d0804..34f08bd48c7 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -82,7 +82,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 13f48d400da..9b22c4b26e6 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -14,81 +14,81 @@ parameters: steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - checkout: self - fetchDepth: 1 - retryCountOnTaskFailure: 3 + - checkout: self + fetchDepth: 1 + retryCountOnTaskFailure: 3 - task: NodeTool@0 inputs: versionSpec: "16.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Compilation - path: $(Build.ArtifactStagingDirectory) - displayName: Download compilation output + - task: DownloadPipelineArtifact@2 + inputs: + artifact: Compilation + path: $(Build.ArtifactStagingDirectory) + displayName: Download compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: reh_node_modules-$(VSCODE_ARCH) - path: $(Build.ArtifactStagingDirectory) - displayName: Download server build dependencies - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: reh_node_modules-$(VSCODE_ARCH) + path: $(Build.ArtifactStagingDirectory) + displayName: Download server build dependencies + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - # Start X server - /etc/init.d/xvfb start - # Start dbus session - DBUS_LAUNCH_RESULT=$(sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address) - echo "##vso[task.setvariable variable=DBUS_SESSION_BUS_ADDRESS]$DBUS_LAUNCH_RESULT" - displayName: Setup system services - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - script: | + set -e + # Start X server + /etc/init.d/xvfb start + # Start dbus session + DBUS_LAUNCH_RESULT=$(sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address) + echo "##vso[task.setvariable variable=DBUS_SESSION_BUS_ADDRESS]$DBUS_LAUNCH_RESULT" + displayName: Setup system services + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz - displayName: Extract compilation output + - script: | + set -e + tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz + displayName: Extract compilation output - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro - script: | mkdir -p .build @@ -97,20 +97,20 @@ steps: displayName: Prepare yarn cache flags - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - task: Cache@2 - inputs: - key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash" - path: .build/node_modules_cache - cacheHitVar: NODE_MODULES_RESTORED - displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash" + path: .build/node_modules_cache + cacheHitVar: NODE_MODULES_RESTORED + displayName: Restore node_modules cache - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: Cache@2 - inputs: - key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" - path: .build/node_modules_cache - cacheHitVar: NODE_MODULES_RESTORED - displayName: Restore node_modules cache + - task: Cache@2 + inputs: + key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" + path: .build/node_modules_cache + cacheHitVar: NODE_MODULES_RESTORED + displayName: Restore node_modules cache - task: Cache@2 inputs: @@ -126,7 +126,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -204,12 +204,12 @@ steps: displayName: Download missing built-in extensions - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - rm -rf remote/node_modules - tar -xzf $(Build.ArtifactStagingDirectory)/reh_node_modules-$(VSCODE_ARCH).tar.gz --directory $(Build.SourcesDirectory)/remote - displayName: Extract server node_modules output - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) + - script: | + set -e + rm -rf remote/node_modules + tar -xzf $(Build.ArtifactStagingDirectory)/reh_node_modules-$(VSCODE_ARCH).tar.gz --directory $(Build.SourcesDirectory)/remote + displayName: Extract server node_modules output + condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'armhf')) - script: | set -e @@ -220,160 +220,160 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci - displayName: Build + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-linux-$(VSCODE_ARCH)-min-ci + displayName: Build - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - node build/azure-pipelines/mixin --server - displayName: Mix in server quality + - script: | + set -e + node build/azure-pipelines/mixin --server + displayName: Mix in server quality - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci - displayName: Build Server + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-linux-$(VSCODE_ARCH)-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-linux-$(VSCODE_ARCH)-min-ci + displayName: Build Server - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp "transpile-client-swc" "transpile-extensions" - displayName: Transpile + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp "transpile-client-swc" "transpile-extensions" + displayName: Transpile - ${{ if eq(parameters.VSCODE_BUILD_TUNNEL_CLI, true) }}: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: vscode_cli_linux_arm64_cli - patterns: '**' - path: $(Build.ArtifactStagingDirectory)/cli - displayName: Download VS Code CLI - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_arm64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - - task: DownloadPipelineArtifact@2 - inputs: - artifact: vscode_cli_linux_x64_cli - patterns: '**' - path: $(Build.ArtifactStagingDirectory)/cli - displayName: Download VS Code CLI - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vscode_cli_linux_x64_cli + patterns: "**" + path: $(Build.ArtifactStagingDirectory)/cli + displayName: Download VS Code CLI + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - - script: | - set -e - tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin - if [ "$(VSCODE_QUALITY)" != "stable" ]; then - mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" - fi - displayName: Make CLI executable + - script: | + set -e + tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin + if [ "$(VSCODE_QUALITY)" != "stable" ]; then + mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" + fi + displayName: Make CLI executable - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - - template: product-build-linux-client-test.yml - parameters: - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} - VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} - VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} + - template: product-build-linux-client-test.yml + parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} + VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} + VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - script: | - set -e - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" - displayName: Build deb, rpm packages + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" + yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-rpm" + displayName: Build deb, rpm packages - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - script: | - set -e - yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" - displayName: Prepare snap package + - script: | + set -e + yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-snap" + displayName: Prepare snap package - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - task: UseDotNet@2 - inputs: - version: 2.x + - task: UseDotNet@2 + inputs: + version: 2.x - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - task: EsrpClientTool@1 - displayName: Download ESRPClient + - task: EsrpClientTool@1 + displayName: Download ESRPClient - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - script: | - set -e - node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" rpm $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) .build/linux/rpm '*.rpm' - displayName: Codesign rpm + - script: | + set -e + node build/azure-pipelines/common/sign "$(esrpclient.toolpath)/$(esrpclient.toolname)" rpm $(ESRP-PKI) $(esrp-aad-username) $(esrp-aad-password) .build/linux/rpm '*.rpm' + displayName: Codesign rpm - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - script: | - set -e - VSCODE_ARCH="$(VSCODE_ARCH)" \ - ./build/azure-pipelines/linux/prepare-publish.sh - displayName: Prepare for Publish + - script: | + set -e + VSCODE_ARCH="$(VSCODE_ARCH)" \ + ./build/azure-pipelines/linux/prepare-publish.sh + displayName: Prepare for Publish - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (client) - inputs: - BuildDropPath: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - PackageName: Visual Studio Code + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (client) + inputs: + BuildDropPath: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + PackageName: Visual Studio Code - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (client) - artifact: vscode_client_linux_$(VSCODE_ARCH)_sbom + - publish: $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (client) + artifact: vscode_client_linux_$(VSCODE_ARCH)_sbom - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: Generate SBOM (server) - inputs: - BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) - PackageName: Visual Studio Code Server + - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: Generate SBOM (server) + inputs: + BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) + PackageName: Visual Studio Code Server - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH)/_manifest - displayName: Publish SBOM (server) - artifact: vscode_server_linux_$(VSCODE_ARCH)_sbom + - publish: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH)/_manifest + displayName: Publish SBOM (server) + artifact: vscode_server_linux_$(VSCODE_ARCH)_sbom - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(DEB_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_deb-package - displayName: Publish deb package + - publish: $(DEB_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_deb-package + displayName: Publish deb package - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(RPM_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_rpm-package - displayName: Publish rpm package + - publish: $(RPM_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_rpm-package + displayName: Publish rpm package - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(TARBALL_PATH) - artifact: vscode_client_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish client archive + - publish: $(TARBALL_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish client archive - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH).tar.gz - artifact: vscode_server_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish server archive + - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH).tar.gz + artifact: vscode_server_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish server archive - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH)-web.tar.gz - artifact: vscode_web_linux_$(VSCODE_ARCH)_archive-unsigned - displayName: Publish web server archive + - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH)-web.tar.gz + artifact: vscode_web_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish web server archive - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: - - task: PublishPipelineArtifact@0 - displayName: "Publish Pipeline Artifact" - inputs: - artifactName: "snap-$(VSCODE_ARCH)" - targetPath: .build/linux/snap-tarball + - task: PublishPipelineArtifact@0 + displayName: "Publish Pipeline Artifact" + inputs: + artifactName: "snap-$(VSCODE_ARCH)" + targetPath: .build/linux/snap-tarball diff --git a/build/azure-pipelines/linux/product-build-linux-server.yml b/build/azure-pipelines/linux/product-build-linux-server.yml index 8ab58da435c..ebec4113dc4 100644 --- a/build/azure-pipelines/linux/product-build-linux-server.yml +++ b/build/azure-pipelines/linux/product-build-linux-server.yml @@ -8,55 +8,55 @@ steps: versionSpec: "16.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + SecretsFilter: "github-distro-mixin-password,ESRP-PKI,esrp-aad-username,esrp-aad-password" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: Docker@1 - displayName: "Pull Docker image" - inputs: - azureSubscriptionEndpoint: "vscode-builds-subscription" - azureContainerRegistry: vscodehub.azurecr.io - command: "Run an image" - imageName: "vscode-linux-build-agent:centos7-devtoolset8-arm64" - containerCommand: uname - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - task: Docker@1 + displayName: "Pull Docker image" + inputs: + azureSubscriptionEndpoint: "vscode-builds-subscription" + azureContainerRegistry: vscodehub.azurecr.io + command: "Run an image" + imageName: "vscode-linux-build-agent:centos7-devtoolset8-arm64" + containerCommand: uname + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - cat << EOF > ~/.netrc - machine github.com - login vscode - password $(github-distro-mixin-password) - EOF + - script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF - git config user.email "vscode@microsoft.com" - git config user.name "VSCode" - displayName: Prepare tooling + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF - echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" - git checkout FETCH_HEAD - condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) - displayName: Checkout override commit + - script: | + set -e + git fetch https://github.com/$(VSCODE_MIXIN_REPO).git $VSCODE_DISTRO_REF + echo "##vso[task.setvariable variable=VSCODE_DISTRO_COMMIT;]$(git rev-parse FETCH_HEAD)" + git checkout FETCH_HEAD + condition: and(succeeded(), ne(variables.VSCODE_DISTRO_REF, ' ')) + displayName: Checkout override commit - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") - displayName: Merge distro + - script: | + set -e + git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") + displayName: Merge distro - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -71,18 +71,18 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - displayName: Register Docker QEMU - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - script: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + displayName: Register Docker QEMU + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - docker run -e VSCODE_QUALITY -e GITHUB_TOKEN -v $(pwd):/root/vscode -v ~/.netrc:/root/.netrc vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-arm64 /root/vscode/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh - displayName: Install dependencies via qemu - env: - GITHUB_TOKEN: "$(github-distro-mixin-password)" - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) + - script: | + set -e + docker run -e VSCODE_QUALITY -e GITHUB_TOKEN -v $(pwd):/root/vscode -v ~/.netrc:/root/.netrc vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-arm64 /root/vscode/build/azure-pipelines/linux/scripts/install-remote-dependencies.sh + displayName: Install dependencies via qemu + env: + GITHUB_TOKEN: "$(github-distro-mixin-password)" + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'arm64')) - script: | set -e diff --git a/build/azure-pipelines/product-build-pr-cache.yml b/build/azure-pipelines/product-build-pr-cache.yml index 042325394d3..7a6aaa7e559 100644 --- a/build/azure-pipelines/product-build-pr-cache.yml +++ b/build/azure-pipelines/product-build-pr-cache.yml @@ -34,7 +34,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index c876066ef04..8110d9aaea3 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -28,7 +28,7 @@ parameters: - name: ENABLE_TERRAPIN displayName: "Enable Terrapin" type: boolean - default: false + default: true - name: VSCODE_BUILD_WIN32 displayName: "🎯 Windows x64" type: boolean diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index b0631e607dc..7e1837a8ae4 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -40,7 +40,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -86,11 +86,11 @@ steps: displayName: Create node_modules archive - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - # Mixin must run before optimize, because the CSS loader will inline small SVGs - - script: | - set -e - node build/azure-pipelines/mixin - displayName: Mix in quality + # Mixin must run before optimize, because the CSS loader will inline small SVGs + - script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - script: | set -e @@ -100,71 +100,71 @@ steps: displayName: Compile & Hygiene - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - yarn --cwd build compile - ./.github/workflows/check-clean-git-state.sh - displayName: Check /build/ folder + - script: | + set -e + yarn --cwd build compile + ./.github/workflows/check-clean-git-state.sh + displayName: Check /build/ folder - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - yarn --cwd test/smoke compile - yarn --cwd test/integration/browser compile - displayName: Compile test suites - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | + set -e + yarn --cwd test/smoke compile + yarn --cwd test/integration/browser compile + displayName: Compile test suites + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: AzureCLI@2 - inputs: - azureSubscription: "vscode-builds-subscription" - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" + - task: AzureCLI@2 + inputs: + azureSubscription: "vscode-builds-subscription" + scriptType: pscore + scriptLocation: inlineScript + addSpnToEnvironment: true + inlineScript: | + Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId" + Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;issecret=true]$env:servicePrincipalKey" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - AZURE_STORAGE_ACCOUNT="ticino" \ - AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ - AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ - AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ - node build/azure-pipelines/upload-sourcemaps - displayName: Upload sourcemaps + - script: | + set -e + AZURE_STORAGE_ACCOUNT="ticino" \ + AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \ + AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \ + AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \ + node build/azure-pipelines/upload-sourcemaps + displayName: Upload sourcemaps - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set - - ./build/azure-pipelines/common/extract-telemetry.sh - displayName: Extract Telemetry + - script: | + set - + ./build/azure-pipelines/common/extract-telemetry.sh + displayName: Extract Telemetry - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - tar -cz --ignore-failed-read -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-* test/integration/browser/out test/smoke/out test/automation/out - displayName: Compress compilation artifact + - script: | + set -e + tar -cz --ignore-failed-read -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-* test/integration/browser/out test/smoke/out test/automation/out + displayName: Compress compilation artifact - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz - artifactName: Compilation - displayName: Publish compilation artifact + - task: PublishPipelineArtifact@1 + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz + artifactName: Compilation + displayName: Publish compilation artifact - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn download-builtin-extensions-cg - displayName: Built-in extensions component details + - script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn download-builtin-extensions-cg + displayName: Built-in extensions component details - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - inputs: - sourceScanPath: $(Build.SourcesDirectory) - continueOnError: true + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + inputs: + sourceScanPath: $(Build.SourcesDirectory) + continueOnError: true diff --git a/build/azure-pipelines/sdl-scan.yml b/build/azure-pipelines/sdl-scan.yml index f6a44d4862b..1df26feebbd 100644 --- a/build/azure-pipelines/sdl-scan.yml +++ b/build/azure-pipelines/sdl-scan.yml @@ -83,7 +83,8 @@ stages: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { npx https://aka.ms/enablesecurefeed standAlone } + exec { npm install https://aka.ms/enablesecurefeed --global } + exec { npm exec terrapinadotask -- standAlone } timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), eq(variables['ENABLE_TERRAPIN'], 'true')) @@ -184,7 +185,7 @@ stages: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index 61e409d4859..735b26cb0e7 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -73,7 +73,7 @@ steps: - script: | set -e - npx https://aka.ms/enablesecurefeed standAlone + npm install https://aka.ms/enablesecurefeed --global && npm exec terrapinadotask -- standAlone timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7145cd689c1..0eb1ab16978 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -108,7 +108,8 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { npx https://aka.ms/enablesecurefeed standAlone } + exec { npm install https://aka.ms/enablesecurefeed --global } + exec { npm exec terrapinadotask -- standAlone } timeoutInMinutes: 5 retryCountOnTaskFailure: 3 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) From 5e8b6807b1e6c007f26233932e8383c3e6880452 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 14 Oct 2022 04:16:07 -0700 Subject: [PATCH 579/599] Command Center With Help (#163635) * Command Center With Modes * fix bug --- .../quickinput/browser/helpQuickAccess.ts | 45 ++++--- .../quickinput/browser/pickerQuickAccess.ts | 8 +- .../quickinput/browser/quickAccess.ts | 21 +++- .../platform/quickinput/common/quickAccess.ts | 23 +++- .../browser/actions/quickAccessActions.ts | 27 ++++- .../parts/titlebar/commandCenterControl.ts | 2 +- .../search/browser/anythingQuickAccess.ts | 111 +++++++++++++++--- 7 files changed, 185 insertions(+), 52 deletions(-) diff --git a/src/vs/platform/quickinput/browser/helpQuickAccess.ts b/src/vs/platform/quickinput/browser/helpQuickAccess.ts index 90d85542cca..e77794d189b 100644 --- a/src/vs/platform/quickinput/browser/helpQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/helpQuickAccess.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { Extensions, IQuickAccessProvider, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; +import { Extensions, IQuickAccessProvider, IQuickAccessProviderDescriptor, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; import { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; interface IHelpQuickAccessPickItem extends IQuickPickItem { @@ -46,34 +46,33 @@ export class HelpQuickAccessProvider implements IQuickAccessProvider { })); // Fill in all providers - picker.items = this.getQuickAccessProviders(); + picker.items = this.getQuickAccessProviders().filter(p => p.prefix !== HelpQuickAccessProvider.PREFIX); return disposables; } - private getQuickAccessProviders(): IHelpQuickAccessPickItem[] { - const providers: IHelpQuickAccessPickItem[] = []; - - for (const provider of this.registry.getQuickAccessProviders().sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix))) { - if (provider.prefix === HelpQuickAccessProvider.PREFIX) { - continue; // exclude help which is already active - } - - for (const helpEntry of provider.helpEntries) { - const prefix = helpEntry.prefix || provider.prefix; - const label = prefix || '\u2026' /* ... */; - - providers.push({ - prefix, - label, - keybinding: helpEntry.commandId ? this.keybindingService.lookupKeybinding(helpEntry.commandId) : undefined, - ariaLabel: localize('helpPickAriaLabel', "{0}, {1}", label, helpEntry.description), - description: helpEntry.description - }); - } - } + public getQuickAccessProviders(): IHelpQuickAccessPickItem[] { + const providers: IHelpQuickAccessPickItem[] = this.registry + .getQuickAccessProviders() + .sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix)) + .flatMap(provider => this.createPicks(provider)); return providers; } + + private createPicks(provider: IQuickAccessProviderDescriptor): IHelpQuickAccessPickItem[] { + return provider.helpEntries.map(helpEntry => { + const prefix = helpEntry.prefix || provider.prefix; + const label = prefix || '\u2026' /* ... */; + + return { + prefix, + label, + keybinding: helpEntry.commandId ? this.keybindingService.lookupKeybinding(helpEntry.commandId) : undefined, + ariaLabel: localize('helpPickAriaLabel', "{0}, {1}", label, helpEntry.description), + description: helpEntry.description + }; + }); + } } diff --git a/src/vs/platform/quickinput/browser/pickerQuickAccess.ts b/src/vs/platform/quickinput/browser/pickerQuickAccess.ts index bba15d63cfc..eb07b7d3dce 100644 --- a/src/vs/platform/quickinput/browser/pickerQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/pickerQuickAccess.ts @@ -7,7 +7,7 @@ import { timeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IKeyMods, IQuickPickDidAcceptEvent, IQuickPickSeparator } from 'vs/base/parts/quickinput/common/quickInput'; -import { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess'; +import { IQuickAccessProvider, IQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess'; import { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; export enum TriggerAction { @@ -97,7 +97,7 @@ export abstract class PickerQuickAccessProvider, token: CancellationToken): IDisposable { + provide(picker: IQuickPick, token: CancellationToken, runOptions?: IQuickAccessProviderRunOptions): IDisposable { const disposables = new DisposableStore(); // Apply options if any @@ -122,7 +122,7 @@ export abstract class PickerQuickAccessProvider, skipEmpty?: boolean): boolean => { let items: readonly Pick[]; @@ -338,5 +338,5 @@ export abstract class PickerQuickAccessProvider | Promise> | FastAndSlowPicks | null; + protected abstract _getPicks(filter: string, disposables: DisposableStore, token: CancellationToken, runOptions?: IQuickAccessProviderRunOptions): Picks | Promise> | FastAndSlowPicks | null; } diff --git a/src/vs/platform/quickinput/browser/quickAccess.ts b/src/vs/platform/quickinput/browser/quickAccess.ts index b2ed573cc72..8b131cde8f9 100644 --- a/src/vs/platform/quickinput/browser/quickAccess.ts +++ b/src/vs/platform/quickinput/browser/quickAccess.ts @@ -8,7 +8,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { once } from 'vs/base/common/functional'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { DefaultQuickAccessFilterValue, Extensions, IQuickAccessController, IQuickAccessOptions, IQuickAccessProvider, IQuickAccessProviderDescriptor, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; +import { DefaultQuickAccessFilterValue, Extensions, IQuickAccessController, IQuickAccessOptions, IQuickAccessProvider, IQuickAccessProviderDescriptor, IQuickAccessProviderRunOptions, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess'; import { IQuickInputService, IQuickPick, IQuickPickItem, ItemActivation } from 'vs/platform/quickinput/common/quickInput'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -122,14 +122,14 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon } // Register listeners - disposables.add(this.registerPickerListeners(picker, provider, descriptor, value)); + disposables.add(this.registerPickerListeners(picker, provider, descriptor, value, options?.providerOptions)); // Ask provider to fill the picker as needed if we have one // and pass over a cancellation token that will indicate when // the picker is hiding without a pick being made. const cts = disposables.add(new CancellationTokenSource()); if (provider) { - disposables.add(provider.provide(picker, cts.token)); + disposables.add(provider.provide(picker, cts.token, options?.providerOptions)); } // Finally, trigger disposal and cancellation when the picker @@ -173,7 +173,13 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon picker.valueSelection = valueSelection; } - private registerPickerListeners(picker: IQuickPick, provider: IQuickAccessProvider | undefined, descriptor: IQuickAccessProviderDescriptor | undefined, value: string): IDisposable { + private registerPickerListeners( + picker: IQuickPick, + provider: IQuickAccessProvider | undefined, + descriptor: IQuickAccessProviderDescriptor | undefined, + value: string, + providerOptions?: IQuickAccessProviderRunOptions + ): IDisposable { const disposables = new DisposableStore(); // Remember as last visible picker and clean up once picker get's disposed @@ -189,7 +195,12 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon disposables.add(picker.onDidChangeValue(value => { const [providerForValue] = this.getOrInstantiateProvider(value); if (providerForValue !== provider) { - this.show(value, { preserveValue: true } /* do not rewrite value from user typing! */); + this.show(value, { + // do not rewrite value from user typing! + preserveValue: true, + // persist the value of the providerOptions from the original showing + providerOptions: providerOptions + }); } else { visibleQuickAccess.value = value; // remember the value in our visible one } diff --git a/src/vs/platform/quickinput/common/quickAccess.ts b/src/vs/platform/quickinput/common/quickAccess.ts index 18976f270ba..a15069be8aa 100644 --- a/src/vs/platform/quickinput/common/quickAccess.ts +++ b/src/vs/platform/quickinput/common/quickAccess.ts @@ -10,6 +10,19 @@ import { ItemActivation } from 'vs/base/parts/quickinput/common/quickInput'; import { IQuickNavigateConfiguration, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { Registry } from 'vs/platform/registry/common/platform'; +/** + * Provider specific options for this particular showing of the + * quick access. + */ +export interface IQuickAccessProviderRunOptions { } + +/** + * The specific options for the AnythingQuickAccessProvider. Put here to share between layers. + */ +export interface AnythingQuickAccessProviderRunOptions extends IQuickAccessProviderRunOptions { + includeHelp?: boolean; +} + export interface IQuickAccessOptions { /** @@ -28,6 +41,12 @@ export interface IQuickAccessOptions { * from any existing value if quick access is visible. */ preserveValue?: boolean; + + /** + * Provider specific options for this particular showing of the + * quick access. + */ + providerOptions?: IQuickAccessProviderRunOptions; } export interface IQuickAccessController { @@ -80,10 +99,12 @@ export interface IQuickAccessProvider { * a long running operation or from event handlers because it could be that the * picker has been closed or changed meanwhile. The token can be used to find out * that the picker was closed without picking an entry (e.g. was canceled by the user). + * @param options additional configuration specific for this provider that will + * influence what picks will be shown. * @return a disposable that will automatically be disposed when the picker * closes or is replaced by another picker. */ - provide(picker: IQuickPick, token: CancellationToken): IDisposable; + provide(picker: IQuickPick, token: CancellationToken, options?: IQuickAccessProviderRunOptions): IDisposable; } export interface IQuickAccessProviderHelp { diff --git a/src/vs/workbench/browser/actions/quickAccessActions.ts b/src/vs/workbench/browser/actions/quickAccessActions.ts index 6cda33c142c..ba895c00fd6 100644 --- a/src/vs/workbench/browser/actions/quickAccessActions.ts +++ b/src/vs/workbench/browser/actions/quickAccessActions.ts @@ -13,6 +13,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { inQuickPickContext, defaultQuickAccessContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess'; import { ILocalizedString } from 'vs/platform/action/common/action'; +import { AnythingQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess'; //#region Quick access management commands and keys @@ -139,6 +140,24 @@ registerAction2(class QuickAccessAction extends Action2 { secondary: globalQuickAccessKeybinding.secondary, mac: globalQuickAccessKeybinding.mac }, + f1: true + }); + } + + run(accessor: ServicesAccessor, prefix: undefined): void { + const quickInputService = accessor.get(IQuickInputService); + quickInputService.quickAccess.show(typeof prefix === 'string' ? prefix : undefined, { preserveValue: typeof prefix === 'string' /* preserve as is if provided */ }); + } +}); + +registerAction2(class QuickAccessAction extends Action2 { + constructor() { + super({ + id: 'workbench.action.quickOpenWithModes', + title: { + value: localize('quickOpenWithModes', "Launch Command Center"), + original: 'Launch Command Center' + }, f1: true, menu: { id: MenuId.CommandCenter, @@ -147,9 +166,13 @@ registerAction2(class QuickAccessAction extends Action2 { }); } - run(accessor: ServicesAccessor, prefix: undefined): void { + run(accessor: ServicesAccessor): void { const quickInputService = accessor.get(IQuickInputService); - quickInputService.quickAccess.show(typeof prefix === 'string' ? prefix : undefined, { preserveValue: typeof prefix === 'string' /* preserve as is if provided */ }); + quickInputService.quickAccess.show(undefined, { + providerOptions: { + includeHelp: true, + } as AnythingQuickAccessProviderRunOptions + }); } }); diff --git a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts index b281f030a55..e59c60f87f6 100644 --- a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts @@ -50,7 +50,7 @@ export class CommandCenterControl { telemetrySource: 'commandCenter', actionViewItemProvider: (action) => { - if (action instanceof MenuItemAction && action.id === 'workbench.action.quickOpen') { + if (action instanceof MenuItemAction && action.id === 'workbench.action.quickOpenWithModes') { class CommandCenterViewItem extends BaseActionViewItem { diff --git a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts index 3a37e9524d2..8708e7c1378 100644 --- a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts +++ b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/anythingQuickAccess'; -import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick, IQuickPickItemWithResource, QuickInputHideReason } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick, IQuickPickItemWithResource, QuickInputHideReason, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction, FastAndSlowPicks, Picks, PicksWithActive } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { prepareQuery, IPreparedQuery, compareItemsByFuzzyScore, scoreItemFuzzy, FuzzyScorerCache } from 'vs/base/common/fuzzyScorer'; import { IFileQueryBuilderOptions, QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder'; @@ -40,7 +40,7 @@ import { Schemas } from 'vs/base/common/network'; import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ResourceMap } from 'vs/base/common/map'; import { SymbolsQuickAccessProvider } from 'vs/workbench/contrib/search/browser/symbolsQuickAccess'; -import { DefaultQuickAccessFilterValue } from 'vs/platform/quickinput/common/quickAccess'; +import { AnythingQuickAccessProviderRunOptions, DefaultQuickAccessFilterValue } from 'vs/platform/quickinput/common/quickAccess'; import { IWorkbenchQuickAccessConfiguration } from 'vs/workbench/browser/quickaccess'; import { GotoSymbolQuickAccessProvider } from 'vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -52,6 +52,10 @@ import { withNullAsUndefined } from 'vs/base/common/types'; import { Codicon } from 'vs/base/common/codicons'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { stripIcons } from 'vs/base/common/iconLabels'; +import { HelpQuickAccessProvider } from 'vs/platform/quickinput/browser/helpQuickAccess'; +import { CommandsQuickAccessProvider } from 'vs/workbench/contrib/quickaccess/browser/commandsQuickAccess'; +import { DEBUG_QUICK_ACCESS_PREFIX } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { TasksQuickAccessProvider } from 'vs/workbench/contrib/tasks/browser/tasksQuickAccess'; interface IAnythingQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource { } @@ -178,7 +182,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider, token: CancellationToken): IDisposable { + override provide(picker: IQuickPick, token: CancellationToken, runOptions?: AnythingQuickAccessProviderRunOptions): IDisposable { const disposables = new DisposableStore(); // Update the pick state for this run @@ -233,7 +238,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider this.clearDecorations(activeEditorControl)); } - protected _getPicks(originalFilter: string, disposables: DisposableStore, token: CancellationToken): Picks | Promise> | FastAndSlowPicks | null { + protected _getPicks(originalFilter: string, disposables: DisposableStore, token: CancellationToken, runOptions?: AnythingQuickAccessProviderRunOptions): Picks | Promise> | FastAndSlowPicks | null { // Find a suitable range from the pattern looking for ":", "#" or "," // unless we have the `@` editor symbol character inside the filter @@ -316,10 +321,15 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider | Promise> | FastAndSlowPicks { + private doGetPicks( + filter: string, + options: AnythingQuickAccessProviderRunOptions & { enableEditorSymbolSearch: boolean }, + disposables: DisposableStore, + token: CancellationToken + ): Picks | Promise> | FastAndSlowPicks { const query = prepareQuery(filter); // Return early if we have editor symbol picks. We support this by: @@ -343,16 +353,24 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider; + if (this.pickState.isQuickNavigating) { + picks = historyEditorPicks; + } else { + picks = []; + if (options.includeHelp) { + picks.push(...this.getHelpPicks(query, token)); + } + if (historyEditorPicks.length !== 0) { + picks.push({ type: 'separator', label: localize('recentlyOpenedSeparator', "recently opened") } as IQuickPickSeparator); + picks.push(...historyEditorPicks); + } + } + return { - // Fast picks: editor history - picks: - (this.pickState.isQuickNavigating || historyEditorPicks.length === 0) ? - historyEditorPicks : - [ - { type: 'separator', label: localize('recentlyOpenedSeparator', "recently opened") }, - ...historyEditorPicks - ], + // Fast picks: help (if included) & editor history + picks, // Slow picks: files and symbols additionalPicks: (async (): Promise> => { @@ -732,6 +750,67 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider = this.helpQuickAccess.getQuickAccessProviders(); + const mapOfProviders = new Map(); + for (const provider of providers) { + mapOfProviders.set(provider.prefix, provider); + } + + const importantProviders: Array = []; + const AddProvider = (prefix: string, modifications: Partial = {}) => { + if (mapOfProviders.has(prefix)) { + const provider = mapOfProviders.get(prefix)!; + + // We swap the label and description in this to emphasize the ability + // not the prefix. + provider.label = provider.description!; + provider.description = provider.prefix; + + // If the user chooses 'Go to File' the help should go away as if they were + // entering a new mode + const providerSpecificOptions: AnythingQuickAccessProviderRunOptions | undefined = provider.prefix === AnythingQuickAccessProvider.PREFIX + ? undefined + : { includeHelp: true }; + + importantProviders.push({ + ...mapOfProviders.get(prefix)!, + ...modifications, + accept: () => { + this.quickInputService.quickAccess.show(provider.prefix, { + preserveValue: true, + providerOptions: providerSpecificOptions + }); + } + }); + } + }; + + // Acts as the ordering too + AddProvider(AnythingQuickAccessProvider.PREFIX); + AddProvider(CommandsQuickAccessProvider.PREFIX); + AddProvider(GotoSymbolQuickAccessProvider.PREFIX); + AddProvider(DEBUG_QUICK_ACCESS_PREFIX); + AddProvider(TasksQuickAccessProvider.PREFIX); + AddProvider(HelpQuickAccessProvider.PREFIX, { + // More concise + label: localize('more', 'More') + }); + + return importantProviders; + } + + //#endregion //#region Workspace Symbols (if enabled) From 2204a16fb0808665178abb34c0e9033621b46592 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 14 Oct 2022 14:23:42 +0200 Subject: [PATCH 580/599] Fix #163343 --- .../platform/userDataProfile/common/userDataProfile.ts | 5 +++++ .../userDataProfile/electron-main/userDataProfile.ts | 5 ----- .../electron-sandbox/userDataProfile.ts | 10 ++++++++++ .../userDataSync/common/userDataSyncService.ts | 9 ++++++++- .../browser/parts/activitybar/activitybarPart.ts | 6 ++++-- src/vs/workbench/browser/web.main.ts | 2 +- .../contrib/userDataProfile/browser/userDataProfile.ts | 1 + .../contrib/userDataSync/browser/userDataSync.ts | 2 +- src/vs/workbench/electron-sandbox/desktop.main.ts | 4 +++- .../services/userDataProfile/common/userDataProfile.ts | 7 +++---- 10 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index c68e5cf1c99..2207f1a08e4 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -106,6 +106,7 @@ export interface IUserDataProfilesService { readonly onDidResetWorkspaces: Event; + isEnabled(): boolean; createNamedProfile(name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: WorkspaceIdentifier): Promise; createTransientProfile(workspaceIdentifier?: WorkspaceIdentifier): Promise; createProfile(id: string, name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: WorkspaceIdentifier): Promise; @@ -225,6 +226,10 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf } } + isEnabled(): boolean { + return this.enabled; + } + protected _profilesObject: UserDataProfilesObject | undefined; protected get profilesObject(): UserDataProfilesObject { if (!this._profilesObject) { diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index a5776c1fa3d..f5c902cc32a 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -18,7 +18,6 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; export const IUserDataProfilesMainService = refineServiceDecorator(IUserDataProfilesService); export interface IUserDataProfilesMainService extends IUserDataProfilesService { - isEnabled(): boolean; getOrSetProfileForWorkspace(workspaceIdentifier: WorkspaceIdentifier, profileToSet?: IUserDataProfile): IUserDataProfile; setProfileForWorkspaceSync(workspaceIdentifier: WorkspaceIdentifier, profileToSet: IUserDataProfile): void; checkAndCreateProfileFromCli(args: NativeParsedArgs): Promise | undefined; @@ -48,10 +47,6 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme } } - isEnabled(): boolean { - return this.enabled; - } - checkAndCreateProfileFromCli(args: NativeParsedArgs): Promise | undefined { if (!this.isEnabled()) { return undefined; diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts index af23d7e7f30..6bcd8ab1c3e 100644 --- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts @@ -29,6 +29,8 @@ export class UserDataProfilesNativeService extends Disposable implements IUserDa readonly onDidResetWorkspaces: Event; + private enabled: boolean = true; + constructor( profiles: readonly UriDto[], @IMainProcessService mainProcessService: IMainProcessService, @@ -48,6 +50,14 @@ export class UserDataProfilesNativeService extends Disposable implements IUserDa this.onDidResetWorkspaces = this.channel.listen('onDidResetWorkspaces'); } + setEnablement(enabled: boolean) { + this.enabled = enabled; + } + + isEnabled(): boolean { + return this.enabled; + } + async createNamedProfile(name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: WorkspaceIdentifier): Promise { const result = await this.channel.call>('createNamedProfile', [name, options, workspaceIdentifier]); return reviveProfile(result, this.profilesHome.scheme); diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 828b37cef34..813a43ad91a 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -418,6 +418,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return isUndefined(result) ? null : result; } + if (this.userDataProfilesService.isEnabled()) { + return null; + } + if (this.environmentService.isBuilt && (!this.productService.enableSyncingProfiles || isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.stableUrl))) { return null; } @@ -543,7 +547,7 @@ class ProfileSynchronizer extends Disposable { @ITelemetryService private readonly telemetryService: ITelemetryService, @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IProductService private readonly productService: IProductService, - @IUserDataProfilesService userDataProfilesService: IUserDataProfilesService, + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IConfigurationService private readonly configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, ) { @@ -590,6 +594,9 @@ class ProfileSynchronizer extends Disposable { if (!this._profile.isDefault) { return; } + if (!this.userDataProfilesService.isEnabled()) { + return; + } if (this.environmentService.isBuilt && (!this.productService.enableSyncingProfiles || isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.stableUrl))) { this.logService.debug('Skipping profiles sync'); return; diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index a0151834ec9..61d1afe68fe 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -196,7 +196,9 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart // Accounts actions.push(new Separator()); actions.push(toAction({ id: 'toggleAccountsVisibility', label: localize('accounts', "Accounts"), checked: this.accountsVisibilityPreference, run: () => this.accountsVisibilityPreference = !this.accountsVisibilityPreference })); - actions.push(toAction({ id: 'toggleProfilesVisibility', label: PROFILES_TTILE.value, checked: this.profilesVisibilityPreference, run: () => this.profilesVisibilityPreference = !this.profilesVisibilityPreference })); + if (this.userDataProfilesService.isEnabled()) { + actions.push(toAction({ id: 'toggleProfilesVisibility', label: PROFILES_TTILE.value, checked: this.profilesVisibilityPreference, run: () => this.profilesVisibilityPreference = !this.profilesVisibilityPreference })); + } actions.push(new Separator()); // Toggle Sidebar @@ -1064,7 +1066,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart } private get profilesVisibilityPreference(): boolean { - return this.storageService.getBoolean(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, this.userDataProfilesService.profiles.length > 1); + return this.userDataProfilesService.isEnabled() && this.storageService.getBoolean(ProfilesActivityActionViewItem.PROFILES_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, this.userDataProfilesService.profiles.length > 1); } private set profilesVisibilityPreference(value: boolean) { diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index e4e95239bba..b96c21e86d2 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -309,7 +309,7 @@ export class BrowserMain extends Disposable { }) ]); - userDataProfilesService.setEnablement(productService.quality !== 'stable' || configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); + userDataProfilesService.setEnablement(!environmentService.remoteAuthority && (productService.quality !== 'stable' || configurationService.getValue(PROFILES_ENABLEMENT_CONFIG))); this._register(configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(PROFILES_ENABLEMENT_CONFIG)) { userDataProfilesService.setEnablement(!!configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 1f8f5687d18..9861a884a99 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -48,6 +48,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements this.registerConfiguration(); this.currentProfileContext = CURRENT_PROFILE_CONTEXT.bindTo(contextKeyService); + PROFILES_ENABLEMENT_CONTEXT.bindTo(contextKeyService).set(this.userDataProfilesService.isEnabled()); this.isCurrentProfileTransientContext = IS_CURRENT_PROFILE_TRANSIENT_CONTEXT.bindTo(contextKeyService); this.currentProfileContext.set(this.userDataProfileService.currentProfile.id); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index dda7b8167bd..6ac33754732 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -609,7 +609,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo id: SyncResource.GlobalState, label: getSyncAreaLabel(SyncResource.GlobalState), }]; - if (!this.environmentService.isBuilt || this.productService.enableSyncingProfiles) { + if (this.userDataProfilesService.isEnabled() && (!this.environmentService.isBuilt || this.productService.enableSyncingProfiles)) { result.push({ id: SyncResource.Profiles, label: getSyncAreaLabel(SyncResource.Profiles), diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index ac5e9d14c95..a460d71c5f3 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -49,7 +49,7 @@ import { isCI, isMacintosh } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/workbench/services/files/electron-sandbox/diskFileSystemProvider'; import { FileUserDataProvider } from 'vs/platform/userData/common/fileUserDataProvider'; -import { IUserDataProfilesService, reviveProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfilesService, PROFILES_ENABLEMENT_CONFIG, reviveProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/electron-sandbox/userDataProfile'; import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; @@ -283,6 +283,8 @@ export class DesktopMain extends Disposable { }) ]); + userDataProfilesService.setEnablement(productService.quality !== 'stable' || configurationService.getValue(PROFILES_ENABLEMENT_CONFIG)); + // Workspace Trust Service const workspaceTrustEnablementService = new WorkspaceTrustEnablementService(configurationService, environmentService); serviceCollection.set(IWorkspaceTrustEnablementService, workspaceTrustEnablementService); diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts index f7efa31fe40..5b202dc50ca 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts @@ -8,9 +8,8 @@ import { Event } from 'vs/base/common/event'; import { localize } from 'vs/nls'; import { MenuId } from 'vs/platform/actions/common/actions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IUserDataProfile, IUserDataProfileOptions, IUserDataProfileUpdateOptions, PROFILES_ENABLEMENT_CONFIG } from 'vs/platform/userDataProfile/common/userDataProfile'; -import { ContextKeyDefinedExpr, ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ProductQualityContext } from 'vs/platform/contextkey/common/contextkeys'; +import { IUserDataProfile, IUserDataProfileOptions, IUserDataProfileUpdateOptions } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export interface DidChangeUserDataProfileEvent { readonly preserveData: boolean; @@ -78,7 +77,7 @@ export const PROFILES_TTILE = { value: localize('settings profiles', "Settings P export const PROFILES_CATEGORY = { ...PROFILES_TTILE }; export const PROFILE_EXTENSION = 'code-profile'; export const PROFILE_FILTER = [{ name: localize('profile', "Settings Profile"), extensions: [PROFILE_EXTENSION] }]; -export const PROFILES_ENABLEMENT_CONTEXT = ContextKeyExpr.or(ProductQualityContext.notEqualsTo('stable'), ContextKeyDefinedExpr.create(`config.${PROFILES_ENABLEMENT_CONFIG}`)); +export const PROFILES_ENABLEMENT_CONTEXT = new RawContextKey('profiles.enabled', true); export const CURRENT_PROFILE_CONTEXT = new RawContextKey('currentSettingsProfile', ''); export const IS_CURRENT_PROFILE_TRANSIENT_CONTEXT = new RawContextKey('isCurrentSettingsProfileTransient', false); export const HAS_PROFILES_CONTEXT = new RawContextKey('hasSettingsProfiles', false); From d49452248d0a52ed6d7f35f6fc41dea268a1b99f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 14 Oct 2022 15:00:28 +0200 Subject: [PATCH 581/599] joh/super quelea (#163642) * change how profiling sampling nodes are stringifyied so that they don't get confused as mail-address * re-enable renderer auto-profile * use/copy profiling model from https://github.com/microsoft/vscode-js-profile-visualizer extract heaviest call path from bottom up profile and submit as telemetry event --- src/vs/platform/profiling/common/profiling.ts | 4 + .../electron-main/windowProfiling.ts | 121 +----- .../platform/profiling/node/profilingModel.ts | 404 ++++++++++++++++++ .../electron-sandbox/rendererAutoProfiler.ts | 50 +-- 4 files changed, 447 insertions(+), 132 deletions(-) create mode 100644 src/vs/platform/profiling/node/profilingModel.ts diff --git a/src/vs/platform/profiling/common/profiling.ts b/src/vs/platform/profiling/common/profiling.ts index bf63e95ecc7..c4bfe9ddd24 100644 --- a/src/vs/platform/profiling/common/profiling.ts +++ b/src/vs/platform/profiling/common/profiling.ts @@ -45,6 +45,10 @@ export interface IV8InspectProfilingService { export namespace Utils { + export function isValidProfile(profile: IV8Profile): profile is Required { + return Boolean(profile.samples && profile.timeDeltas); + } + export function rewriteAbsolutePaths(profile: IV8Profile, replace: string = 'noAbsolutePaths') { for (const node of profile.nodes) { if (node.callFrame && node.callFrame.url) { diff --git a/src/vs/platform/profiling/electron-main/windowProfiling.ts b/src/vs/platform/profiling/electron-main/windowProfiling.ts index 18549159fe4..c2469272bac 100644 --- a/src/vs/platform/profiling/electron-main/windowProfiling.ts +++ b/src/vs/platform/profiling/electron-main/windowProfiling.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Profile, ProfileNode, ProfileResult } from 'v8-inspect-profiler'; +import type { Profile, ProfileResult } from 'v8-inspect-profiler'; import { BrowserWindow } from 'electron'; import { timeout } from 'vs/base/common/async'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; @@ -13,12 +13,14 @@ import { tmpdir } from 'os'; import { join } from 'vs/base/common/path'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Utils } from 'vs/platform/profiling/common/profiling'; +import { bottomUp, } from 'vs/platform/profiling/node/profilingModel'; type TelemetrySampleData = { sessionId: string; selfTime: number; totalTime: number; + percentage: number; functionName: string; callstack: string; }; @@ -27,44 +29,13 @@ type TelemetrySampleDataClassification = { owner: 'jrieken'; comment: 'A callstack that took a long time to execute'; sessionId: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Session identifier that allows to correlate samples from one profile' }; - selfTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Self time of the sample' }; - totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Total time of the sample' }; + selfTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Self time of the sample' }; + totalTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Total time of the sample' }; + percentage: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Relative time (percentage) of the sample' }; functionName: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The name of the sample' }; callstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The stacktrace leading into the sample' }; }; -class Node { - - // these are set later - parent: Node | undefined; - children: Node[] = []; - selfTime: number = -1; - totalTime: number = -1; - - constructor( - readonly node: ProfileNode, - readonly callFrame: typeof node.callFrame, - ) { - // noop - } - - toString() { - return `${this.callFrame.url}#${this.callFrame.functionName}@${this.callFrame.lineNumber}:${this.callFrame.columnNumber}`; - } - - static makeTotals(call: Node) { - if (call.totalTime !== -1) { - return call.totalTime; - } - let result = call.selfTime; - for (const child of call.children) { - result += Node.makeTotals(child); - } - call.totalTime = result; - return result; - } -} - export class WindowProfiler { private _profileAtOrAfter: number = 0; @@ -173,85 +144,21 @@ export class WindowProfiler { private _digest(profile: Profile): void { // https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-Profile - if (!profile.samples || !profile.timeDeltas) { + if (!Utils.isValidProfile(profile)) { this._logService.warn('[perf] INVALID profile: no samples or timeDeltas', this._sessionId); return; } - // PII removal - no absolute paths - Utils.rewriteAbsolutePaths(profile, 'piiRemoved'); - - // create nodes - const all = new Map(); - for (const node of profile.nodes) { - all.set(node.id, new Node(node, node.callFrame)); - } - - // set children/parents - for (const node of profile.nodes) { - if (node.children) { - const parent = all.get(node.id)!; - for (const id of node.children) { - const child = all.get(id)!; - parent.children.push(child); - child.parent = parent; - } - } - } - - // SELF times - const duration = (profile.endTime - profile.startTime); - let lastNodeTime = duration - profile.timeDeltas[0]; - for (let i = 0; i < profile.samples.length - 1; i++) { - const sample = profile.samples[i]; - const node = all.get(sample); - if (node) { - const duration = profile.timeDeltas[i + 1]; - node.selfTime += duration; - lastNodeTime -= duration; - } - } - const lastNode = all.get(profile.samples[profile.samples.length - 1]); - if (lastNode) { - lastNode.selfTime += lastNodeTime; - } - - // TOTAL times - all.forEach(Node.makeTotals); - - const sorted = Array.from(all.values()).sort((a, b) => b.selfTime - a.selfTime); - - if (sorted[0].callFrame.functionName === '(idle)') { - this._logService.warn('[perf] top stack is IDLE, ignoring this profile...', this._sessionId); - this._telemetryService.publicLog2('prof.sample', { - sessionId: this._sessionId, - selfTime: 0, - totalTime: 0, - functionName: '(idle)', - callstack: '' - }); - return; - } - - for (let i = 0; i < sorted.length; i++) { - if (i > 4) { - // report top 5 - break; - } - const node = sorted[i]; - const callstack: string[] = []; - let candidate: Node | undefined = node; - while (candidate) { - callstack.push(candidate.toString()); - candidate = candidate.parent; - } + const samples = bottomUp(profile, 5, false); + for (const sample of samples) { const data: TelemetrySampleData = { sessionId: this._sessionId, - selfTime: node.selfTime / 1000, - totalTime: node.totalTime / 1000, - functionName: node.callFrame.functionName, - callstack: callstack.join('\n') + selfTime: sample.selfTime, + totalTime: sample.totalTime, + percentage: sample.percentage, + functionName: sample.location, + callstack: sample.caller.map(c => `${c.percentage}|${c.location}`).join('<') }; this._telemetryService.publicLog2('prof.freeze.sample', data); } diff --git a/src/vs/platform/profiling/node/profilingModel.ts b/src/vs/platform/profiling/node/profilingModel.ts new file mode 100644 index 00000000000..fd5978eecec --- /dev/null +++ b/src/vs/platform/profiling/node/profilingModel.ts @@ -0,0 +1,404 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { Profile, ProfileNode } from 'v8-inspect-profiler'; +import { basename } from 'vs/base/common/path'; + +// #region +// https://github.com/microsoft/vscode-js-profile-visualizer/blob/6e7401128ee860be113a916f80fcfe20ac99418e/packages/vscode-js-profile-core/src/cpu/model.ts#L4 + +interface IProfileModel { + nodes: ReadonlyArray; + locations: ReadonlyArray; + samples: ReadonlyArray; + timeDeltas: ReadonlyArray; + rootPath?: string; + duration: number; +} + +interface IComputedNode { + id: number; + selfTime: number; + aggregateTime: number; + children: number[]; + parent?: number; + locationId: number; +} + +interface ISourceLocation { + lineNumber: number; + columnNumber: number; + // source: Dap.Source; + relativePath?: string; +} + +interface CdpCallFrame { + functionName: string; + scriptId: string; + url: string; + lineNumber: number; + columnNumber: number; +} + +interface CdpPositionTickInfo { + line: number; + ticks: number; +} + +interface INode { + id: number; + // category: Category; + callFrame: CdpCallFrame; + src?: ISourceLocation; +} + +interface ILocation extends INode { + selfTime: number; + aggregateTime: number; + ticks: number; +} + +interface IAnnotationLocation { + callFrame: CdpCallFrame; + locations: ISourceLocation[]; +} + +interface IProfileNode extends ProfileNode { + locationId?: number; + positionTicks?: (CdpPositionTickInfo & { + startLocationId?: number; + endLocationId?: number; + })[]; +} + +interface ICpuProfileRaw extends Profile { + // $vscode?: IJsDebugAnnotations; + nodes: IProfileNode[]; +} + + +/** + * Recursive function that computes and caches the aggregate time for the + * children of the computed now. + */ +const computeAggregateTime = (index: number, nodes: IComputedNode[]): number => { + const row = nodes[index]; + if (row.aggregateTime) { + return row.aggregateTime; + } + + let total = row.selfTime; + for (const child of row.children) { + total += computeAggregateTime(child, nodes); + } + + return (row.aggregateTime = total); +}; + +const ensureSourceLocations = (profile: ICpuProfileRaw): ReadonlyArray => { + + let locationIdCounter = 0; + const locationsByRef = new Map(); + + const getLocationIdFor = (callFrame: CdpCallFrame) => { + const ref = [ + callFrame.functionName, + callFrame.url, + callFrame.scriptId, + callFrame.lineNumber, + callFrame.columnNumber, + ].join(':'); + + const existing = locationsByRef.get(ref); + if (existing) { + return existing.id; + } + const id = locationIdCounter++; + locationsByRef.set(ref, { + id, + callFrame, + location: { + lineNumber: callFrame.lineNumber + 1, + columnNumber: callFrame.columnNumber + 1, + // source: { + // name: maybeFileUrlToPath(callFrame.url), + // path: maybeFileUrlToPath(callFrame.url), + // sourceReference: 0, + // }, + }, + }); + + return id; + }; + + for (const node of profile.nodes) { + node.locationId = getLocationIdFor(node.callFrame); + node.positionTicks = node.positionTicks?.map(tick => ({ + ...tick, + // weirdly, line numbers here are 1-based, not 0-based. The position tick + // only gives line-level granularity, so 'mark' the entire range of source + // code the tick refers to + startLocationId: getLocationIdFor({ + ...node.callFrame, + lineNumber: tick.line - 1, + columnNumber: 0, + }), + endLocationId: getLocationIdFor({ + ...node.callFrame, + lineNumber: tick.line, + columnNumber: 0, + }), + })); + } + + return [...locationsByRef.values()] + .sort((a, b) => a.id - b.id) + .map(l => ({ locations: [l.location], callFrame: l.callFrame })); +}; + +/** + * Computes the model for the given profile. + */ +export const buildModel = (profile: ICpuProfileRaw): IProfileModel => { + if (!profile.timeDeltas || !profile.samples) { + return { + nodes: [], + locations: [], + samples: profile.samples || [], + timeDeltas: profile.timeDeltas || [], + // rootPath: profile.$vscode?.rootPath, + duration: profile.endTime - profile.startTime, + }; + } + + const { samples, timeDeltas } = profile; + const sourceLocations = ensureSourceLocations(profile); + const locations: ILocation[] = sourceLocations.map((l, id) => { + const src = l.locations[0]; //getBestLocation(profile, l.locations); + + return { + id, + selfTime: 0, + aggregateTime: 0, + ticks: 0, + // category: categorize(l.callFrame, src), + callFrame: l.callFrame, + src, + }; + }); + + const idMap = new Map(); + const mapId = (nodeId: number) => { + let id = idMap.get(nodeId); + if (id === undefined) { + id = idMap.size; + idMap.set(nodeId, id); + } + + return id; + }; + + // 1. Created a sorted list of nodes. It seems that the profile always has + // incrementing IDs, although they are just not initially sorted. + const nodes = new Array(profile.nodes.length); + for (let i = 0; i < profile.nodes.length; i++) { + const node = profile.nodes[i]; + + // make them 0-based: + const id = mapId(node.id); + nodes[id] = { + id, + selfTime: 0, + aggregateTime: 0, + locationId: node.locationId as number, + children: node.children?.map(mapId) || [], + }; + + for (const child of node.positionTicks || []) { + if (child.startLocationId) { + locations[child.startLocationId].ticks += child.ticks; + } + } + } + + for (const node of nodes) { + for (const child of node.children) { + nodes[child].parent = node.id; + } + } + + // 2. The profile samples are the 'bottom-most' node, the currently running + // code. Sum of these in the self time. + const duration = profile.endTime - profile.startTime; + let lastNodeTime = duration - timeDeltas[0]; + for (let i = 0; i < timeDeltas.length - 1; i++) { + const d = timeDeltas[i + 1]; + nodes[mapId(samples[i])].selfTime += d; + lastNodeTime -= d; + } + + // Add in an extra time delta for the last sample. `timeDeltas[0]` is the + // time before the first sample, and the time of the last sample is only + // derived (approximately) by the missing time in the sum of deltas. Save + // some work by calculating it here. + if (nodes.length) { + nodes[mapId(samples[timeDeltas.length - 1])].selfTime += lastNodeTime; + timeDeltas.push(lastNodeTime); + } + + // 3. Add the aggregate times for all node children and locations + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + const location = locations[node.locationId]; + location.aggregateTime += computeAggregateTime(i, nodes); + location.selfTime += node.selfTime; + } + + return { + nodes, + locations, + samples: samples.map(mapId), + timeDeltas, + // rootPath: profile.$vscode?.rootPath, + duration, + }; +}; + +class BottomUpNode { + public static root() { + return new BottomUpNode({ + id: -1, + selfTime: 0, + aggregateTime: 0, + ticks: 0, + callFrame: { + functionName: '(root)', + lineNumber: -1, + columnNumber: -1, + scriptId: '0', + url: '', + }, + }); + } + + public children: { [id: number]: BottomUpNode } = {}; + public aggregateTime = 0; + public selfTime = 0; + public ticks = 0; + public childrenSize = 0; + + public get id() { + return this.location.id; + } + + public get callFrame() { + return this.location.callFrame; + } + + public get src() { + return this.location.src; + } + + constructor(public readonly location: ILocation, public readonly parent?: BottomUpNode) { } + + public addNode(node: IComputedNode) { + this.selfTime += node.selfTime; + this.aggregateTime += node.aggregateTime; + } + +} + +const processNode = (aggregate: BottomUpNode, node: IComputedNode, model: IProfileModel, initialNode = node) => { + let child = aggregate.children[node.locationId]; + if (!child) { + child = new BottomUpNode(model.locations[node.locationId], aggregate); + aggregate.childrenSize++; + aggregate.children[node.locationId] = child; + } + + child.addNode(initialNode); + + if (node.parent) { + processNode(child, model.nodes[node.parent], model, initialNode); + } +}; + +//#endregion + +function isSpecial(call: CdpCallFrame): boolean { + return call.functionName.startsWith('(') && call.functionName.endsWith(')'); +} + +export interface BottomUpSample { + selfTime: number; + totalTime: number; + location: string; + caller: { percentage: number; location: string }[]; + percentage: number; + isSpecial: boolean; +} + +export function bottomUp(p: Profile, topN: number, fullPaths: boolean = false) { + const model = buildModel(p); + const root = BottomUpNode.root(); + for (const node of model.nodes) { + processNode(root, node, model); + root.addNode(node); + } + + const result = Object.values(root.children) + .sort((a, b) => b.selfTime - a.selfTime) + // .filter(a => !isSpecial(a.callFrame)) + .slice(0, topN); + + + const samples: BottomUpSample[] = []; + + function printCallFrame(frame: CdpCallFrame): string { + let result = frame.functionName || '(anonymous)'; + if (frame.url) { + result += '#'; + result += fullPaths ? frame.url : basename(frame.url); + if (frame.lineNumber >= 0) { + result += ':'; + result += frame.lineNumber + 1; + } + } + return result; + } + + for (const node of result) { + + const sample: BottomUpSample = { + selfTime: node.selfTime / 1000, + totalTime: node.aggregateTime / 1000, + location: printCallFrame(node.callFrame), + caller: [], + percentage: Math.round(node.selfTime / (model.duration / 100)), + isSpecial: isSpecial(node.callFrame) + }; + + // follow the heaviest caller paths + const stack = [node]; + while (stack.length) { + const node = stack.pop()!; + let top: BottomUpNode | undefined; + for (const candidate of Object.values(node.children)) { + if (!top || top.selfTime < candidate.selfTime) { + top = candidate; + } + } + if (top) { + const percentage = Math.round(top.selfTime / (node.selfTime / 100)); + sample.caller.push({ percentage, location: printCallFrame(top.callFrame) }); + stack.push(top); + } + } + + samples.push(sample); + } + + return samples; +} diff --git a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts index b80db72dddb..9fc70c63922 100644 --- a/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-sandbox/rendererAutoProfiler.ts @@ -69,34 +69,34 @@ export class RendererProfiling { editors: JSON.stringify(editors), }); - // // start heartbeat monitoring - // const sessionDisposables = this._disposables.add(new DisposableStore()); - // logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); - // // pause observation, we'll take a detailed look - // obs.disconnect(); - // nativeHostService.startHeartbeat(sessionId).then(success => { - // if (!success) { - // logService.warn('[perf] FAILED to start heartbeat sending'); - // return; - // } + // start heartbeat monitoring + const sessionDisposables = this._disposables.add(new DisposableStore()); + logService.warn(`[perf] Renderer reported VERY LONG TASK (${maxDuration}ms), starting auto profiling session '${sessionId}'`); + // pause observation, we'll take a detailed look + obs.disconnect(); + nativeHostService.startHeartbeat(sessionId).then(success => { + if (!success) { + logService.warn('[perf] FAILED to start heartbeat sending'); + return; + } - // // start sending a repeated heartbeat which is expected to be received by the main side - // const handle1 = setInterval(() => nativeHostService.sendHeartbeat(sessionId), 500); + // start sending a repeated heartbeat which is expected to be received by the main side + const handle1 = setInterval(() => nativeHostService.sendHeartbeat(sessionId), 500); - // // stop heartbeat after 20s - // const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); + // stop heartbeat after 20s + const handle2 = setTimeout(() => sessionDisposables.clear(), 20 * 1000); - // // cleanup - // // - stop heartbeat - // // - reconnect perf observer - // sessionDisposables.add(toDisposable(() => { - // clearInterval(handle1); - // clearTimeout(handle2); - // nativeHostService.stopHeartbeat(sessionId); - // logService.warn(`[perf] STOPPING to send heartbeat`); - // obs.observe({ entryTypes: ['longtask'] }); - // })); - // }); + // cleanup + // - stop heartbeat + // - reconnect perf observer + sessionDisposables.add(toDisposable(() => { + clearInterval(handle1); + clearTimeout(handle2); + nativeHostService.stopHeartbeat(sessionId); + logService.warn(`[perf] STOPPING to send heartbeat`); + obs.observe({ entryTypes: ['longtask'] }); + })); + }); }); this._disposables.add(toDisposable(() => obs.disconnect())); From 28da8ed1aaecb8a472bc117c511e1b3adc407269 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 14 Oct 2022 10:38:36 -0400 Subject: [PATCH 582/599] Add some tests for extension telemetry (#163584) * Add some tests for extension telemetry * Fix failing tests * More attempts at fixing failing tests * Ok, I think I fixed the tests this time --- .../test/common/telemetryLogAppender.test.ts | 2 +- .../workbench/api/common/extHostTelemetry.ts | 9 +- .../api/test/browser/extHostTelemetry.test.ts | 145 ++++++++++++++++++ .../vscode.proposed.telemetryLogger.d.ts | 2 +- 4 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 src/vs/workbench/api/test/browser/extHostTelemetry.test.ts diff --git a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts index e39dd7c0576..b1cb552a339 100644 --- a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts +++ b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts @@ -58,7 +58,7 @@ class TestTelemetryLogger extends AbstractLogger implements ILogger { flush(): void { } } -class TestTelemetryLoggerService implements ILoggerService { +export class TestTelemetryLoggerService implements ILoggerService { _serviceBrand: undefined; logger?: TestTelemetryLogger; diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index b0095f90a14..809d8e2d5a8 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -34,7 +34,6 @@ export class ExtHostTelemetry implements ExtHostTelemetryShape { @IExtHostInitDataService private readonly initData: IExtHostInitDataService, @ILoggerService loggerService: ILoggerService, ) { - console.log(this.initData.environment.extensionTelemetryLogResource); this._outputLogger = loggerService.createLogger(URI.revive(this.initData.environment.extensionTelemetryLogResource)); this._outputLogger.info('Below are logs for extension telemetry events sent to the telemetry output channel API once the log level is set to trace.'); this._outputLogger.info('==========================================================='); @@ -183,16 +182,16 @@ export class ExtHostTelemetryLogger { if (!this._apiObject) { const that = this; const obj: vscode.TelemetryLogger = { - logUsage: that.logUsage, + logUsage: that.logUsage.bind(that), get isUsageEnabled() { return that._telemetryEnablements.isUsageEnabled; }, get isErrorsEnabled() { return that._telemetryEnablements.isErrorsEnabled; }, - logError: that.logError, - dispose: that.dispose, - onDidChangeEnableStates: that._onDidChangeEnableStates.event + logError: that.logError.bind(that), + dispose: that.dispose.bind(that), + onDidChangeEnableStates: that._onDidChangeEnableStates.event.bind(that) }; this._apiObject = Object.freeze(obj); } diff --git a/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts b/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts new file mode 100644 index 00000000000..2153a61f480 --- /dev/null +++ b/src/vs/workbench/api/test/browser/extHostTelemetry.test.ts @@ -0,0 +1,145 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { URI } from 'vs/base/common/uri'; +import { ExtensionIdentifier, IExtensionDescription, TargetPlatform } from 'vs/platform/extensions/common/extensions'; +import { DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log'; +import { ITelemetryInfo, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { TestTelemetryLoggerService } from 'vs/platform/telemetry/test/common/telemetryLogAppender.test'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { ExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; +import { IEnvironment } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { mock } from 'vs/workbench/test/common/workbenchTestServices'; +import type { TelemetryAppender } from 'vscode'; + +suite('ExtHostTelemetry', function () { + + const mockEnvironment: IEnvironment = { + isExtensionDevelopmentDebug: false, + extensionDevelopmentLocationURI: undefined, + extensionTestsLocationURI: undefined, + appRoot: undefined, + appName: 'test', + extensionTelemetryLogResource: URI.parse('fake'), + appHost: 'test', + appLanguage: 'en', + globalStorageHome: URI.parse('fake'), + workspaceStorageHome: URI.parse('fake'), + appUriScheme: 'test', + }; + + const mockTelemetryInfo: ITelemetryInfo = { + firstSessionDate: '2020-01-01T00:00:00.000Z', + sessionId: 'test', + machineId: 'test', + }; + + const mockRemote = { + authority: 'test', + isRemote: false, + connectionData: null + }; + + const mockExtensionIdentifier: IExtensionDescription = { + identifier: new ExtensionIdentifier('test-extension'), + targetPlatform: TargetPlatform.UNIVERSAL, + isBuiltin: true, + isUserBuiltin: true, + isUnderDevelopment: true, + name: 'test-extension', + publisher: 'vscode', + version: '1.0.0', + engines: { vscode: '*' }, + extensionLocation: URI.parse('fake') + }; + + test('Ensure logger gets proper telemetry level during initialization', function () { + const extensionTelemetry = new ExtHostTelemetry(new class extends mock() { + override environment: IEnvironment = mockEnvironment; + override telemetryInfo: ITelemetryInfo = mockTelemetryInfo; + override remote = mockRemote; + }, new TestTelemetryLoggerService(DEFAULT_LOG_LEVEL)); + extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.USAGE, { usage: true, error: true }); + let config = extensionTelemetry.getTelemetryDetails(); + assert.strictEqual(config.isCrashEnabled, true); + assert.strictEqual(config.isUsageEnabled, true); + assert.strictEqual(config.isErrorsEnabled, true); + + // Initialize would never be called twice, but this is just for testing + extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.ERROR, { usage: true, error: true }); + config = extensionTelemetry.getTelemetryDetails(); + assert.strictEqual(config.isCrashEnabled, true); + assert.strictEqual(config.isUsageEnabled, false); + assert.strictEqual(config.isErrorsEnabled, true); + + extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.CRASH, { usage: true, error: true }); + config = extensionTelemetry.getTelemetryDetails(); + assert.strictEqual(config.isCrashEnabled, true); + assert.strictEqual(config.isUsageEnabled, false); + assert.strictEqual(config.isErrorsEnabled, false); + + extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.USAGE, { usage: false, error: true }); + config = extensionTelemetry.getTelemetryDetails(); + assert.strictEqual(config.isCrashEnabled, true); + assert.strictEqual(config.isUsageEnabled, false); + assert.strictEqual(config.isErrorsEnabled, true); + }); + + test('Simple log event to TelemetryLogger', function () { + const sentData: any[] = []; + const sentExceptions: any[] = []; + let flushCalled = false; + + // This is the appender which the extension would contribute + const appender: TelemetryAppender = { + logEvent: (eventName: string, data) => { + sentData.push({ eventName, data }); + }, + logException: (exception, data) => { + sentExceptions.push({ exception, data }); + }, + ignoreBuiltInCommonProperties: false, + flush: () => { + flushCalled = true; + } + }; + + const extensionTelemetry = new ExtHostTelemetry(new class extends mock() { + override environment: IEnvironment = mockEnvironment; + override telemetryInfo: ITelemetryInfo = mockTelemetryInfo; + override remote = mockRemote; + }, new TestTelemetryLoggerService(DEFAULT_LOG_LEVEL)); + + extensionTelemetry.$initializeTelemetryLevel(TelemetryLevel.USAGE, { usage: true, error: true }); + + // Create the logger usting the appender + const logger = extensionTelemetry.instantiateLogger(mockExtensionIdentifier, appender); + + logger.logUsage('test-event', { 'test-data': 'test-data' }); + assert.strictEqual(sentData.length, 1); + assert.strictEqual(sentData[0].eventName, `${mockExtensionIdentifier.name}/test-event`); + assert.strictEqual(sentData[0].data['test-data'], 'test-data'); + + logger.logUsage('test-event', { 'test-data': 'test-data' }); + assert.strictEqual(sentData.length, 2); + + logger.logError('test-event', { 'test-data': 'test-data' }); + assert.strictEqual(sentData.length, 3); + + logger.logError(new Error('test-error'), { 'test-data': 'test-data' }); + assert.strictEqual(sentData.length, 3); + assert.strictEqual(sentExceptions.length, 1); + + + // Assert not flushed + assert.strictEqual(flushCalled, false); + + // Call flush and assert that flush occurs + logger.dispose(); + assert.strictEqual(flushCalled, true); + + }); +}); diff --git a/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts b/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts index dfd38a77dd8..94a9a0a186e 100644 --- a/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts +++ b/src/vscode-dts/vscode.proposed.telemetryLogger.d.ts @@ -48,7 +48,7 @@ declare module 'vscode' { /** * Any additional common properties which should be injected into the data object. */ - readonly additionalCommonProperties: Record; + readonly additionalCommonProperties?: Record; /** * User-defined function which logs an event, used within the TelemetryLogger From f83ad50c8943492d0834a233ff0f10c807713032 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 14 Oct 2022 07:52:29 -0700 Subject: [PATCH 583/599] Load bundle for web from unpkg service (#163641) * move extensionResourceLoader service into platform * use the ExtensionResourceLoader to load translations from a language pack * do join after * missed a deletion --- .../browser/extensionResourceLoaderService.ts | 2 +- .../common/extensionResourceLoader.ts | 0 .../extensionResourceLoaderService.ts | 2 +- .../languagePacks/browser/languagePacks.ts | 71 ++++++++++++++++--- .../languagePacks/common/languagePacks.ts | 6 +- .../languagePacks/node/languagePacks.ts | 8 +-- .../api/browser/mainThreadLocalization.ts | 2 +- .../languageConfigurationExtensionPoint.ts | 2 +- .../contrib/snippets/browser/snippetsFile.ts | 2 +- .../snippets/browser/snippetsService.ts | 2 +- .../themes/browser/themes.contribution.ts | 2 +- .../builtinExtensionsScannerService.ts | 2 +- .../browser/webExtensionsScannerService.ts | 2 +- .../browser/abstractTextMateService.ts | 2 +- .../textMate/browser/nativeTextMateService.ts | 2 +- .../themes/browser/fileIconThemeData.ts | 2 +- .../themes/browser/productIconThemeData.ts | 2 +- .../themes/browser/workbenchThemeService.ts | 2 +- .../services/themes/common/colorThemeData.ts | 2 +- .../tokenStyleResolving.test.ts | 2 +- src/vs/workbench/workbench.desktop.main.ts | 2 +- src/vs/workbench/workbench.web.main.ts | 2 +- 22 files changed, 86 insertions(+), 35 deletions(-) rename src/vs/{workbench/services => platform}/extensionResourceLoader/browser/extensionResourceLoaderService.ts (96%) rename src/vs/{workbench/services => platform}/extensionResourceLoader/common/extensionResourceLoader.ts (100%) rename src/vs/{workbench/services => platform}/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts (95%) diff --git a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts similarity index 96% rename from src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts rename to src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts index 897d54766fb..e2bc58ae980 100644 --- a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts +++ b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -6,13 +6,13 @@ import { URI } from 'vs/base/common/uri'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; -import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { diff --git a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts similarity index 100% rename from src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts rename to src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts b/src/vs/platform/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts similarity index 95% rename from src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts rename to src/vs/platform/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts index c3db91f3a38..c6e63dc3aec 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts +++ b/src/vs/platform/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts @@ -6,13 +6,13 @@ import { URI } from 'vs/base/common/uri'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; -import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { IProductService } from 'vs/platform/product/common/productService'; import { asTextOrError, IRequestService } from 'vs/platform/request/common/request'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { diff --git a/src/vs/platform/languagePacks/browser/languagePacks.ts b/src/vs/platform/languagePacks/browser/languagePacks.ts index f7fdae65552..f63b7b552fa 100644 --- a/src/vs/platform/languagePacks/browser/languagePacks.ts +++ b/src/vs/platform/languagePacks/browser/languagePacks.ts @@ -3,21 +3,72 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { Language } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks'; +import { ILogService } from 'vs/platform/log/common/log'; export class WebLanguagePacksService extends LanguagePackBaseService { - // TODO: support builtin extensions using unpkg service - // constructor( - // @IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService, - // @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, - // @ILogService private readonly logService: ILogService - // ) { - // super(extensionGalleryService); - // } + constructor( + @IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService, + @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, + @ILogService private readonly logService: ILogService + ) { + super(extensionGalleryService); + } - getTranslationsUri(id: string): Promise { - return Promise.resolve(undefined); + async getBuiltInExtensionTranslationsUri(id: string): Promise { + + const queryTimeout = new CancellationTokenSource(); + setTimeout(() => queryTimeout.cancel(), 1000); + + // First get the extensions that supports the language (there should only be one but just in case let's include more results) + let result; + try { + result = await this.extensionGalleryService.query({ + text: `tag:"lp-${Language.value()}"`, + pageSize: 5 + }, queryTimeout.token); + } catch (err) { + this.logService.error(err); + return undefined; + } + + const languagePackExtensions = result.firstPage.find(e => e.properties.localizedLanguages?.length); + if (!languagePackExtensions) { + this.logService.trace(`No language pack found for language ${Language.value()}`); + return undefined; + } + + // Then get the manifest for that extension + const manifestTimeout = new CancellationTokenSource(); + setTimeout(() => queryTimeout.cancel(), 1000); + const manifest = await this.extensionGalleryService.getManifest(languagePackExtensions, manifestTimeout.token); + + // Find the translation from the language pack + const localization = manifest?.contributes?.localizations?.find(l => l.languageId === Language.value()); + const translation = localization?.translations.find(t => t.id === id); + if (!translation) { + this.logService.trace(`No translation found for id '${id}, in ${manifest?.name}`); + return undefined; + } + + // get the resource uri and return it + const uri = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ + // If translation is defined then manifest should have been defined. + name: manifest!.name, + publisher: manifest!.publisher, + version: manifest!.version + }); + if (!uri) { + this.logService.trace('Gallery does not provide extension resources.'); + return undefined; + } + + return URI.joinPath(uri, translation.path); } // Web doesn't have a concept of language packs, so we just return an empty array diff --git a/src/vs/platform/languagePacks/common/languagePacks.ts b/src/vs/platform/languagePacks/common/languagePacks.ts index 589e8678326..93f337da2ff 100644 --- a/src/vs/platform/languagePacks/common/languagePacks.ts +++ b/src/vs/platform/languagePacks/common/languagePacks.ts @@ -23,18 +23,18 @@ export interface ILanguagePackService { readonly _serviceBrand: undefined; getAvailableLanguages(): Promise>; getInstalledLanguages(): Promise>; - getTranslationsUri(id: string): Promise; + getBuiltInExtensionTranslationsUri(id: string): Promise; getLocale(extension: IGalleryExtension): string | undefined; } export abstract class LanguagePackBaseService extends Disposable implements ILanguagePackService { declare readonly _serviceBrand: undefined; - constructor(@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService) { + constructor(@IExtensionGalleryService protected readonly extensionGalleryService: IExtensionGalleryService) { super(); } - abstract getTranslationsUri(id: string): Promise; + abstract getBuiltInExtensionTranslationsUri(id: string): Promise; abstract getInstalledLanguages(): Promise>; diff --git a/src/vs/platform/languagePacks/node/languagePacks.ts b/src/vs/platform/languagePacks/node/languagePacks.ts index f2d2516c9bd..db283b29318 100644 --- a/src/vs/platform/languagePacks/node/languagePacks.ts +++ b/src/vs/platform/languagePacks/node/languagePacks.ts @@ -16,7 +16,7 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens import { ILogService } from 'vs/platform/log/common/log'; import { ILocalizationContribution } from 'vs/platform/extensions/common/extensions'; import { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks'; -import { locale } from 'vs/base/common/platform'; +import { Language } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; interface ILanguagePack { @@ -50,11 +50,11 @@ export class NativeLanguagePackService extends LanguagePackBaseService { }); } - async getTranslationsUri(id: string): Promise { + async getBuiltInExtensionTranslationsUri(id: string): Promise { const packs = await this.cache.getLanguagePacks(); - const pack = packs[locale!]; + const pack = packs[Language.value()]; if (!pack) { - this.logService.warn(`No language pack found for ${locale}`); + this.logService.warn(`No language pack found for ${Language.value()}`); return undefined; } diff --git a/src/vs/workbench/api/browser/mainThreadLocalization.ts b/src/vs/workbench/api/browser/mainThreadLocalization.ts index c3cdd418461..cc532e404ea 100644 --- a/src/vs/workbench/api/browser/mainThreadLocalization.ts +++ b/src/vs/workbench/api/browser/mainThreadLocalization.ts @@ -23,7 +23,7 @@ export class MainThreadLocalization extends Disposable implements MainThreadLoca async $fetchBuiltInBundleUri(id: string): Promise { try { - const uri = await this.languagePackService.getTranslationsUri(id); + const uri = await this.languagePackService.getBuiltInExtensionTranslationsUri(id); return uri; } catch (e) { return undefined; diff --git a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts index dd288894ba7..6e524e57ce8 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts @@ -16,7 +16,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ITextMateService } from 'vs/workbench/services/textMate/browser/textMate'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { hash } from 'vs/base/common/hash'; import { Disposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts index 070fd986cdf..7d88688f68d 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IdleValue } from 'vs/base/common/async'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { relativePath } from 'vs/base/common/resources'; import { isObject } from 'vs/base/common/types'; import { Iterable } from 'vs/base/common/iterator'; diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 069f3bf44f3..c26746632e3 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -22,7 +22,7 @@ import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippe import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { languagesExtPoint } from 'vs/workbench/services/language/common/languageService'; import { SnippetCompletionProvider } from './snippetCompletionProvider'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { ResourceMap } from 'vs/base/common/map'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { isStringArray } from 'vs/base/common/types'; diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 8a094b654d6..0cf8cd7b52f 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -30,7 +30,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { Emitter } from 'vs/base/common/event'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts index e614f82d01b..41a586dc3f1 100644 --- a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts @@ -11,7 +11,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { FileAccess } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { IProductService } from 'vs/platform/product/common/productService'; import { ITranslations, localizeManifest } from 'vs/platform/extensionManagement/common/extensionNls'; import { ILogService } from 'vs/platform/log/common/log'; diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index bc0c3415950..313e55a10b5 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -25,7 +25,7 @@ import { isString } from 'vs/base/common/types'; import { getErrorMessage } from 'vs/base/common/errors'; import { ResourceMap } from 'vs/base/common/map'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index 8a59203a4df..2f45c4699cf 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -28,7 +28,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry'; import { missingTMGrammarErrorMessage, TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { TMTokenization } from 'vs/workbench/services/textMate/common/TMTokenization'; diff --git a/src/vs/workbench/services/textMate/browser/nativeTextMateService.ts b/src/vs/workbench/services/textMate/browser/nativeTextMateService.ts index 326cb3c09f9..eaed1a95612 100644 --- a/src/vs/workbench/services/textMate/browser/nativeTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/nativeTextMateService.ts @@ -22,7 +22,7 @@ import { UriComponents, URI } from 'vs/base/common/uri'; import { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder'; import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; import { IModelContentChangedEvent } from 'vs/editor/common/textModelEvents'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { FileAccess } from 'vs/base/common/network'; diff --git a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts index c570a913f61..b65836c2377 100644 --- a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts @@ -12,7 +12,7 @@ import { ExtensionData, IThemeExtensionPoint, IWorkbenchFileIconTheme } from 'vs import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { asCSSUrl } from 'vs/base/browser/dom'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { ILanguageService } from 'vs/editor/common/languages/language'; export class FileIconThemeData implements IWorkbenchFileIconTheme { diff --git a/src/vs/workbench/services/themes/browser/productIconThemeData.ts b/src/vs/workbench/services/themes/browser/productIconThemeData.ts index 63ca74a35cd..97fff900e80 100644 --- a/src/vs/workbench/services/themes/browser/productIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/productIconThemeData.ts @@ -17,7 +17,7 @@ import { isObject, isString } from 'vs/base/common/types'; import { ILogService } from 'vs/platform/log/common/log'; import { IconDefinition, getIconRegistry, IconContribution, IconFontDefinition, IconFontSource } from 'vs/platform/theme/common/iconRegistry'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; export const DEFAULT_PRODUCT_ICON_THEME_ID = ''; // TODO diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index e164e0ac1f2..9e8bad431cb 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -27,7 +27,7 @@ import { registerColorThemeSchemas } from 'vs/workbench/services/themes/common/c import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { ThemeRegistry, registerColorThemeExtensionPoint, registerFileIconThemeExtensionPoint, registerProductIconThemeExtensionPoint } from 'vs/workbench/services/themes/common/themeExtensionPoints'; import { updateColorThemeConfigurationSchemas, updateFileIconThemeConfigurationSchemas, ThemeConfiguration, updateProductIconThemeConfigurationSchemas } from 'vs/workbench/services/themes/common/themeConfiguration'; import { ProductIconThemeData, DEFAULT_PRODUCT_ICON_THEME_ID } from 'vs/workbench/services/themes/browser/productIconThemeData'; diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 5ccb9e5f93d..c498d6c4da4 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -19,7 +19,7 @@ import { URI } from 'vs/base/common/uri'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { TokenStyle, SemanticTokenRule, ProbeScope, getTokenClassificationRegistry, TokenStyleValue, TokenStyleData, parseClassifierString } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; import { CharCode } from 'vs/base/common/charCode'; import { StorageScope, IStorageService, StorageTarget } from 'vs/platform/storage/common/storage'; import { ThemeConfiguration } from 'vs/workbench/services/themes/common/themeConfiguration'; diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 7067dd39095..d93a77294b0 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -13,7 +13,7 @@ import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { ExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; +import { ExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; import { ITokenStyle } from 'vs/platform/theme/common/themeService'; import { mock, TestProductService } from 'vs/workbench/test/common/workbenchTestServices'; import { IRequestService } from 'vs/platform/request/common/request'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index aa0846dcb24..0bbbc48473b 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -46,7 +46,6 @@ import 'vs/workbench/services/lifecycle/electron-sandbox/lifecycleService'; import 'vs/workbench/services/title/electron-sandbox/titleService'; import 'vs/workbench/services/host/electron-sandbox/nativeHostService'; import 'vs/workbench/services/request/electron-sandbox/requestService'; -import 'vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; import 'vs/workbench/services/clipboard/electron-sandbox/clipboardService'; import 'vs/workbench/services/contextmenu/electron-sandbox/contextmenuService'; import 'vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService'; @@ -61,6 +60,7 @@ import 'vs/workbench/services/encryption/electron-sandbox/encryptionService'; import 'vs/workbench/services/localization/electron-sandbox/languagePackService'; import 'vs/workbench/services/telemetry/electron-sandbox/telemetryService'; import 'vs/workbench/services/extensions/electron-sandbox/extensionHostStarter'; +import 'vs/platform/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; import 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService'; import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 286ab2b2f22..23b6577a3cc 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -53,7 +53,6 @@ import 'vs/workbench/services/dialogs/browser/fileDialogService'; import 'vs/workbench/services/host/browser/browserHostService'; import 'vs/workbench/services/lifecycle/browser/lifecycleService'; import 'vs/workbench/services/clipboard/browser/clipboardService'; -import 'vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService'; import 'vs/workbench/services/path/browser/pathService'; import 'vs/workbench/services/themes/browser/browserHostColorSchemeService'; import 'vs/workbench/services/encryption/browser/encryptionService'; @@ -64,6 +63,7 @@ import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService'; import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService'; import 'vs/workbench/services/userDataSync/browser/userDataSyncProfilesStorageService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import 'vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; From 6684350a586e2e10654d58c57f2a927afab2d008 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 14 Oct 2022 08:41:21 -0700 Subject: [PATCH 584/599] Onboard GitHub & Microsoft auth extensions to l10n (#163662) * onboard github-auth completely to l10n * onboard microsoft-authentication entirely on to l10n --- extensions/github-authentication/package.json | 7 ++- .../github-authentication/src/github.ts | 4 +- .../github-authentication/src/githubServer.ts | 43 +++++++++++-------- extensions/github-authentication/yarn.lock | 5 --- .../microsoft-authentication/package.json | 3 +- .../microsoft-authentication/src/AADHelper.ts | 15 +++---- .../microsoft-authentication/src/logger.ts | 2 +- extensions/microsoft-authentication/yarn.lock | 5 --- 8 files changed, 39 insertions(+), 45 deletions(-) diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 7e4f7dde431..dbabf7fcbbf 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -34,16 +34,16 @@ "id": "github" }, { - "label": "GitHub Enterprise", + "label": "GitHub Enterprise Server", "id": "github-enterprise" } ], "configuration": { - "title": "GitHub Enterprise Authentication Provider", + "title": "GitHub Enterprise Server Authentication Provider", "properties": { "github-enterprise.uri": { "type": "string", - "description": "URI of your GitHub Enterprise Instance" + "description": "GitHub Enterprise Server URI" } } } @@ -65,7 +65,6 @@ "node-fetch": "2.6.7", "uuid": "8.1.0", "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.2.0", "vscode-tas-client": "^0.1.47" }, "devDependencies": { diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index f6f2301ab16..0c7273d8bf0 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -256,7 +256,7 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid */ this._telemetryReporter?.sendTelemetryEvent('loginFailed'); - vscode.window.showErrorMessage(`Sign in failed: ${e}`); + vscode.window.showErrorMessage(vscode.l10n.t('Sign in failed: {0}', `${e}`)); this._logger.error(e); throw e; } @@ -299,7 +299,7 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid */ this._telemetryReporter?.sendTelemetryEvent('logoutFailed'); - vscode.window.showErrorMessage(`Sign out failed: ${e}`); + vscode.window.showErrorMessage(vscode.l10n.t('Sign out failed: {0}', `${e}`)); this._logger.error(e); throw e; } diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index 5c6bff905db..42e43549a58 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vscode-nls'; import * as vscode from 'vscode'; import fetch, { Response } from 'node-fetch'; import { v4 as uuid } from 'uuid'; @@ -15,7 +14,6 @@ import { isSupportedEnvironment } from './common/env'; import { LoopbackAuthServer } from './authServer'; import path = require('path'); -const localize = nls.loadMessageBundle(); const CLIENT_ID = '01ab8ac9400c4e429b23'; const GITHUB_TOKEN_URL = 'https://vscode.dev/codeExchangeProxyEndpoints/github/login/oauth/access_token'; const NETWORK_ERROR = 'network error'; @@ -157,15 +155,15 @@ export class GitHubServer implements IGitHubServer { // Used for showing a friendlier message to the user when the explicitly cancel a flow. let userCancelled: boolean | undefined; const yes = vscode.l10n.t('Yes'); - const no = localize('no', "No"); + const no = vscode.l10n.t('No'); const promptToContinue = async () => { if (userCancelled === undefined) { // We haven't had a failure yet so wait to prompt return; } const message = userCancelled - ? localize('userCancelledMessage', "Having trouble logging in? Would you like to try a different way?") - : localize('otherReasonMessage', "You have not yet finished authorizing this extension to use GitHub. Would you like to keep trying?"); + ? vscode.l10n.t('Having trouble logging in? Would you like to try a different way?') + : vscode.l10n.t('otherReasonMessage', 'You have not yet finished authorizing this extension to use GitHub. Would you like to keep trying?'); const result = await vscode.window.showWarningMessage(message, yes, no); if (result !== yes) { throw new Error('Cancelled'); @@ -221,7 +219,11 @@ export class GitHubServer implements IGitHubServer { this._logger.info(`Trying without local server... (${scopes})`); return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, - title: localize('signingIn', 'Signing in to {0}...', this.baseUri.authority), + title: vscode.l10n.t({ + message: 'Signing in to {0}...', + args: [this.baseUri.authority], + comment: ['The {0} will be a url, e.g. github.com'] + }), cancellable: true }, async (_, token) => { const existingNonces = this._pendingNonces.get(scopes) || []; @@ -266,7 +268,11 @@ export class GitHubServer implements IGitHubServer { this._logger.info(`Trying with local server... (${scopes})`); return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, - title: localize('signingInAnotherWay', "Signing in to {0}...", this.baseUri.authority), + title: vscode.l10n.t({ + message: 'Signing in to {0}...', + args: [this.baseUri.authority], + comment: ['The {0} will be a url, e.g. github.com'] + }), cancellable: true }, async (_, token) => { const redirectUri = await this.getRedirectEndpoint(); @@ -323,15 +329,15 @@ export class GitHubServer implements IGitHubServer { const json = await result.json() as IGitHubDeviceCodeResponse; - + const button = vscode.l10n.t('Copy & Continue to GitHub'); const modalResult = await vscode.window.showInformationMessage( - localize('code.title', "Your Code: {0}", json.user_code), + vscode.l10n.t({ message: 'Your Code: {0}', args: [json.user_code], comment: ['The {0} will be a code, e.g. 123-456'] }), { modal: true, - detail: localize('code.detail', "To finish authenticating, navigate to GitHub and paste in the above one-time code.") - }, 'Copy & Continue to GitHub'); + detail: vscode.l10n.t('To finish authenticating, navigate to GitHub and paste in the above one-time code.') + }, button); - if (modalResult !== 'Copy & Continue to GitHub') { + if (modalResult !== button) { throw new Error('User Cancelled'); } @@ -372,11 +378,14 @@ export class GitHubServer implements IGitHubServer { return await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: true, - title: localize( - 'progress', - "Open [{0}]({0}) in a new tab and paste your one-time code: {1}", - json.verification_uri, - json.user_code) + title: vscode.l10n.t({ + message: 'Open [{0}]({0}) in a new tab and paste your one-time code: {1}', + args: [json.verification_uri, json.user_code], + comment: [ + 'The [{0}]({0}) will be a url and the {1} will be a code, e.g. 123-456', + '{Locked="[{0}]({0})"}' + ] + }) }, async (_, token) => { const refreshTokenUri = this.baseUri.with({ path: '/login/oauth/access_token', diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index 330255ba858..bfc332713a8 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -143,11 +143,6 @@ uuid@8.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== -vscode-nls@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" - integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== - vscode-tas-client@^0.1.47: version "0.1.47" resolved "https://registry.yarnpkg.com/vscode-tas-client/-/vscode-tas-client-0.1.47.tgz#d66795cbbaa231aba659b6c40d43927d73596375" diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index 8bf6cd70855..1fb6e7d83a5 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -61,8 +61,7 @@ "sha.js": "2.4.11", "stream": "0.0.2", "uuid": "^8.2.0", - "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.2.0" + "@vscode/extension-telemetry": "0.6.2" }, "repository": { "type": "git", diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index 288157ba00d..3a7307a47c0 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -7,7 +7,6 @@ import * as randomBytes from 'randombytes'; import * as querystring from 'querystring'; import { Buffer } from 'buffer'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; import { v4 as uuid } from 'uuid'; import fetch, { Response } from 'node-fetch'; import Logger from './logger'; @@ -17,8 +16,6 @@ import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecret import { LoopbackAuthServer } from './authServer'; import path = require('path'); -const localize = nls.loadMessageBundle(); - const redirectUrl = 'https://vscode.dev/redirect'; const loginEndpointUrl = 'https://login.microsoftonline.com/'; const DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56'; @@ -139,7 +136,7 @@ export class AzureActiveDirectoryService { sessionId: session.id }); } else { - vscode.window.showErrorMessage(localize('signOut', "You have been signed out because reading stored authentication information failed.")); + vscode.window.showErrorMessage(vscode.l10n.t('You have been signed out because reading stored authentication information failed.')); Logger.error(e); await this.removeSessionByIToken({ accessToken: undefined, @@ -446,7 +443,7 @@ export class AzureActiveDirectoryService { onDidChangeSessions.fire({ added: [], removed: [], changed: [this.convertToSessionSync(refreshedToken)] }); } catch (e) { if (e.message !== REFRESH_NETWORK_FAILURE) { - vscode.window.showErrorMessage(localize('signOut', "You have been signed out because reading stored authentication information failed.")); + vscode.window.showErrorMessage(vscode.l10n.t('You have been signed out because reading stored authentication information failed.')); await this.removeSessionById(sessionId); } } @@ -683,9 +680,9 @@ export class AzureActiveDirectoryService { private async handleCodeInputBox(inputBox: vscode.InputBox, verifier: string, scopeData: IScopeData): Promise { inputBox.ignoreFocusOut = true; - inputBox.title = localize('pasteCodeTitle', 'Microsoft Authentication'); - inputBox.prompt = localize('pasteCodePrompt', 'Provide the authorization code to complete the sign in flow.'); - inputBox.placeholder = localize('pasteCodePlaceholder', 'Paste authorization code here...'); + inputBox.title = vscode.l10n.t('Microsoft Authentication'); + inputBox.prompt = vscode.l10n.t('Provide the authorization code to complete the sign in flow.'); + inputBox.placeholder = vscode.l10n.t('Paste authorization code here...'); return new Promise((resolve: (value: vscode.AuthenticationSession) => void, reject) => { inputBox.show(); inputBox.onDidAccept(async () => { @@ -829,7 +826,7 @@ export class AzureActiveDirectoryService { } catch (e) { // Network failures will automatically retry on next poll. if (e.message !== REFRESH_NETWORK_FAILURE) { - vscode.window.showErrorMessage(localize('signOut', "You have been signed out because reading stored authentication information failed.")); + vscode.window.showErrorMessage(vscode.l10n.t('You have been signed out because reading stored authentication information failed.')); await this.removeSessionById(session.id); } return; diff --git a/extensions/microsoft-authentication/src/logger.ts b/extensions/microsoft-authentication/src/logger.ts index 92b5876e1b4..38ae6c732d6 100644 --- a/extensions/microsoft-authentication/src/logger.ts +++ b/extensions/microsoft-authentication/src/logger.ts @@ -5,5 +5,5 @@ import * as vscode from 'vscode'; -const Logger = vscode.window.createOutputChannel('Microsoft Authentication', { log: true }); +const Logger = vscode.window.createOutputChannel(vscode.l10n.t('Microsoft Authentication'), { log: true }); export default Logger; diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index 8d01670e906..d66929ff7f6 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -198,11 +198,6 @@ uuid@^8.2.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e" integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q== -vscode-nls@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.2.0.tgz#3cb6893dd9bd695244d8a024bdf746eea665cc3f" - integrity sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From a2ecf38136c5988629f2a5ed778b8ab431738ee4 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Fri, 14 Oct 2022 08:41:31 -0700 Subject: [PATCH 585/599] move banner above title bar in web (#163492) * move banner above title bar in web * bug fixes, testing PWA --- src/vs/workbench/browser/layout.ts | 40 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 8d367d84589..08a205b6ffa 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -161,9 +161,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi get offset() { let top = 0; let quickPickTop = 0; + if (this.isVisible(Parts.BANNER_PART)) { + top = this.getPart(Parts.BANNER_PART).maximumHeight; + quickPickTop = top; + } if (this.isVisible(Parts.TITLEBAR_PART)) { - top = this.getPart(Parts.TITLEBAR_PART).maximumHeight; - quickPickTop = this.titleService.isCommandCenterVisible ? 0 : top; + top += this.getPart(Parts.TITLEBAR_PART).maximumHeight; + quickPickTop = this.titleService.isCommandCenterVisible ? quickPickTop : top; } return { top, quickPickTop }; } @@ -1019,6 +1023,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return !this.stateModel.getRuntimeValue(LayoutStateKeys.ACTIVITYBAR_HIDDEN); case Parts.EDITOR_PART: return !this.stateModel.getRuntimeValue(LayoutStateKeys.EDITOR_HIDDEN); + case Parts.BANNER_PART: + return this.workbenchGrid.isViewVisible(this.bannerPartView); default: return false; // any other part cannot be hidden } @@ -1301,7 +1307,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.workbenchGrid = workbenchGrid; this.workbenchGrid.edgeSnapping = this.state.runtime.fullscreen; - for (const part of [titleBar, editorPart, activityBar, panelPart, sideBar, statusBar, auxiliaryBarPart]) { + for (const part of [titleBar, editorPart, activityBar, panelPart, sideBar, statusBar, auxiliaryBarPart, bannerPart]) { this._register(part.onDidVisibilityChange((visible) => { if (part === sideBar) { this.setSideBarHidden(!visible, true); @@ -2096,6 +2102,21 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const activityBarWidth = this.activityBarPartView.minimumWidth; const middleSectionHeight = height - titleBarHeight - statusBarHeight; + const titleAndBanner: ISerializedNode[] = [ + { + type: 'leaf', + data: { type: Parts.TITLEBAR_PART }, + size: titleBarHeight, + visible: this.isVisible(Parts.TITLEBAR_PART) + }, + { + type: 'leaf', + data: { type: Parts.BANNER_PART }, + size: bannerHeight, + visible: false + } + ]; + const activityBarNode: ISerializedLeafNode = { type: 'leaf', data: { type: Parts.ACTIVITYBAR_PART }, @@ -2145,18 +2166,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi type: 'branch', size: width, data: [ - { - type: 'leaf', - data: { type: Parts.TITLEBAR_PART }, - size: titleBarHeight, - visible: this.isVisible(Parts.TITLEBAR_PART) - }, - { - type: 'leaf', - data: { type: Parts.BANNER_PART }, - size: bannerHeight, - visible: false - }, + ...(isWeb ? titleAndBanner.reverse() : titleAndBanner), { type: 'branch', data: middleSection, From ee0b7792a199ff6db98fdb5b4cf8656bf88c8b6e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 14 Oct 2022 17:51:16 +0200 Subject: [PATCH 586/599] fix https://github.com/microsoft/vscode/issues/147762 (#162751) --- .../gotoSymbol/browser/link/clickLinkGesture.ts | 8 ++++++-- .../browser/link/goToDefinitionAtPosition.ts | 11 ++++++----- .../stickyScroll/browser/stickyScrollWidget.ts | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts b/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts index 78b3bdbfed5..a5777a61539 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts @@ -25,11 +25,15 @@ export class ClickLinkMouseEvent { public readonly hasTriggerModifier: boolean; public readonly hasSideBySideModifier: boolean; public readonly isNoneOrSingleMouseDown: boolean; - public readonly hasRightClick: boolean; + public readonly isLeftClick: boolean; + public readonly isMiddleClick: boolean; + public readonly isRightClick: boolean; constructor(source: IEditorMouseEvent, opts: ClickLinkOptions) { this.target = source.target; - this.hasRightClick = source.event.rightButton; + this.isLeftClick = source.event.leftButton; + this.isMiddleClick = source.event.middleButton; + this.isRightClick = source.event.rightButton; this.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier); this.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier); this.isNoneOrSingleMouseDown = (source.event.detail <= 1); diff --git a/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts b/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts index 87492186e71..48ec76ca093 100644 --- a/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts +++ b/src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts @@ -277,11 +277,12 @@ export class GotoDefinitionAtPositionEditorContribution implements IEditorContri } private isEnabled(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent): boolean { - return this.editor.hasModel() && - mouseEvent.isNoneOrSingleMouseDown && - (mouseEvent.target.type === MouseTargetType.CONTENT_TEXT) && - (mouseEvent.hasTriggerModifier || (withKey ? withKey.keyCodeIsTriggerKey : false)) && - this.languageFeaturesService.definitionProvider.has(this.editor.getModel()); + return this.editor.hasModel() + && mouseEvent.isLeftClick + && mouseEvent.isNoneOrSingleMouseDown + && mouseEvent.target.type === MouseTargetType.CONTENT_TEXT + && (mouseEvent.hasTriggerModifier || (withKey ? withKey.keyCodeIsTriggerKey : false)) + && this.languageFeaturesService.definitionProvider.has(this.editor.getModel()); } private findDefinition(position: Position, token: CancellationToken): Promise { diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts index 777154b9891..ed4f02e586c 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts @@ -152,7 +152,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { this._editor.revealPosition({ lineNumber: this._hoverOnLine, column: 1 }); } this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, { uri: this._editor.getModel()!.uri, range: this._stickyRangeProjectedOnEditor } as Location); - } else if (!e.hasRightClick) { + } else if (!e.isRightClick) { // Normal click this._editor.revealPosition({ lineNumber: this._hoverOnLine, column: 1 }); } From 1bca8df33306a9c220af9851c73f5a82c9dc50f5 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 14 Oct 2022 08:59:02 -0700 Subject: [PATCH 587/599] Fixes #163151 (#163663) Fixes #163151 --- .../browser/authenticationService.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index 69cb0d2ba48..d5e2b750297 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -92,13 +92,17 @@ export type AuthenticationSessionInfo = { readonly id: string; readonly accessTo export async function getCurrentAuthenticationSessionInfo(credentialsService: ICredentialsService, productService: IProductService): Promise { const authenticationSessionValue = await credentialsService.getPassword(`${productService.urlProtocol}.login`, 'account'); if (authenticationSessionValue) { - const authenticationSessionInfo: AuthenticationSessionInfo = JSON.parse(authenticationSessionValue); - if (authenticationSessionInfo - && isString(authenticationSessionInfo.id) - && isString(authenticationSessionInfo.accessToken) - && isString(authenticationSessionInfo.providerId) - ) { - return authenticationSessionInfo; + try { + const authenticationSessionInfo: AuthenticationSessionInfo = JSON.parse(authenticationSessionValue); + if (authenticationSessionInfo + && isString(authenticationSessionInfo.id) + && isString(authenticationSessionInfo.accessToken) + && isString(authenticationSessionInfo.providerId) + ) { + return authenticationSessionInfo; + } + } catch (e) { + // ignore as this is a best effort operation. } } return undefined; From ff80ce61d7209f8d6253bcbdfd8a7bf4a07978f9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 09:08:52 -0700 Subject: [PATCH 588/599] Remove custom jupyter notebook migration logic (#163362) This migration should have taken place so I don't think we need this code anymore --- .../browser/customEditorInputFactory.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index e98fbb5a058..37fe6a28c75 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -15,7 +15,6 @@ import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebo import { IWebviewService, WebviewContentOptions, WebviewContentPurpose, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { DeserializedWebview, restoreWebviewContentOptions, restoreWebviewOptions, reviveWebviewExtensionDescription, SerializedWebview, SerializedWebviewOptions, WebviewEditorInputSerializer } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer'; import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; -import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService'; import { IWorkingCopyBackupMeta } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; @@ -58,7 +57,6 @@ export class CustomEditorInputSerializer extends WebviewEditorInputSerializer { @IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IWebviewService private readonly _webviewService: IWebviewService, - @IEditorResolverService private readonly _editorResolverService: IEditorResolverService ) { super(webviewWorkbenchService); } @@ -92,12 +90,6 @@ export class CustomEditorInputSerializer extends WebviewEditorInputSerializer { serializedEditorInput: string ): CustomEditorInput { const data = this.fromJson(JSON.parse(serializedEditorInput)); - if (data.viewType === 'jupyter.notebook.ipynb') { - const editorAssociation = this._editorResolverService.getAssociationsForResource(data.editorResource); - if (!editorAssociation.find(association => association.viewType === 'jupyter.notebook.ipynb')) { - return NotebookEditorInput.create(this._instantiationService, data.editorResource, 'jupyter-notebook', { _backupId: data.backupId, startDirty: data.dirty }) as any; - } - } const webview = reviveWebview(this._webviewService, data); const customInput = this._instantiationService.createInstance(CustomEditorInput, { resource: data.editorResource, viewType: data.viewType, id: data.id }, webview, { startsDirty: data.dirty, backupId: data.backupId }); @@ -131,7 +123,6 @@ export class ComplexCustomWorkingCopyEditorHandler extends Disposable implements @IInstantiationService private readonly _instantiationService: IInstantiationService, @IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService, @IWorkingCopyBackupService private readonly _workingCopyBackupService: IWorkingCopyBackupService, - @IEditorResolverService private readonly _editorResolverService: IEditorResolverService, @IWebviewService private readonly _webviewService: IWebviewService, @ICustomEditorService _customEditorService: ICustomEditorService // DO NOT REMOVE (needed on startup to register overrides properly) ) { @@ -177,13 +168,6 @@ export class ComplexCustomWorkingCopyEditorHandler extends Disposable implements } const backupData = backup.meta; - if (backupData.viewType === 'jupyter.notebook.ipynb') { - const editorAssociation = this._editorResolverService.getAssociationsForResource(URI.revive(backupData.editorResource)); - if (!editorAssociation.find(association => association.viewType === 'jupyter.notebook.ipynb')) { - return NotebookEditorInput.create(this._instantiationService, URI.revive(backupData.editorResource), 'jupyter-notebook', { startDirty: !!backupData.backupId, _backupId: backupData.backupId, _workingCopy: workingCopy }) as any; - } - } - const id = backupData.webview.id; const extension = reviveWebviewExtensionDescription(backupData.extension?.id, backupData.extension?.location); const webview = reviveWebview(this._webviewService, { From 25bb57566d7b9d3528220b15b0dac05b5bebbf90 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:29:15 -0700 Subject: [PATCH 589/599] add restrict search to folder (#163597) --- .../search/browser/search.contribution.ts | 53 ++++++++++++++++--- .../contrib/search/browser/searchActions.ts | 13 +++-- .../contrib/search/browser/searchView.ts | 4 ++ .../contrib/search/common/constants.ts | 1 + 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 90afe040b3b..07e2cf84134 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -38,7 +38,7 @@ import { getMultiSelectedResources, IExplorerService } from 'vs/workbench/contri import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition, VIEWLET_ID as VIEWLET_ID_FILES } from 'vs/workbench/contrib/files/common/files'; import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess'; import { registerContributions as replaceContributions } from 'vs/workbench/contrib/search/browser/replaceContributions'; -import { cancelSearch, clearHistoryCommand, clearSearchResults, CloseReplaceAction, collapseDeepestExpandedLevel, copyAllCommand, copyMatchCommand, copyPathCommand, expandAll, FindInFilesCommand, findOrReplaceInFiles, FocusNextInputAction, focusNextSearchResult, FocusPreviousInputAction, focusPreviousSearchResult, focusSearchListCommand, getSearchView, openSearchView, refreshSearch, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, toggleWholeWordCommand } from 'vs/workbench/contrib/search/browser/searchActions'; +import { cancelSearch, clearHistoryCommand, clearSearchResults, CloseReplaceAction, collapseDeepestExpandedLevel, copyAllCommand, copyMatchCommand, copyPathCommand, expandAll, FindInFilesCommand, findOrReplaceInFiles, FocusNextInputAction, focusNextSearchResult, FocusPreviousInputAction, focusPreviousSearchResult, focusSearchListCommand, getMultiSelectedSearchResources, getSearchView, openSearchView, refreshSearch, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, toggleWholeWordCommand } from 'vs/workbench/contrib/search/browser/searchActions'; import { searchClearIcon, searchCollapseAllIcon, searchExpandAllIcon, searchRefreshIcon, searchStopIcon, searchShowAsTree, searchViewIcon, searchShowAsList } from 'vs/workbench/contrib/search/browser/searchIcons'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; import { registerContributions as searchWidgetContributions } from 'vs/workbench/contrib/search/browser/searchWidget'; @@ -47,7 +47,7 @@ import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { resolveResourcesForSearchIncludes } from 'vs/workbench/services/search/common/queryBuilder'; import { getWorkspaceSymbols, IWorkspaceSymbol, SearchStateKey, SearchUIState } from 'vs/workbench/contrib/search/common/search'; import { ISearchHistoryService, SearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService'; -import { FileMatch, FileMatchOrMatch, FolderMatch, ISearchWorkbenchService, Match, RenderableMatch, SearchWorkbenchService } from 'vs/workbench/contrib/search/common/searchModel'; +import { FileMatch, FileMatchOrMatch, FolderMatch, FolderMatchWithResource, ISearchWorkbenchService, Match, RenderableMatch, SearchWorkbenchService } from 'vs/workbench/contrib/search/common/searchModel'; import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants'; import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -228,6 +228,19 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +const restrictSearchToFolderFromSearch: ICommandHandler = async (accessor, folderMatch?: FolderMatchWithResource) => { + return searchInFolderCommand(accessor, false, undefined, folderMatch); +}; + +const RESTRICT_SEARCH_TO_FOLDER_ID = 'search.restrictSearchToFolder'; +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: RESTRICT_SEARCH_TO_FOLDER_ID, + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.ResourceFolderFocusKey), + primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyF, + handler: restrictSearchToFolderFromSearch +}); + MenuRegistry.appendMenuItem(MenuId.SearchContext, { command: { id: Constants.ReplaceActionId, @@ -268,6 +281,16 @@ MenuRegistry.appendMenuItem(MenuId.SearchContext, { order: 2 }); +MenuRegistry.appendMenuItem(MenuId.SearchContext, { + group: 'search', + order: 3, + command: { + id: RESTRICT_SEARCH_TO_FOLDER_ID, + title: nls.localize('restrictResultsToFolder', "Restrict Search to Folder...") + }, + when: ContextKeyExpr.and(Constants.ResourceFolderFocusKey) +}); + KeybindingsRegistry.registerCommandAndKeybindingRule({ id: Constants.CopyMatchCommandId, weight: KeybindingWeight.WorkbenchContrib, @@ -583,17 +606,31 @@ const FocusSearchListCommand: ICommandAction = { }; MenuRegistry.addCommand(FocusSearchListCommand); +const searchInFolderFromExplorer: ICommandHandler = async (accessor, resource?: URI) => { + return searchInFolderCommand(accessor, true, resource); +}; -const searchInFolderCommand: ICommandHandler = async (accessor, resource?: URI) => { +const searchInFolderCommand: ICommandHandler = async (accessor, isFromExplorer: boolean, resource?: URI, folderMatch?: FolderMatchWithResource) => { const listService = accessor.get(IListService); const fileService = accessor.get(IFileService); const viewsService = accessor.get(IViewsService); const contextService = accessor.get(IWorkspaceContextService); const commandService = accessor.get(ICommandService); - const resources = getMultiSelectedResources(resource, listService, accessor.get(IEditorService), accessor.get(IExplorerService)); const searchConfig = accessor.get(IConfigurationService).getValue().search; const mode = searchConfig.mode; + let resources: URI[]; + + if (isFromExplorer) { + resources = getMultiSelectedResources(resource, listService, accessor.get(IEditorService), accessor.get(IExplorerService)); + } else { + const searchView = getSearchView(accessor.get(IViewsService)); + if (!searchView) { + return; + } + resources = getMultiSelectedSearchResources(searchView.getControl(), folderMatch, searchConfig); + } + const resolvedResources = fileService.resolveAll(resources.map(resource => ({ resource }))).then(results => { const folders: URI[] = []; results.forEach(result => { @@ -619,13 +656,13 @@ const searchInFolderCommand: ICommandHandler = async (accessor, resource?: URI) } }; -const FIND_IN_FOLDER_ID = 'filesExplorer.findInFolder'; +const FIND_IN_FOLDER_EXPLORER_ID = 'filesExplorer.findInFolder'; KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: FIND_IN_FOLDER_ID, + id: FIND_IN_FOLDER_EXPLORER_ID, weight: KeybindingWeight.WorkbenchContrib, when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerFolderContext), primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyF, - handler: searchInFolderCommand + handler: searchInFolderFromExplorer }); const FIND_IN_WORKSPACE_ID = 'filesExplorer.findInWorkspace'; @@ -652,7 +689,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { group: '4_search', order: 10, command: { - id: FIND_IN_FOLDER_ID, + id: FIND_IN_FOLDER_EXPLORER_ID, title: nls.localize('findInFolder', "Find in Folder...") }, when: ContextKeyExpr.and(ExplorerFolderContext) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 6d2be5c0d26..faa4fe8452a 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -31,6 +31,7 @@ import { SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/sea import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ISearchConfiguration, ISearchConfigurationProperties, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { URI } from 'vs/base/common/uri'; export function isSearchViewFocused(viewsService: IViewsService): boolean { const searchView = getSearchView(viewsService); @@ -683,13 +684,19 @@ export const focusSearchListCommand: ICommandHandler = accessor => { }); }; -function getElementsToOperateOnInfo(viewer: WorkbenchCompressibleObjectTree, currElement: RenderableMatch, sortConfig: ISearchConfigurationProperties): { elements: RenderableMatch[]; mustReselect: boolean } { +export function getMultiSelectedSearchResources(viewer: WorkbenchCompressibleObjectTree, currElement: RenderableMatch | undefined, sortConfig: ISearchConfigurationProperties): URI[] { + return getElementsToOperateOnInfo(viewer, currElement, sortConfig).elements + .map((renderableMatch) => ((renderableMatch instanceof Match) ? null : renderableMatch.resource)) + .filter((renderableMatch): renderableMatch is URI => (renderableMatch !== null)); +} + +function getElementsToOperateOnInfo(viewer: WorkbenchCompressibleObjectTree, currElement: RenderableMatch | undefined, sortConfig: ISearchConfigurationProperties): { elements: RenderableMatch[]; mustReselect: boolean } { let elements: RenderableMatch[] = viewer.getSelection().filter((x): x is RenderableMatch => x !== null).sort((a, b) => searchComparer(a, b, sortConfig.sortOrder)); - const mustReselect = elements.includes(currElement); // this indicates whether we need to re-focus/re-select on a remove. + const mustReselect = !currElement || elements.includes(currElement); // this indicates whether we need to re-focus/re-select on a remove. // if selection doesn't include multiple elements, just return current focus element. - if (!(elements.length > 1 && elements.includes(currElement))) { + if (currElement && !(elements.length > 1 && elements.includes(currElement))) { elements = [currElement]; } diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 9dbb88f8ed4..a74cfaff012 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -110,6 +110,7 @@ export class SearchView extends ViewPane { private fileMatchOrFolderMatchWithResourceFocus: IContextKey; private fileMatchFocused: IContextKey; private folderMatchFocused: IContextKey; + private folderMatchWithResourceFocused: IContextKey; private matchFocused: IContextKey; private hasSearchResultsKey: IContextKey; private lastFocusState: 'input' | 'tree' = 'input'; @@ -197,6 +198,7 @@ export class SearchView extends ViewPane { this.fileMatchOrFolderMatchWithResourceFocus = Constants.FileMatchOrFolderMatchWithResourceFocusKey.bindTo(this.contextKeyService); this.fileMatchFocused = Constants.FileFocusKey.bindTo(this.contextKeyService); this.folderMatchFocused = Constants.FolderFocusKey.bindTo(this.contextKeyService); + this.folderMatchWithResourceFocused = Constants.ResourceFolderFocusKey.bindTo(this.contextKeyService); this.hasSearchResultsKey = Constants.HasSearchResults.bindTo(this.contextKeyService); this.matchFocused = Constants.MatchFocusKey.bindTo(this.contextKeyService); this.searchStateKey = SearchStateKey.bindTo(this.contextKeyService); @@ -806,6 +808,7 @@ export class SearchView extends ViewPane { this.matchFocused.set(focus instanceof Match); this.fileMatchOrFolderMatchFocus.set(focus instanceof FileMatch || focus instanceof FolderMatch); this.fileMatchOrFolderMatchWithResourceFocus.set(focus instanceof FileMatch || focus instanceof FolderMatchWithResource); + this.folderMatchWithResourceFocused.set(focus instanceof FolderMatchWithResource); this.lastFocusState = 'tree'; } })); @@ -818,6 +821,7 @@ export class SearchView extends ViewPane { this.matchFocused.reset(); this.fileMatchOrFolderMatchFocus.reset(); this.fileMatchOrFolderMatchWithResourceFocus.reset(); + this.folderMatchWithResourceFocused.reset(); })); } diff --git a/src/vs/workbench/contrib/search/common/constants.ts b/src/vs/workbench/contrib/search/common/constants.ts index e1306326def..bd145765be8 100644 --- a/src/vs/workbench/contrib/search/common/constants.ts +++ b/src/vs/workbench/contrib/search/common/constants.ts @@ -57,6 +57,7 @@ export const FileMatchOrFolderMatchFocusKey = new RawContextKey('fileMa export const FileMatchOrFolderMatchWithResourceFocusKey = new RawContextKey('fileMatchOrFolderMatchWithResourceFocus', false); // Excludes "Other files" export const FileFocusKey = new RawContextKey('fileMatchFocus', false); export const FolderFocusKey = new RawContextKey('folderMatchFocus', false); +export const ResourceFolderFocusKey = new RawContextKey('folderMatchWithResourceFocus', false); export const MatchFocusKey = new RawContextKey('matchFocus', false); export const ViewHasSearchPatternKey = new RawContextKey('viewHasSearchPattern', false); export const ViewHasReplacePatternKey = new RawContextKey('viewHasReplacePattern', false); From 5df430612d11bef990fa09125f46a2cdb467c92b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 11:06:15 -0700 Subject: [PATCH 590/599] Make sure we clean up viewItemDisposables (#163673) This makes sure we clean up `viewItemDisposables`. This map stores dom event listeners, so it is good to be explicit about always disposing of these --- src/vs/base/browser/ui/actionbar/actionbar.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index bf63bee9f9e..a0f509ed0ae 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -10,7 +10,7 @@ import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { ActionRunner, IAction, IActionRunner, IRunEvent, Separator } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableMap, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import * as types from 'vs/base/common/types'; import 'vs/css!./actionbar'; @@ -62,7 +62,7 @@ export class ActionBar extends Disposable implements IActionRunner { private readonly options: IActionBarOptions; private _actionRunner: IActionRunner; - private _actionRunnerDisposables = this._register(new DisposableStore()); + private readonly _actionRunnerDisposables = this._register(new DisposableStore()); private _context: unknown; private readonly _orientation: ActionsOrientation; private readonly _triggerKeys: { @@ -72,7 +72,7 @@ export class ActionBar extends Disposable implements IActionRunner { // View Items viewItems: IActionViewItem[]; - private viewItemDisposables: Map; + private readonly viewItemDisposables = this._register(new DisposableMap()); private previouslyFocusedItem?: number; protected focusedItem?: number; private focusTracker: DOM.IFocusTracker; @@ -121,7 +121,6 @@ export class ActionBar extends Disposable implements IActionRunner { this._actionRunnerDisposables.add(this._actionRunner.onWillRun(e => this._onWillRun.fire(e))); this.viewItems = []; - this.viewItemDisposables = new Map(); this.focusedItem = undefined; this.domNode = document.createElement('div'); @@ -413,18 +412,15 @@ export class ActionBar extends Disposable implements IActionRunner { pull(index: number): void { if (index >= 0 && index < this.viewItems.length) { this.actionsList.removeChild(this.actionsList.childNodes[index]); - this.viewItemDisposables.get(this.viewItems[index])?.dispose(); - this.viewItemDisposables.delete(this.viewItems[index]); + this.viewItemDisposables.deleteAndDispose(this.viewItems[index]); dispose(this.viewItems.splice(index, 1)); this.refreshRole(); } } clear(): void { - dispose(this.viewItems); - dispose(this.viewItemDisposables.values()); - this.viewItemDisposables.clear(); - this.viewItems = []; + this.viewItems = dispose(this.viewItems); + this.viewItemDisposables.clearAndDisposeAll(); DOM.clearNode(this.actionsList); this.refreshRole(); } @@ -579,8 +575,7 @@ export class ActionBar extends Disposable implements IActionRunner { } override dispose(): void { - dispose(this.viewItems); - this.viewItems = []; + this.viewItems = dispose(this.viewItems); this.getContainer().remove(); super.dispose(); } From 7b673b211f431bd60103541f6898006e67a063cf Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 11:09:13 -0700 Subject: [PATCH 591/599] Move quick input list element cleanup to `disposeElement` (#163668) Move quick input list cleanup to `disposeElement` The the disposables, we are currently trying to dispose of these values twice (which is a noop) The action bar should also be cleared in `disposeElement` instead of relying on `renderElement` being called again --- src/vs/base/parts/quickinput/browser/quickInputList.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/quickInputList.ts b/src/vs/base/parts/quickinput/browser/quickInputList.ts index ba66b6e4afa..515bae093a6 100644 --- a/src/vs/base/parts/quickinput/browser/quickInputList.ts +++ b/src/vs/base/parts/quickinput/browser/quickInputList.ts @@ -158,7 +158,6 @@ class ListElementRenderer implements IListRenderer { @@ -236,6 +234,7 @@ class ListElementRenderer implements IListRenderer Date: Thu, 13 Oct 2022 08:59:20 -0700 Subject: [PATCH 592/599] cli: use openssl for all crypto-related activities For compliance with SDL and MSFT crypto standards. Right now this uses our forks of russh and secret-service. russh seems amenable to getting this merged (https://github.com/warp-tech/russh/pull/52) but TBD about the secret-service crate. Fixes https://github.com/microsoft/vscode-internalbacklog/issues/3158 --- cli/Cargo.lock | 1315 ++++++++++++++------------------ cli/Cargo.toml | 8 +- cli/src/tunnels/dev_tunnels.rs | 8 +- 3 files changed, 603 insertions(+), 728 deletions(-) diff --git a/cli/Cargo.lock b/cli/Cargo.lock index cc6b94be2f4..389b31b5d01 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -8,87 +8,67 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher 0.2.5", -] - -[[package]] -name = "aes" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" -dependencies = [ - "cfg-if", - "cipher 0.4.3", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" -dependencies = [ - "aead", - "aes 0.8.1", - "cipher 0.4.3", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] -name = "async-io" -version = "1.7.0" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ + "libc", +] + +[[package]] +name = "async-broadcast" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61" +dependencies = [ + "event-listener", + "futures-core", + "parking_lot", +] + +[[package]] +name = "async-channel" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-io" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +dependencies = [ + "autocfg", "concurrent-queue", "futures-lite", "libc", @@ -103,10 +83,36 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.53" +name = "async-lock" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + +[[package]] +name = "async-trait" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", @@ -136,21 +142,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "base64ct" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" - [[package]] name = "bcrypt-pbkdf" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12621b8e87feb183a6e5dbb315e49026b2229c4398797ee0ae2d1bc00aef41b9" +checksum = "7c38c03b9506bd92bf1ef50665a81eda156f615438f7654bffba58907e6149d7" dependencies = [ "blowfish", - "crypto-mac 0.11.1", - "pbkdf2 0.8.0", + "crypto-mac", + "pbkdf2", "sha2 0.9.9", "zeroize", ] @@ -178,29 +178,13 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] -[[package]] -name = "block-modes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" -dependencies = [ - "block-padding 0.2.1", - "cipher 0.2.5", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "block-padding" version = "0.3.2" @@ -217,15 +201,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" dependencies = [ "byteorder", - "cipher 0.3.0", + "cipher", "opaque-debug", ] [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byteorder" @@ -235,9 +219,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cache-padded" @@ -245,15 +229,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher 0.4.3", -] - [[package]] name = "cc" version = "1.0.73" @@ -266,40 +241,22 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chacha20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" -dependencies = [ - "cfg-if", - "cipher 0.4.3", - "cpufeatures", -] - [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", "time", + "wasm-bindgen", "winapi", ] -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.3.0" @@ -309,28 +266,18 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" -version = "3.1.6" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim", "termcolor", "textwrap", @@ -338,9 +285,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.1.4" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -392,7 +339,7 @@ dependencies = [ "tar", "tempfile", "tokio", - "tokio-util 0.7.0", + "tokio-util", "tunnels", "url", "uuid", @@ -401,24 +348,33 @@ dependencies = [ ] [[package]] -name = "concurrent-queue" -version = "1.2.2" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" dependencies = [ "cache-padded", ] [[package]] name = "console" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" dependencies = [ "encode_unicode", + "lazy_static", "libc", - "once_cell", - "regex", "terminal_size", "unicode-width", "winapi", @@ -442,9 +398,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -460,9 +416,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -470,9 +426,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -481,25 +437,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if", - "lazy_static", ] [[package]] @@ -509,20 +464,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.3", "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -534,25 +478,47 @@ dependencies = [ ] [[package]] -name = "ctr" -version = "0.9.1" +name = "cxx" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d14f329cfbaf5d0e06b5e87fff7e265d2673c5ea7d2c27691a2c107db1442a0" +checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" dependencies = [ - "cipher 0.4.3", + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", ] [[package]] -name = "curve25519-dalek" -version = "3.2.0" +name = "cxx-build" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -574,9 +540,9 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c8ae48e400addc32a8710c8d62d55cb84249a7d58ac4cd959daecfbaddc545" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" dependencies = [ "console", "tempfile", @@ -594,11 +560,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", "subtle", ] @@ -623,43 +589,20 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", "winapi", ] -[[package]] -name = "ed25519" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "encode_unicode" @@ -669,18 +612,18 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", "serde", @@ -688,9 +631,9 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", @@ -712,35 +655,39 @@ dependencies = [ ] [[package]] -name = "fastrand" -version = "1.7.0" +name = "event-listener" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] [[package]] name = "filetime" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi", + "windows-sys", ] [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] @@ -776,9 +723,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -791,9 +738,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -801,15 +748,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -818,9 +765,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-lite" @@ -839,9 +786,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -850,21 +797,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-channel", "futures-core", @@ -880,9 +827,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -911,30 +858,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", -] - -[[package]] -name = "ghash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "h2" -version = "0.3.11" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ "bytes", "fnv", @@ -945,15 +882,15 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.6.9", + "tokio-util", "tracing", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -970,46 +907,32 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hex-literal" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac 0.10.1", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.1", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] name = "http" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", @@ -1018,9 +941,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -1029,9 +952,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1041,9 +964,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.19" +version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ "bytes", "futures-channel", @@ -1076,6 +999,30 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "idna" version = "0.3.0" @@ -1088,9 +1035,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -1114,7 +1061,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "block-padding 0.3.2", + "block-padding", "generic-array", ] @@ -1129,30 +1076,30 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] [[package]] name = "keyring" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "894a58932447ecc241a3545135bdfd26ac0e611295b391904ce0b085310ab38c" +checksum = "38fb8399ddcabfccb274577a8d90f0653e0b5b5977797c1c8834ad09839a10e5" dependencies = [ "byteorder", "secret-service", @@ -1168,16 +1115,26 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ + "autocfg", "scopeguard", ] @@ -1198,9 +1155,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -1219,12 +1176,11 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", - "autocfg", ] [[package]] @@ -1236,14 +1192,14 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys", ] [[package]] name = "native-tls" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" dependencies = [ "lazy_static", "libc", @@ -1257,24 +1213,13 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nb-connect" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb540dc6ef51cfe1916ec038ce7a620daf3a111e2502d745197cd53d6bca15" -dependencies = [ - "libc", - "socket2", -] - [[package]] name = "nix" -version = "0.22.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cc", "cfg-if", "libc", "memoffset", @@ -1291,11 +1236,11 @@ dependencies = [ [[package]] name = "num" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" dependencies = [ - "num-bigint 0.3.3", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -1303,17 +1248,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -1328,18 +1262,18 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1358,21 +1292,21 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.3.3", + "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] @@ -1395,9 +1329,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "opaque-debug" @@ -1407,28 +1341,40 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "open" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0524af9508f9b5c4eb41dce095860456727748f63b478d625f119a70e0d764a" +checksum = "f2423ffbf445b82e58c3b1543655968923dd06f85432f10be2bb4f1b7122f98c" dependencies = [ "pathdiff", - "winapi", + "windows-sys", ] [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -1446,9 +1392,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.72" +version = "0.9.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce" dependencies = [ "autocfg", "cc", @@ -1546,14 +1492,21 @@ dependencies = [ ] [[package]] -name = "os_str_bytes" -version = "6.0.0" +name = "ordered-stream" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" dependencies = [ - "memchr", + "futures-core", + "pin-project-lite", ] +[[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + [[package]] name = "parking" version = "2.0.0" @@ -1572,27 +1525,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.32.0", + "windows-sys", ] [[package]] -name = "password-hash" -version = "0.4.2" +name = "paste" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.3", - "subtle", -] +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pathdiff" @@ -1606,19 +1554,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ - "crypto-mac 0.11.1", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.3", - "hmac 0.12.1", - "password-hash", - "sha2 0.10.2", + "crypto-mac", ] [[package]] @@ -1641,16 +1577,17 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "polling" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" dependencies = [ + "autocfg", "cfg-if", "libc", "log", @@ -1658,29 +1595,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1689,19 +1603,11 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] @@ -1732,18 +1638,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -1769,7 +1675,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -1789,7 +1695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -1803,11 +1709,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.7", ] [[package]] @@ -1821,9 +1727,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -1833,41 +1739,41 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.7", "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -1876,9 +1782,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -1891,9 +1797,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" dependencies = [ "base64", "bytes", @@ -1907,10 +1813,10 @@ dependencies = [ "hyper-tls", "ipnet", "js-sys", - "lazy_static", "log", "mime", "native-tls", + "once_cell", "percent-encoding", "pin-project-lite", "serde", @@ -1918,7 +1824,8 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-util 0.6.9", + "tokio-util", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -1928,19 +1835,20 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" dependencies = [ "byteorder", "num-traits", + "paste", ] [[package]] name = "rmp-serde" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3eedffbfcc6a428f230c04baf8f59bd73c1781361e4286111fe900849aaddaf" +checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" dependencies = [ "byteorder", "rmp", @@ -1950,31 +1858,25 @@ dependencies = [ [[package]] name = "russh" version = "0.34.0-beta.16" -source = "git+https://github.com/microsoft/vscode-russh?branch=own#fbf1ae38259bb20bd0b0ca310abc9d765abb6a90" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#e1d29f04658b62b33391a0b14899517fd72d1f5c" dependencies = [ - "aes 0.8.1", - "aes-gcm", "bitflags", "byteorder", - "chacha20", - "ctr", - "curve25519-dalek", - "digest 0.10.3", + "digest 0.10.5", "flate2", "futures", "generic-array", "hex-literal", - "hmac 0.12.1", + "hmac", "log", - "num-bigint 0.4.3", + "num-bigint", "once_cell", "openssl", - "poly1305", "rand 0.8.5", "russh-cryptovec", "russh-keys", - "sha1", - "sha2 0.10.2", + "sha1 0.10.5", + "sha2 0.10.6", "subtle", "thiserror", "tokio", @@ -1983,7 +1885,7 @@ dependencies = [ [[package]] name = "russh-cryptovec" version = "0.7.0-beta.1" -source = "git+https://github.com/microsoft/vscode-russh?branch=own#fbf1ae38259bb20bd0b0ca310abc9d765abb6a90" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#e1d29f04658b62b33391a0b14899517fd72d1f5c" dependencies = [ "libc", "winapi", @@ -1991,34 +1893,27 @@ dependencies = [ [[package]] name = "russh-keys" -version = "0.22.0-beta.6" -source = "git+https://github.com/microsoft/vscode-russh?branch=own#fbf1ae38259bb20bd0b0ca310abc9d765abb6a90" +version = "0.22.0-beta.7" +source = "git+https://github.com/microsoft/vscode-russh?branch=main#e1d29f04658b62b33391a0b14899517fd72d1f5c" dependencies = [ - "aes 0.8.1", "bcrypt-pbkdf", "bit-vec", - "block-padding 0.3.2", "byteorder", - "cbc", - "ctr", "data-encoding", "dirs 3.0.2", - "ed25519-dalek", "futures", - "hmac 0.12.1", "inout", "log", "md5", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "openssl", - "pbkdf2 0.11.0", "rand 0.7.3", "rand_core 0.5.1", "russh-cryptovec", "serde", "serde_derive", - "sha2 0.10.2", + "sha2 0.10.6", "thiserror", "tokio", "tokio-stream", @@ -2033,26 +1928,20 @@ checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi", + "windows-sys", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" @@ -2060,30 +1949,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "secret-service" -version = "2.0.1" +name = "scratch" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2400fb1bf2a87b303ada204946294f932ade4929477e9e2bf66d7b49a66656ec" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "secret-service" +version = "2.0.2" +source = "git+https://github.com/microsoft/vscode-secret-service-rs?rev=ccef335714cdf3744ff85f812b8fba5b6194dcfa#ccef335714cdf3744ff85f812b8fba5b6194dcfa" dependencies = [ - "aes 0.6.0", - "block-modes", - "hkdf", - "lazy_static", + "futures-util", + "generic-array", "num", + "once_cell", + "openssl", "rand 0.8.5", "serde", - "sha2 0.9.9", "zbus", - "zbus_macros", - "zvariant", - "zvariant_derive", ] [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2104,27 +1994,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -2133,9 +2023,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" dependencies = [ "itoa", "ryu", @@ -2144,9 +2034,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", @@ -2173,20 +2063,35 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] name = "sha1" -version = "0.10.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.9.9" @@ -2202,13 +2107,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -2220,29 +2125,26 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ea32af43239f0d353a7dd75a22d94c329c8cdaafdcb4c1c1335aa10c298a4a" - [[package]] name = "slab" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -2268,9 +2170,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -2291,9 +2193,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.23.5" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fa4c84a5305909b0eedfcc8d1f2fafdbede645bb700a45ecaafe681a0ac5d6" +checksum = "3977ec2e0520829be45c8a2df70db2bf364714d8a748316a10c3c35d4d2b01c9" dependencies = [ "cfg-if", "core-foundation-sys", @@ -2350,24 +2252,24 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -2387,9 +2289,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -2402,9 +2304,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ "autocfg", "bytes", @@ -2412,7 +2314,6 @@ dependencies = [ "memchr", "mio", "num_cpus", - "once_cell", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -2423,9 +2324,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -2444,9 +2345,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite", @@ -2469,31 +2370,17 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] @@ -2507,26 +2394,38 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.29" +name = "tracing-attributes" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] @@ -2560,7 +2459,7 @@ dependencies = [ [[package]] name = "tunnels" version = "0.1.0" -source = "git+https://github.com/connor4312/dev-tunnels?branch=host-relay#066acce214983ae28110d6d867e5b8006cc2da7f" +source = "git+https://github.com/microsoft/dev-tunnels?rev=3870e9133dfb9557774521bb447827f19b26e55d#3870e9133dfb9557774521bb447827f19b26e55d" dependencies = [ "async-trait", "chrono", @@ -2574,7 +2473,7 @@ dependencies = [ "thiserror", "tokio", "tokio-tungstenite", - "tokio-util 0.7.0", + "tokio-util", "tungstenite", "url", "uuid", @@ -2587,47 +2486,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] -name = "unicode-bidi" -version = "0.3.7" +name = "uds_windows" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" @@ -2652,7 +2551,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.7", "serde", ] @@ -2704,9 +2603,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2714,13 +2613,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -2729,9 +2628,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", @@ -2741,9 +2640,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2751,9 +2650,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -2764,15 +2663,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -2833,20 +2732,7 @@ dependencies = [ "bitflags", "err-derive", "widestring", - "windows-sys 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" -dependencies = [ - "windows_aarch64_msvc 0.32.0", - "windows_i686_gnu 0.32.0", - "windows_i686_msvc 0.32.0", - "windows_x86_64_gnu 0.32.0", - "windows_x86_64_msvc 0.32.0", + "windows-sys", ] [[package]] @@ -2855,67 +2741,37 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_msvc" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" - [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" -[[package]] -name = "windows_i686_gnu" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" - [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" -[[package]] -name = "windows_i686_msvc" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" - [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" -[[package]] -name = "windows_x86_64_gnu" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" - [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" - [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -2924,18 +2780,18 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] [[package]] name = "xattr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] @@ -2947,64 +2803,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" dependencies = [ "bit-vec", - "num-bigint 0.4.3", + "num-bigint", ] [[package]] name = "zbus" -version = "1.9.3" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cbeb2291cd7267a94489b71376eda33496c1b9881adf6b36f26cc2779f3fc49" +checksum = "be2db10dd0354816a3615c72deff837f983d5c8ad9a0312727d0f89a5a9e9145" dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", "byteorder", "derivative", + "dirs 4.0.0", "enumflags2", - "fastrand", - "futures", - "nb-connect", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", "nix", "once_cell", - "polling", - "scoped-tls", + "ordered-stream", + "rand 0.8.5", "serde", "serde_repr", + "sha1 0.6.1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", "zbus_macros", + "zbus_names", "zvariant", ] [[package]] name = "zbus_macros" -version = "1.9.3" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3959a7847cf95e3d51e312856617c5b1b77191176c65a79a5f14d778bbe0a6" +checksum = "7d03f1a5fb482cc0d97f3d3de9fe2e942f436a635a5fb6c12c9f03f21eb03075" dependencies = [ - "proc-macro-crate 0.1.5", + "proc-macro-crate", "proc-macro2", "quote", + "regex", "syn", ] +[[package]] +name = "zbus_names" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + [[package]] name = "zeroize" -version = "1.5.7" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" [[package]] name = "zip" @@ -3021,9 +2890,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "2.10.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525" +checksum = "b794fb7f59af4105697b0449ba31731ee5dbb3e773a17dbdf3d36206ea1b1644" dependencies = [ "byteorder", "enumflags2", @@ -3035,11 +2904,11 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "2.10.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ca5e22593eb4212382d60d26350065bf2a02c34b85bc850474a74b589a3de9" +checksum = "dd58d4b6c8e26d3dd2149c8c40c6613ef6451b9885ff1296d1ac86c388351a54" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 936f75bb9dd..eca7ee53a6d 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -39,7 +39,7 @@ serde_bytes = "0.11.5" chrono = { version = "0.4", features = ["serde"] } gethostname = "0.2.3" libc = "0.2" -tunnels = { git = "https://github.com/connor4312/dev-tunnels", branch = "host-relay", features = ["connections", "vendored-openssl"] } +tunnels = { git = "https://github.com/microsoft/dev-tunnels", rev = "3870e9133dfb9557774521bb447827f19b26e55d", default-features = false, features = ["connections", "vendored-openssl"] } keyring = "1.1" dialoguer = "0.10" hyper = "0.14" @@ -56,6 +56,12 @@ windows-service = "0.5" [target.'cfg(target_os = "linux")'.dependencies] tar = { version = "0.4" } +[patch.crates-io] +russh = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +russh-cryptovec = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +russh-keys = { git = "https://github.com/microsoft/vscode-russh", branch = "main" } +secret-service = { git = "https://github.com/microsoft/vscode-secret-service-rs", rev = "ccef335714cdf3744ff85f812b8fba5b6194dcfa" } + [profile.release] strip = true lto = true diff --git a/cli/src/tunnels/dev_tunnels.rs b/cli/src/tunnels/dev_tunnels.rs index 224e0a43b62..cc1c639a18f 100644 --- a/cli/src/tunnels/dev_tunnels.rs +++ b/cli/src/tunnels/dev_tunnels.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; use std::time::Duration; use tokio::sync::{mpsc, watch}; -use tunnels::connections::{ForwardedPortConnection, HostRelay}; +use tunnels::connections::{ForwardedPortConnection, RelayTunnelHost}; use tunnels::contracts::{ Tunnel, TunnelPort, TunnelRelayTunnelEndpoint, PORT_TOKEN, TUNNEL_PROTOCOL_AUTO, }; @@ -607,7 +607,7 @@ impl DevTunnels { struct ActiveTunnelManager { close_tx: Option>, endpoint_rx: watch::Receiver>>, - relay: Arc>, + relay: Arc>, } impl ActiveTunnelManager { @@ -620,7 +620,7 @@ impl ActiveTunnelManager { let (endpoint_tx, endpoint_rx) = watch::channel(None); let (close_tx, close_rx) = mpsc::channel(1); - let relay = Arc::new(tokio::sync::Mutex::new(HostRelay::new(locator, mgmt))); + let relay = Arc::new(tokio::sync::Mutex::new(RelayTunnelHost::new(locator, mgmt))); let relay_spawned = relay.clone(); tokio::spawn(async move { @@ -719,7 +719,7 @@ impl ActiveTunnelManager { async fn spawn_tunnel( log: log::Logger, - relay: Arc>, + relay: Arc>, mut close_rx: mpsc::Receiver<()>, endpoint_tx: watch::Sender>>, access_token_provider: impl AccessTokenProvider + 'static, From 8dfd89e065931251b3b6e7728a00cb52c39f86de Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:11:47 -0700 Subject: [PATCH 593/599] change search badge to show recursive match number (#163604) --- src/vs/workbench/contrib/search/browser/searchResultsView.ts | 2 +- src/vs/workbench/contrib/search/common/searchModel.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index da7f41befc9..54584f9a82c 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -168,7 +168,7 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree } private renderFolderDetails(folder: FolderMatch, templateData: IFolderMatchTemplate) { - const count = this.searchView.isTreeLayoutViewVisible ? folder.count() : folder.recursiveFileCount(); + const count = folder.recursiveMatchCount(); templateData.badge.setCount(count); templateData.badge.setTitleFormat(count > 1 ? nls.localize('searchFileMatches', "{0} files found", count) : nls.localize('searchFileMatch', "{0} file found", count)); diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 858e3294543..ab6b3513570 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -662,6 +662,10 @@ export class FolderMatch extends Disposable { return this.downstreamFileMatches().length; } + recursiveMatchCount(): number { + return this.downstreamFileMatches().reduce((prev, match) => prev + match.count(), 0); + } + get query(): ITextQuery | null { return this._query; } From 46e6b68743bd06db07d355db0c86fd78f8db9c22 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 11:12:46 -0700 Subject: [PATCH 594/599] Move webview animation workaround to viewPane (#163675) This workaround is only required for webview views, so let's move the code there --- .../contrib/webview/browser/overlayWebview.ts | 14 -------------- .../contrib/webviewView/browser/webviewViewPane.ts | 13 +++++++++++-- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts index b3d0e5afd70..50678fca436 100644 --- a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts +++ b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts @@ -31,7 +31,6 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { private _html: string = ''; private _initialScrollProgress: number = 0; private _state: string | undefined = undefined; - private _repositionTimeout: any | undefined = undefined; private _extension: WebviewExtensionDescription | undefined; private _contentOptions: WebviewContentOptions; @@ -85,8 +84,6 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { } this._firstLoadPendingMessages.clear(); - clearTimeout(this._repositionTimeout); - this._onDidDispose.fire(); super.dispose(); @@ -163,17 +160,6 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { } public layoutWebviewOverElement(element: HTMLElement, dimension?: Dimension, clippingContainer?: HTMLElement) { - this.doLayoutWebviewOverElement(element, dimension, clippingContainer); - - // Temporary fix for https://github.com/microsoft/vscode/issues/110450 - // There is an animation that lasts about 200ms, update the webview positioning once this animation is complete. - clearTimeout(this._repositionTimeout); - this._repositionTimeout = setTimeout(() => { - this.doLayoutWebviewOverElement(element, dimension, clippingContainer); - }, 200); - } - - public doLayoutWebviewOverElement(element: HTMLElement, dimension?: Dimension, clippingContainer?: HTMLElement) { if (!this._container || !this._container.parentElement) { return; } diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts index 0ede150e8ce..e9cc85ee973 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts @@ -63,6 +63,8 @@ export class WebviewViewPane extends ViewPane { private readonly viewState: MementoObject; private readonly extensionId?: ExtensionIdentifier; + private _repositionTimeout?: any; + constructor( options: IViewletViewOptions, @IConfigurationService configurationService: IConfigurationService, @@ -110,6 +112,8 @@ export class WebviewViewPane extends ViewPane { override dispose() { this._onDispose.fire(); + clearTimeout(this._repositionTimeout); + super.dispose(); } @@ -286,16 +290,21 @@ export class WebviewViewPane extends ViewPane { return; } - webviewEntry.layoutWebviewOverElement(this._container); - if (!this._rootContainer || !this._rootContainer.isConnected) { this._rootContainer = this.findRootContainer(this._container); } + webviewEntry.layoutWebviewOverElement(this._container); + if (this._rootContainer) { const { top, left, right, bottom } = computeClippingRect(this._container, this._rootContainer); webviewEntry.container.style.clipPath = `polygon(${left}px ${top}px, ${right}px ${top}px, ${right}px ${bottom}px, ${left}px ${bottom}px)`; } + + // Temporary fix for https://github.com/microsoft/vscode/issues/110450 + // There is an animation that lasts about 200ms, update the webview positioning once this animation is complete. + clearTimeout(this._repositionTimeout); + this._repositionTimeout = setTimeout(() => this.layoutWebview(), 200); } private findRootContainer(container: HTMLElement): HTMLElement | undefined { From 740d837399e5561f1706f8440d573feb1119dc8a Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:16:43 -0700 Subject: [PATCH 595/599] Switch workspace restricted settings to use indicators (#163601) * Change policy and workspace trust to indicators * Add link to workspace trust indicator * Remove restricted settings configured check * Fix deprecated method usage * fix - trigger event when restricted settings are updated * feedback - use userDataProfilesService for profilesEnabled variable Co-authored-by: Sandeep Somavarapu --- .../common/configurationModels.ts | 4 +- .../settingsEditorSettingIndicators.ts | 117 ++++++++++++++---- .../preferences/browser/settingsTree.ts | 116 ++--------------- .../preferences/browser/settingsTreeModels.ts | 19 +-- .../test/browser/configurationService.test.ts | 51 ++++++++ 5 files changed, 162 insertions(+), 145 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 804398fe3d3..167cb634f1c 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -33,7 +33,7 @@ export class ConfigurationModel implements IConfigurationModel { } private _rawConfiguration: ConfigurationModel | undefined; - private get rawConfiguration(): ConfigurationModel { + get rawConfiguration(): ConfigurationModel { if (!this._rawConfiguration) { if (this.raw?.length) { const rawConfigurationModels = this.raw.map(raw => { @@ -978,7 +978,7 @@ export class ConfigurationChangeEvent implements IConfigurationChangeEvent { } function compare(from: ConfigurationModel | undefined, to: ConfigurationModel | undefined): IConfigurationCompareResult { - const { added, removed, updated } = compareConfigurationContents(to, from); + const { added, removed, updated } = compareConfigurationContents(to?.rawConfiguration, from?.rawConfiguration); const overrides: [string, string[]][] = []; const fromOverrideIdentifiers = from?.getAllOverrideIdentifiers() || []; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts index 73b3f4e8f3e..cf90eed08f2 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts @@ -12,11 +12,13 @@ import { Emitter } from 'vs/base/common/event'; import { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { localize } from 'vs/nls'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { getIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge'; import { getDefaultIgnoredSettings, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; -import { MODIFIED_INDICATOR_USE_INLINE_ONLY } from 'vs/workbench/contrib/preferences/common/preferences'; +import { MODIFIED_INDICATOR_USE_INLINE_ONLY, POLICY_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences'; import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; const $ = DOM.$; @@ -34,20 +36,26 @@ export interface ISettingOverrideClickEvent { */ export class SettingsTreeIndicatorsLabel implements IDisposable { private indicatorsContainerElement: HTMLElement; + private workspaceTrustElement: HTMLElement; private scopeOverridesElement: HTMLElement; private scopeOverridesLabel: SimpleIconLabel; private scopeOverridesHover: MutableDisposable; private syncIgnoredElement: HTMLElement; - private syncIgnoredHover: ICustomHover | undefined; private defaultOverrideIndicatorElement: HTMLElement; private hoverDelegate: IHoverDelegate; + private profilesEnabled: boolean; + + // Holds hovers that contain a fixed message. + private simpleHoverStore: DisposableStore; constructor( container: HTMLElement, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IConfigurationService configurationService: IConfigurationService, @IHoverService hoverService: IHoverService, @IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService, - @ILanguageService private readonly languageService: ILanguageService) { + @ILanguageService private readonly languageService: ILanguageService, + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, + @ICommandService private readonly commandService: ICommandService) { this.indicatorsContainerElement = DOM.append(container, $('.misc-label')); this.indicatorsContainerElement.style.display = 'inline'; @@ -60,12 +68,41 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { placement: 'element' }; + this.simpleHoverStore = new DisposableStore(); const scopeOverridesIndicator = this.createScopeOverridesIndicator(); + this.workspaceTrustElement = this.createWorkspaceTrustElement(); this.scopeOverridesElement = scopeOverridesIndicator.element; this.scopeOverridesLabel = scopeOverridesIndicator.label; this.syncIgnoredElement = this.createSyncIgnoredElement(); this.defaultOverrideIndicatorElement = this.createDefaultOverrideIndicator(); this.scopeOverridesHover = new MutableDisposable(); + this.profilesEnabled = this.userDataProfilesService.isEnabled(); + } + + private createWorkspaceTrustElement(): HTMLElement { + const workspaceTrustElement = $('span.setting-item-workspace-trust'); + const workspaceTrustLabel = new SimpleIconLabel(workspaceTrustElement); + workspaceTrustLabel.text = localize('workspaceUntrustedLabel', "Requires Workspace Trust"); + const contentFallback = localize('trustLabel', "This setting can only be applied in a trusted workspace."); + + const contentMarkdownString = contentFallback + ` [${localize('manageWorkspaceTrust', "Manage Workspace Trust")}](manage-workspace-trust).`; + const content: ITooltipMarkdownString = { + markdown: { + value: contentMarkdownString, + isTrusted: false, + supportHtml: false + }, + markdownNotSupportedFallback: contentFallback + }; + const options: IUpdatableHoverOptions = { + linkHandler: (url: string) => { + this.commandService.executeCommand('workbench.trust.manage'); + this.scopeOverridesHover.value?.hide(); + } + }; + + this.simpleHoverStore.add(setupCustomHover(this.hoverDelegate, workspaceTrustElement, content, options)); + return workspaceTrustElement; } private createScopeOverridesIndicator(): { element: HTMLElement; label: SimpleIconLabel } { @@ -79,7 +116,7 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { const syncIgnoredLabel = new SimpleIconLabel(syncIgnoredElement); syncIgnoredLabel.text = localize('extensionSyncIgnoredLabel', 'Not synced'); const syncIgnoredHoverContent = localize('syncIgnoredTitle', "This setting is ignored during sync"); - this.syncIgnoredHover = setupCustomHover(this.hoverDelegate, syncIgnoredElement, syncIgnoredHoverContent); + this.simpleHoverStore.add(setupCustomHover(this.hoverDelegate, syncIgnoredElement, syncIgnoredHoverContent)); return syncIgnoredElement; } @@ -91,7 +128,7 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { } private render() { - const elementsToShow = [this.scopeOverridesElement, this.syncIgnoredElement, this.defaultOverrideIndicatorElement].filter(element => { + const elementsToShow = [this.scopeOverridesElement, this.workspaceTrustElement, this.syncIgnoredElement, this.defaultOverrideIndicatorElement].filter(element => { return element.style.display !== 'none'; }); @@ -109,6 +146,11 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { } } + updateWorkspaceTrust(element: SettingsTreeSettingElement) { + this.workspaceTrustElement.style.display = element.isUntrusted ? 'inline' : 'none'; + this.render(); + } + updateSyncIgnored(element: SettingsTreeSettingElement, ignoredSettings: string[]) { this.syncIgnoredElement.style.display = this.userDataSyncEnablementService.isEnabled() && ignoredSettings.includes(element.setting.key) ? 'inline' : 'none'; @@ -128,14 +170,38 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { dispose() { this.scopeOverridesHover.dispose(); - this.syncIgnoredHover?.dispose(); + this.simpleHoverStore.dispose(); } - updateScopeOverrides(element: SettingsTreeSettingElement, elementDisposables: DisposableStore, onDidClickOverrideElement: Emitter) { + updateScopeOverrides(element: SettingsTreeSettingElement, elementDisposables: DisposableStore, onDidClickOverrideElement: Emitter, onApplyFilter: Emitter) { this.scopeOverridesElement.innerText = ''; this.scopeOverridesElement.style.display = 'none'; - const profileFeatureEnabled = this.configurationService.getValue('workbench.experimental.settingsProfiles.enabled'); - if (profileFeatureEnabled && !element.setting.isLanguageTagSetting && element.matchesScope(ConfigurationTarget.APPLICATION, false)) { + if (element.hasPolicyValue) { + // If the setting falls under a policy, then no matter what the user sets, the policy value takes effect. + this.scopeOverridesElement.style.display = 'inline'; + this.scopeOverridesElement.classList.add('with-custom-hover'); + + const policyText = localize('policyLabelText', "Managed by policy"); + this.scopeOverridesLabel.text = policyText; + + const contentFallback = localize('policyDescription', "This setting is managed by your organization."); + const contentMarkdownString = contentFallback + ` [${localize('policyFilterLink', "View policy settings")}](policy-settings).`; + const content: ITooltipMarkdownString = { + markdown: { + value: contentMarkdownString, + isTrusted: false, + supportHtml: false + }, + markdownNotSupportedFallback: contentFallback + }; + const options: IUpdatableHoverOptions = { + linkHandler: (url: string) => { + onApplyFilter.fire(`@${POLICY_SETTING_TAG}`); + this.scopeOverridesHover.value?.hide(); + } + }; + this.scopeOverridesHover.value = setupCustomHover(this.hoverDelegate, this.scopeOverridesElement, content, options); + } else if (this.profilesEnabled && element.matchesScope(ConfigurationTarget.APPLICATION, false)) { // If the setting is an application-scoped setting, there are no overrides so we can use this // indicator to display that information instead. this.scopeOverridesElement.style.display = 'inline'; @@ -290,22 +356,29 @@ function getAccessibleScopeDisplayMidSentenceText(completeScope: string, languag return localizedScope; } -export function getIndicatorsLabelAriaLabel(element: SettingsTreeSettingElement, configurationService: IConfigurationService, languageService: ILanguageService): string { +export function getIndicatorsLabelAriaLabel(element: SettingsTreeSettingElement, configurationService: IConfigurationService, userDataProfilesService: IUserDataProfilesService, languageService: ILanguageService): string { const ariaLabelSections: string[] = []; - const profileFeatureEnabled = configurationService.getValue('workbench.experimental.settingsProfiles.enabled'); - if (profileFeatureEnabled && element.matchesScope(ConfigurationTarget.APPLICATION, false)) { - ariaLabelSections.push(localize('applicationSettingDescriptionAccessible', "Setting value retained when switching profiles")); + // Add workspace trust text + if (element.isUntrusted) { + ariaLabelSections.push(localize('workspaceUntrustedAriaLabel', "Workspace untrusted; setting value will not take effect")); } - // Add other overrides text - const otherOverridesStart = element.isConfigured ? - localize('alsoConfiguredIn', "Also modified in") : - localize('configuredIn', "Modified in"); - const otherOverridesList = element.overriddenScopeList - .map(scope => getAccessibleScopeDisplayMidSentenceText(scope, languageService)).join(', '); - if (element.overriddenScopeList.length) { - ariaLabelSections.push(`${otherOverridesStart} ${otherOverridesList}`); + const profilesEnabled = userDataProfilesService.isEnabled(); + if (element.hasPolicyValue) { + ariaLabelSections.push(localize('policyDescriptionAccessible', "Managed by organization policy")); + } else if (profilesEnabled && element.matchesScope(ConfigurationTarget.APPLICATION, false)) { + ariaLabelSections.push(localize('applicationSettingDescriptionAccessible', "Setting value retained when switching profiles")); + } else { + // Add other overrides text + const otherOverridesStart = element.isConfigured ? + localize('alsoConfiguredIn', "Also modified in") : + localize('configuredIn', "Modified in"); + const otherOverridesList = element.overriddenScopeList + .map(scope => getAccessibleScopeDisplayMidSentenceText(scope, languageService)).join(', '); + if (element.overriddenScopeList.length) { + ariaLabelSections.push(`${otherOverridesStart} ${otherOverridesList}`); + } } // Add sync ignored text diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index d6f5f844270..4fa2edb2ff0 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -33,17 +33,16 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, getLanguageTagSettingPlainKey, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorBackground, editorErrorForeground, editorInfoForeground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { editorBackground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { getIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge'; import { ITOCEntry } from 'vs/workbench/contrib/preferences/browser/settingsLayout'; import { inspectSetting, ISettingsEditorViewState, settingKeyToDisplayFormat, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeNewExtensionsElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { ExcludeSettingWidget, ISettingListChangeEvent, IListDataItem, ListSettingWidget, ObjectSettingDropdownWidget, IObjectDataItem, IObjectEnumOption, ObjectValue, IObjectValueSuggester, IObjectKeySuggester, ObjectSettingCheckboxWidget } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; -import { LANGUAGE_SETTING_TAG, POLICY_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; +import { LANGUAGE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISetting, ISettingsGroup, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { getDefaultIgnoredSettings, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; @@ -64,6 +63,7 @@ import { focusedRowBackground, focusedRowBorder, rowHoverBackground, settingsHea import { getIndicatorsLabelAriaLabel, ISettingOverrideClickEvent, SettingsTreeIndicatorsLabel } from 'vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; const $ = DOM.$; @@ -592,7 +592,6 @@ interface ISettingItemTemplate extends IDisposableTemplate { containerElement: HTMLElement; categoryElement: HTMLElement; labelElement: SimpleIconLabel; - policyWarningElement: HTMLElement; descriptionElement: HTMLElement; controlElement: HTMLElement; deprecationWarningElement: HTMLElement; @@ -648,7 +647,6 @@ interface IGroupTitleTemplate extends IDisposableTemplate { parent: HTMLElement; } -const SETTINGS_UNTRUSTED_TEMPLATE_ID = 'settings.untrusted.template'; const SETTINGS_TEXT_TEMPLATE_ID = 'settings.text.template'; const SETTINGS_MULTILINE_TEXT_TEMPLATE_ID = 'settings.multilineText.template'; const SETTINGS_NUMBER_TEMPLATE_ID = 'settings.number.template'; @@ -801,8 +799,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre const deprecationWarningElement = DOM.append(container, $('.setting-item-deprecation-message')); - const policyWarningElement = this.renderPolicyLabel(container, toDispose); - const toolbarContainer = DOM.append(container, $('.setting-toolbar-container')); const toolbar = this.renderSettingToolbar(toolbarContainer); @@ -813,7 +809,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre containerElement: container, categoryElement, labelElement, - policyWarningElement, descriptionElement, controlElement, deprecationWarningElement, @@ -848,33 +843,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre }); } - protected renderPolicyLabel(container: HTMLElement, toDispose: DisposableStore): HTMLElement { - const policyWarningElement = DOM.append(container, $('.setting-item-policy-description')); - const policyIcon = DOM.append(policyWarningElement, $('span.codicon.codicon-lock')); - toDispose.add(attachStylerCallback(this._themeService, { editorInfoForeground }, colors => { - policyIcon.style.setProperty('--organization-policy-icon-color', colors.editorInfoForeground?.toString() || ''); - })); - const element = DOM.append(policyWarningElement, $('span')); - element.textContent = localize('policyLabel', "This setting is managed by your organization."); - const viewPolicyLabel = localize('viewPolicySettings', "View policy settings"); - const linkElement: HTMLAnchorElement = DOM.append(policyWarningElement, $('a')); - linkElement.textContent = viewPolicyLabel; - linkElement.setAttribute('tabindex', '0'); - linkElement.href = '#'; - toDispose.add(DOM.addStandardDisposableListener(linkElement, DOM.EventType.CLICK, (e: MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this._onApplyFilter.fire(`@${POLICY_SETTING_TAG}`); - })); - toDispose.add(DOM.addStandardDisposableListener(linkElement, DOM.EventType.KEY_DOWN, (e: IKeyboardEvent) => { - if (e.equals(KeyCode.Enter) || e.equals(KeyCode.Space)) { - e.stopPropagation(); - this._onApplyFilter.fire(`@${POLICY_SETTING_TAG}`); - } - })); - return policyWarningElement; - } - protected renderSettingToolbar(container: HTMLElement): ToolBar { const toggleMenuKeybinding = this._keybindingService.lookupKeybinding(SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU); let toggleMenuTitle = localize('settingsContextMenuTitle', "More Actions... "); @@ -919,7 +887,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre template.descriptionElement.innerText = element.description; } - template.indicatorsLabel.updateScopeOverrides(element, template.elementDisposables, this._onDidClickOverrideElement); + template.indicatorsLabel.updateScopeOverrides(element, template.elementDisposables, this._onDidClickOverrideElement, this._onApplyFilter); const onChange = (value: any) => this._onDidChangeSetting.fire({ key: element.setting.key, @@ -940,14 +908,13 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre this.renderValue(element, template, onChange); + template.indicatorsLabel.updateWorkspaceTrust(element); template.indicatorsLabel.updateSyncIgnored(element, this.ignoredSettings); template.indicatorsLabel.updateDefaultOverrideIndicator(element); template.elementDisposables.add(this.onDidChangeIgnoredSettings(() => { template.indicatorsLabel.updateSyncIgnored(element, this.ignoredSettings); })); - template.policyWarningElement.hidden = !element.hasPolicyValue; - this.updateSettingTabbable(element, template); template.elementDisposables.add(element.onDidChangeTabbable(() => { this.updateSettingTabbable(element, template); @@ -1573,7 +1540,6 @@ abstract class AbstractSettingTextRenderer extends AbstractSettingRenderer imple template.onChange = undefined; template.inputBox.value = dataElement.value; template.inputBox.setAriaLabel(dataElement.setting.key); - template.inputBox.inputElement.disabled = !!dataElement.hasPolicyValue; template.onChange = value => { if (!renderValidations(dataElement, template, false)) { onChange(value); @@ -1739,10 +1705,6 @@ export class SettingEnumRenderer extends AbstractSettingRenderer implements ITre } }; - if (template.selectElement) { - template.selectElement.disabled = !!dataElement.hasPolicyValue; - } - template.enumDescriptionElement.innerText = ''; } } @@ -1794,7 +1756,6 @@ export class SettingNumberRenderer extends AbstractSettingRenderer implements IT template.onChange = undefined; template.inputBox.value = dataElement.value; template.inputBox.setAriaLabel(dataElement.setting.key); - template.inputBox.setEnabled(!dataElement.hasPolicyValue); template.onChange = value => { if (!renderValidations(dataElement, template, false)) { onChange(nullNumParseFn(value)); @@ -1856,8 +1817,6 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre const toolbar = this.renderSettingToolbar(toolbarContainer); toDispose.add(toolbar); - const policyWarningElement = this.renderPolicyLabel(container, toDispose); - const template: ISettingBoolItemTemplate = { toDispose, elementDisposables: toDispose.add(new DisposableStore()), @@ -1867,7 +1826,6 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre labelElement, controlElement, checkbox, - policyWarningElement, descriptionElement, deprecationWarningElement, indicatorsLabel, @@ -1892,57 +1850,10 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre template.onChange = undefined; template.checkbox.checked = dataElement.value; template.checkbox.setTitle(dataElement.setting.key); - if (dataElement.hasPolicyValue) { - template.checkbox.disable(); - } else { - template.checkbox.enable(); - } template.onChange = onChange; } } -export class SettingUntrustedRenderer extends AbstractSettingRenderer implements ITreeRenderer { - templateId = SETTINGS_UNTRUSTED_TEMPLATE_ID; - - renderTemplate(container: HTMLElement): ISettingItemTemplate { - const template = this.renderCommonTemplate(null, container, 'untrusted'); - - const manageWorkspaceTrustLabel = localize('manageWorkspaceTrust', "Manage Workspace Trust"); - const trustLabelElement = $('.setting-item-trust-description'); - const untrustedWorkspaceIcon = DOM.append(trustLabelElement, $('span.codicon.codicon-workspace-untrusted')); - template.toDispose.add(attachStylerCallback(this._themeService, { editorErrorForeground }, colors => { - untrustedWorkspaceIcon.style.setProperty('--workspace-trust-state-untrusted-color', colors.editorErrorForeground?.toString() || ''); - })); - const element = DOM.append(trustLabelElement, $('span')); - element.textContent = localize('trustLabel', "This setting can only be applied in a trusted workspace"); - const linkElement: HTMLAnchorElement = DOM.append(trustLabelElement, $('a')); - linkElement.textContent = manageWorkspaceTrustLabel; - linkElement.setAttribute('tabindex', '0'); - linkElement.href = '#'; - template.toDispose.add(DOM.addStandardDisposableListener(linkElement, DOM.EventType.CLICK, (e: MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this._commandService.executeCommand('workbench.trust.manage'); - })); - template.toDispose.add(DOM.addStandardDisposableListener(linkElement, DOM.EventType.KEY_DOWN, (e: IKeyboardEvent) => { - if (e.equals(KeyCode.Enter) || e.equals(KeyCode.Space)) { - this._commandService.executeCommand('workbench.trust.manage'); - e.stopPropagation(); - } - })); - - template.containerElement.insertBefore(trustLabelElement, template.descriptionElement); - - return template; - } - - renderElement(element: ITreeNode, index: number, templateData: ISettingItemTemplate): void { - super.renderSettingElement(element, index, templateData); - } - - protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingComplexItemTemplate, onChange: (value: string) => void): void { } -} - export class SettingTreeRenderers { readonly onDidClickOverrideElement: Event; @@ -2000,7 +1911,6 @@ export class SettingTreeRenderers { this._instantiationService.createInstance(SettingEnumRenderer, this.settingActions, actionFactory), this._instantiationService.createInstance(SettingObjectRenderer, this.settingActions, actionFactory), this._instantiationService.createInstance(SettingBoolObjectRenderer, this.settingActions, actionFactory), - this._instantiationService.createInstance(SettingUntrustedRenderer, this.settingActions, actionFactory), ]; this.onDidClickOverrideElement = Event.any(...settingRenderers.map(r => r.onDidClickOverrideElement)); @@ -2211,11 +2121,6 @@ class SettingsTreeDelegate extends CachedListVirtualDelegate extends ObjectTreeModel { } class SettingsTreeAccessibilityProvider implements IListAccessibilityProvider { - constructor(private readonly configurationService: IConfigurationService, private readonly languageService: ILanguageService) { + constructor(private readonly configurationService: IConfigurationService, private readonly languageService: ILanguageService, private readonly userDataProfilesService: IUserDataProfilesService) { } getAriaLabel(element: SettingsTreeElement) { @@ -2311,7 +2216,7 @@ class SettingsTreeAccessibilityProvider implements IListAccessibilityProvider { @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService, - @ILanguageService languageService: ILanguageService + @ILanguageService languageService: ILanguageService, + @IUserDataProfilesService userDataProfilesService: IUserDataProfilesService ) { super('SettingsTree', container, new SettingsTreeDelegate(), @@ -2356,7 +2262,7 @@ export class SettingsTree extends WorkbenchObjectTree { return e.id; } }, - accessibilityProvider: new SettingsTreeAccessibilityProvider(configurationService, languageService), + accessibilityProvider: new SettingsTreeAccessibilityProvider(configurationService, languageService, userDataProfilesService), styleController: id => new DefaultStyleController(DOM.createStyleSheet(container), id), filter: instantiationService.createInstance(SettingsTreeFilter, viewState), smoothScrolling: configurationService.getValue('workbench.list.smoothScrolling'), diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index a9ac3c6746d..308e79c7c31 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -529,7 +529,7 @@ export class SettingsTreeModel { } private updateRequireTrustedTargetElements(): void { - this.updateSettings(arrays.flatten([...this._treeElementsBySettingName.values()]).filter(s => s.isUntrusted)); + this.updateSettings([...this._treeElementsBySettingName.values()].flat().filter(s => s.isUntrusted)); } private getTargetToInspect(settingScope: ConfigurationScope | undefined): SettingsTarget { @@ -541,11 +541,11 @@ export class SettingsTreeModel { } private updateSettings(settings: SettingsTreeSettingElement[]): void { - settings.forEach(element => { + for (const element of settings) { const target = this.getTargetToInspect(element.setting.scope); const inspectResult = inspectSetting(element.setting.key, target, this._viewState.languageFilter, this._configurationService); element.update(inspectResult, this._isWorkspaceTrusted); - }); + } } private createSettingsTreeGroupElement(tocEntry: ITOCEntry, parent?: SettingsTreeGroupElement): SettingsTreeGroupElement { @@ -612,19 +612,6 @@ export function inspectSetting(key: string, target: SettingsTarget, languageFilt target === ConfigurationTarget.WORKSPACE ? 'workspace' : 'workspaceFolder'; let isConfigured = typeof inspected[targetSelector] !== 'undefined'; - if (!isConfigured) { - if (target === ConfigurationTarget.APPLICATION) { - isConfigured = !!configurationService.restrictedSettings.application?.includes(key); - } else if (target === ConfigurationTarget.USER_LOCAL) { - isConfigured = !!configurationService.restrictedSettings.userLocal?.includes(key); - } else if (target === ConfigurationTarget.USER_REMOTE) { - isConfigured = !!configurationService.restrictedSettings.userRemote?.includes(key); - } else if (target === ConfigurationTarget.WORKSPACE) { - isConfigured = !!configurationService.restrictedSettings.workspace?.includes(key); - } else if (target instanceof URI) { - isConfigured = !!configurationService.restrictedSettings.workspaceFolder?.get(target)?.includes(key); - } - } const overrideIdentifiers = inspected.overrideIdentifiers; const inspectedLanguageOverrides = new Map>(); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index 6fbc0225b97..eab8dede672 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -1184,6 +1184,25 @@ suite('WorkspaceConfigurationService - Folder', () => { }); })); + test('inspect restricted settings after change', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + testObject.updateWorkspaceTrust(false); + await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "userRestrictedValue" }')); + await testObject.reloadConfiguration(); + + const promise = Event.toPromise(testObject.onDidChangeConfiguration); + await fileService.writeFile(joinPath(workspaceService.getWorkspace().folders[0].uri, '.vscode', 'settings.json'), VSBuffer.fromString('{ "configurationService.folder.restrictedSetting": "workspaceRestrictedValue" }')); + const event = await promise; + + const actual = testObject.inspect('configurationService.folder.restrictedSetting'); + assert.strictEqual(actual.defaultValue, 'isSet'); + assert.strictEqual(actual.application, undefined); + assert.strictEqual(actual.userValue, 'userRestrictedValue'); + assert.strictEqual(actual.workspaceValue, 'workspaceRestrictedValue'); + assert.strictEqual(actual.workspaceFolderValue, undefined); + assert.strictEqual(actual.value, 'userRestrictedValue'); + assert.strictEqual(event.affectsConfiguration('configurationService.folder.restrictedSetting'), true); + })); + test('keys', () => runWithFakedTimers({ useFakeTimers: true }, async () => { let actual = testObject.keys(); assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1); @@ -2096,6 +2115,38 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.strictEqual(actual.value, 'workspaceFolderRestrictedValue'); })); + test('inspect restricted settings after change', () => runWithFakedTimers({ useFakeTimers: true }, async () => { + testObject.updateWorkspaceTrust(false); + await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.workspace.testRestrictedSetting1": "userRestrictedValue" }')); + await testObject.reloadConfiguration(); + + let promise = Event.toPromise(testObject.onDidChangeConfiguration); + await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['settings'], value: { 'configurationService.workspace.testRestrictedSetting1': 'workspaceRestrictedValue' } }], true); + let event = await promise; + + let actual = testObject.inspect('configurationService.workspace.testRestrictedSetting1', { resource: workspaceContextService.getWorkspace().folders[0].uri }); + assert.strictEqual(actual.defaultValue, 'isSet'); + assert.strictEqual(actual.application, undefined); + assert.strictEqual(actual.userValue, 'userRestrictedValue'); + assert.strictEqual(actual.workspaceValue, 'workspaceRestrictedValue'); + assert.strictEqual(actual.workspaceFolderValue, undefined); + assert.strictEqual(actual.value, 'userRestrictedValue'); + assert.strictEqual(event.affectsConfiguration('configurationService.workspace.testRestrictedSetting1'), true); + + promise = Event.toPromise(testObject.onDidChangeConfiguration); + await fileService.writeFile(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json'), VSBuffer.fromString('{ "configurationService.workspace.testRestrictedSetting1": "workspaceFolderRestrictedValue" }')); + event = await promise; + + actual = testObject.inspect('configurationService.workspace.testRestrictedSetting1', { resource: workspaceContextService.getWorkspace().folders[0].uri }); + assert.strictEqual(actual.defaultValue, 'isSet'); + assert.strictEqual(actual.application, undefined); + assert.strictEqual(actual.userValue, 'userRestrictedValue'); + assert.strictEqual(actual.workspaceValue, 'workspaceRestrictedValue'); + assert.strictEqual(actual.workspaceFolderValue, 'workspaceFolderRestrictedValue'); + assert.strictEqual(actual.value, 'userRestrictedValue'); + assert.strictEqual(event.affectsConfiguration('configurationService.workspace.testRestrictedSetting1'), true); + })); + test('get launch configuration', () => runWithFakedTimers({ useFakeTimers: true }, async () => { const expectedLaunchConfiguration = { 'version': '0.1.0', From 7daf9c77efae69bd1729a3e51ff9c264decde8f9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 14 Oct 2022 20:38:16 +0200 Subject: [PATCH 596/599] make access to inspect props delayed (#163679) --- .../common/configurationModels.ts | 215 +++++++++++++++--- .../api/common/extHostConfiguration.ts | 20 +- 2 files changed, 189 insertions(+), 46 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 167cb634f1c..469bcf54e1c 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -19,6 +19,12 @@ import { FileOperation, IFileService } from 'vs/platform/files/common/files'; import { Registry } from 'vs/platform/registry/common/platform'; import { Workspace } from 'vs/platform/workspace/common/workspace'; +export interface IInspectValue { + value?: V; + override?: V; + merged?: V; +} + export class ConfigurationModel implements IConfigurationModel { private frozen: boolean = false; @@ -77,7 +83,7 @@ export class ConfigurationModel implements IConfigurationModel { return section ? getConfigurationValue(this.contents, section) : this.contents; } - inspect(section: string | undefined, overrideIdentifier?: string | null): { value?: V; override?: V; merged?: V } { + inspect(section: string | undefined, overrideIdentifier?: string | null): IInspectValue { const value = this.rawConfiguration.getValue(section); const override = overrideIdentifier ? this.rawConfiguration.getOverrideValue(section, overrideIdentifier) : undefined; const merged = overrideIdentifier ? this.rawConfiguration.override(overrideIdentifier).getValue(section) : value; @@ -483,6 +489,162 @@ export class UserSettings extends Disposable { } } +class ConfigurationInspectValue implements IConfigurationValue { + + constructor( + private readonly key: string, + private readonly overrides: IConfigurationOverrides, + readonly value: V | undefined, + readonly overrideIdentifiers: string[] | undefined, + private readonly defaultConfiguration: ConfigurationModel, + private readonly policyConfiguration: ConfigurationModel | undefined, + private readonly applicationConfiguration: ConfigurationModel | undefined, + private readonly userConfiguration: ConfigurationModel, + private readonly localUserConfiguration: ConfigurationModel, + private readonly remoteUserConfiguration: ConfigurationModel, + private readonly workspaceConfiguration: ConfigurationModel | undefined, + private readonly folderConfigurationModel: ConfigurationModel | undefined, + private readonly memoryInspectValue: IInspectValue, + ) { + } + + private _defaultInspectValue: IInspectValue | undefined; + private get defaultInspectValue(): IInspectValue { + if (!this._defaultInspectValue) { + this._defaultInspectValue = this.defaultConfiguration.inspect(this.key, this.overrides.overrideIdentifier); + } + return this._defaultInspectValue; + } + + get defaultValue(): V | undefined { + return this.defaultInspectValue.merged; + } + + get default(): { value?: V; override?: V } | undefined { + return this.defaultInspectValue.value !== undefined || this.defaultInspectValue.override !== undefined ? { value: this.defaultInspectValue.value, override: this.defaultInspectValue.override } : undefined; + } + + private _policyInspectValue: IInspectValue | undefined | null; + private get policyInspectValue(): IInspectValue | null { + if (this._policyInspectValue === undefined) { + this._policyInspectValue = this.policyConfiguration ? this.policyConfiguration.inspect(this.key) : null; + } + return this._policyInspectValue; + } + + get policyValue(): V | undefined { + return this.policyInspectValue?.merged; + } + + get policy(): { value?: V; override?: V } | undefined { + return this.policyInspectValue?.value !== undefined ? { value: this.policyInspectValue.value } : undefined; + } + + private _applicationInspectValue: IInspectValue | undefined | null; + private get applicationInspectValue(): IInspectValue | null { + if (this._applicationInspectValue === undefined) { + this._applicationInspectValue = this.applicationConfiguration ? this.applicationConfiguration.inspect(this.key) : null; + } + return this._applicationInspectValue; + } + + get applicationValue(): V | undefined { + return this.applicationInspectValue?.merged; + } + + get application(): { value?: V; override?: V } | undefined { + return this.applicationInspectValue?.value !== undefined || this.applicationInspectValue?.override !== undefined ? { value: this.applicationInspectValue.value, override: this.applicationInspectValue.override } : undefined; + } + + private _userInspectValue: IInspectValue | undefined; + private get userInspectValue(): IInspectValue { + if (!this._userInspectValue) { + this._userInspectValue = this.userConfiguration.inspect(this.key, this.overrides.overrideIdentifier); + } + return this._userInspectValue; + } + + get userValue(): V | undefined { + return this.userInspectValue.merged; + } + + get user(): { value?: V; override?: V } | undefined { + return this.userInspectValue.value !== undefined || this.userInspectValue.override !== undefined ? { value: this.userInspectValue.value, override: this.userInspectValue.override } : undefined; + } + + private _userLocalInspectValue: IInspectValue | undefined; + private get userLocalInspectValue(): IInspectValue { + if (!this._userLocalInspectValue) { + this._userLocalInspectValue = this.localUserConfiguration.inspect(this.key, this.overrides.overrideIdentifier); + } + return this._userLocalInspectValue; + } + + get userLocalValue(): V | undefined { + return this.userLocalInspectValue.merged; + } + + get userLocal(): { value?: V; override?: V } | undefined { + return this.userLocalInspectValue.value !== undefined || this.userLocalInspectValue.override !== undefined ? { value: this.userLocalInspectValue.value, override: this.userLocalInspectValue.override } : undefined; + } + + private _userRemoteInspectValue: IInspectValue | undefined; + private get userRemoteInspectValue(): IInspectValue { + if (!this._userRemoteInspectValue) { + this._userRemoteInspectValue = this.remoteUserConfiguration.inspect(this.key, this.overrides.overrideIdentifier); + } + return this._userRemoteInspectValue; + } + + get userRemoteValue(): V | undefined { + return this.userRemoteInspectValue.merged; + } + + get userRemote(): { value?: V; override?: V } | undefined { + return this.userRemoteInspectValue.value !== undefined || this.userRemoteInspectValue.override !== undefined ? { value: this.userRemoteInspectValue.value, override: this.userRemoteInspectValue.override } : undefined; + } + + private _workspaceInspectValue: IInspectValue | undefined | null; + private get workspaceInspectValue(): IInspectValue | null { + if (this._workspaceInspectValue === undefined) { + this._workspaceInspectValue = this.workspaceConfiguration ? this.workspaceConfiguration.inspect(this.key, this.overrides.overrideIdentifier) : null; + } + return this._workspaceInspectValue; + } + + get workspaceValue(): V | undefined { + return this.workspaceInspectValue?.merged; + } + + get workspace(): { value?: V; override?: V } | undefined { + return this.workspaceInspectValue?.value !== undefined || this.workspaceInspectValue?.override !== undefined ? { value: this.workspaceInspectValue.value, override: this.workspaceInspectValue.override } : undefined; + } + + private _workspaceFolderInspectValue: IInspectValue | undefined | null; + private get workspaceFolderInspectValue(): IInspectValue | null { + if (this._workspaceFolderInspectValue === undefined) { + this._workspaceFolderInspectValue = this.folderConfigurationModel ? this.folderConfigurationModel.inspect(this.key, this.overrides.overrideIdentifier) : null; + } + return this._workspaceFolderInspectValue; + } + + get workspaceFolderValue(): V | undefined { + return this.workspaceFolderInspectValue?.merged; + } + + get workspaceFolder(): { value?: V; override?: V } | undefined { + return this.workspaceFolderInspectValue?.value !== undefined || this.workspaceFolderInspectValue?.override !== undefined ? { value: this.workspaceFolderInspectValue.value, override: this.workspaceFolderInspectValue.override } : undefined; + } + + get memoryValue(): V | undefined { + return this.memoryInspectValue.merged; + } + + get memory(): { value?: V; override?: V } | undefined { + return this.memoryInspectValue.value !== undefined || this.memoryInspectValue.override !== undefined ? { value: this.memoryInspectValue.value, override: this.memoryInspectValue.override } : undefined; + } + +} export class Configuration { @@ -532,45 +694,26 @@ export class Configuration { inspect(key: string, overrides: IConfigurationOverrides, workspace: Workspace | undefined): IConfigurationValue { const consolidateConfigurationModel = this.getConsolidatedConfigurationModel(key, overrides, workspace); + const overrideIdentifiers: string[] = arrays.distinct(consolidateConfigurationModel.overrides.map(override => override.identifiers).flat()).filter(overrideIdentifier => consolidateConfigurationModel.getOverrideValue(key, overrideIdentifier) !== undefined); const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace); const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; - const defaultInspectValue = this._defaultConfiguration.inspect(key, overrides.overrideIdentifier); - const policyInspectValue = this._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration.freeze().inspect(key); - const applicationInspectValue = this.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration.freeze().inspect(key); - const userInspectValue = this.userConfiguration.freeze().inspect(key, overrides.overrideIdentifier); - const userLocalInspectValue = this.localUserConfiguration.freeze().inspect(key, overrides.overrideIdentifier); - const userRemoteInspectValue = this.remoteUserConfiguration.freeze().inspect(key, overrides.overrideIdentifier); - const workspaceInspectValue = workspace ? this._workspaceConfiguration.freeze().inspect(key, overrides.overrideIdentifier) : undefined; //Check on workspace exists or not because _workspaceConfiguration is never null - const workspaceFolderInspectValue = folderConfigurationModel ? folderConfigurationModel.freeze().inspect(key, overrides.overrideIdentifier) : undefined; - const memoryInspectValue = memoryConfigurationModel.inspect(key, overrides.overrideIdentifier); - const value = consolidateConfigurationModel.getValue(key); - const overrideIdentifiers: string[] = arrays.distinct(consolidateConfigurationModel.overrides.map(override => override.identifiers).flat()).filter(overrideIdentifier => consolidateConfigurationModel.getOverrideValue(key, overrideIdentifier) !== undefined); + return new ConfigurationInspectValue( + key, + overrides, + consolidateConfigurationModel.getValue(key), + overrideIdentifiers.length ? overrideIdentifiers : undefined, + this._defaultConfiguration, + this._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration.freeze(), + this.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration.freeze(), + this.userConfiguration.freeze(), + this.localUserConfiguration.freeze(), + this.remoteUserConfiguration.freeze(), + workspace ? this._workspaceConfiguration.freeze() : undefined, + folderConfigurationModel ? folderConfigurationModel.freeze() : undefined, + memoryConfigurationModel.inspect(key, overrides.overrideIdentifier) + ); - return { - defaultValue: defaultInspectValue ? defaultInspectValue.merged : undefined, - policyValue: policyInspectValue ? policyInspectValue.merged : undefined, - applicationValue: applicationInspectValue ? applicationInspectValue.merged : undefined, - userValue: userInspectValue ? userInspectValue.merged : undefined, - userLocalValue: userLocalInspectValue ? userLocalInspectValue.merged : undefined, - userRemoteValue: userRemoteInspectValue ? userRemoteInspectValue.merged : undefined, - workspaceValue: workspaceInspectValue ? workspaceInspectValue.merged : undefined, - workspaceFolderValue: workspaceFolderInspectValue ? workspaceFolderInspectValue.merged : undefined, - memoryValue: memoryInspectValue ? memoryInspectValue.merged : undefined, - value, - - default: defaultInspectValue.value !== undefined || defaultInspectValue.override !== undefined ? { value: defaultInspectValue.value, override: defaultInspectValue.override } : undefined, - policy: policyInspectValue?.value !== undefined ? { value: policyInspectValue.value } : undefined, - application: applicationInspectValue?.value !== undefined || applicationInspectValue?.override !== undefined ? { value: applicationInspectValue.value, override: applicationInspectValue.override } : undefined, - user: userInspectValue.value !== undefined || userInspectValue.override !== undefined ? { value: userInspectValue.value, override: userInspectValue.override } : undefined, - userLocal: userLocalInspectValue.value !== undefined || userLocalInspectValue.override !== undefined ? { value: userLocalInspectValue.value, override: userLocalInspectValue.override } : undefined, - userRemote: userRemoteInspectValue.value !== undefined || userRemoteInspectValue.override !== undefined ? { value: userRemoteInspectValue.value, override: userRemoteInspectValue.override } : undefined, - workspace: workspaceInspectValue?.value !== undefined || workspaceInspectValue?.override !== undefined ? { value: workspaceInspectValue.value, override: workspaceInspectValue.override } : undefined, - workspaceFolder: workspaceFolderInspectValue?.value !== undefined || workspaceFolderInspectValue?.override !== undefined ? { value: workspaceFolderInspectValue.value, override: workspaceFolderInspectValue.override } : undefined, - memory: memoryInspectValue.value !== undefined || memoryInspectValue.override !== undefined ? { value: memoryInspectValue.value, override: memoryInspectValue.override } : undefined, - - overrideIdentifiers: overrideIdentifiers.length ? overrideIdentifiers : undefined - }; } keys(workspace: Workspace | undefined): { diff --git a/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts index 2e9c5b7ada8..68f363f19f0 100644 --- a/src/vs/workbench/api/common/extHostConfiguration.ts +++ b/src/vs/workbench/api/common/extHostConfiguration.ts @@ -251,22 +251,22 @@ export class ExtHostConfigProvider { }, inspect: (key: string): ConfigurationInspect | undefined => { key = section ? `${section}.${key}` : key; - const config = deepClone(this._configuration.inspect(key, overrides, this._extHostWorkspace.workspace)); + const config = this._configuration.inspect(key, overrides, this._extHostWorkspace.workspace); if (config) { return { key, - defaultValue: config.policy?.value ?? config.default?.value, - globalValue: config.user?.value ?? config.application?.value, - workspaceValue: config.workspace?.value, - workspaceFolderValue: config.workspaceFolder?.value, + defaultValue: deepClone(config.policy?.value ?? config.default?.value), + globalValue: deepClone(config.user?.value ?? config.application?.value), + workspaceValue: deepClone(config.workspace?.value), + workspaceFolderValue: deepClone(config.workspaceFolder?.value), - defaultLanguageValue: config.default?.override, - globalLanguageValue: config.user?.override ?? config.application?.override, - workspaceLanguageValue: config.workspace?.override, - workspaceFolderLanguageValue: config.workspaceFolder?.override, + defaultLanguageValue: deepClone(config.default?.override), + globalLanguageValue: deepClone(config.user?.override ?? config.application?.override), + workspaceLanguageValue: deepClone(config.workspace?.override), + workspaceFolderLanguageValue: deepClone(config.workspaceFolder?.override), - languageIds: config.overrideIdentifiers + languageIds: deepClone(config.overrideIdentifiers) }; } return undefined; From 3b255af0cb7550d9abcc0249432546c8970f8b83 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 11:46:24 -0700 Subject: [PATCH 597/599] Pick up latest vscode-markdown-languageservice (#163681) --- extensions/markdown-language-features/server/package.json | 2 +- extensions/markdown-language-features/server/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json index dd812e21af6..a5322a81c4a 100644 --- a/extensions/markdown-language-features/server/package.json +++ b/extensions/markdown-language-features/server/package.json @@ -13,7 +13,7 @@ "vscode-languageserver": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.5", "vscode-languageserver-types": "^3.17.1", - "vscode-markdown-languageservice": "^0.2.0-alpha.1", + "vscode-markdown-languageservice": "^0.2.0-alpha.2", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.3" }, diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index df3fe7b2b5b..f9067270e01 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -42,10 +42,10 @@ vscode-languageserver@^8.0.2: dependencies: vscode-languageserver-protocol "3.17.2" -vscode-markdown-languageservice@^0.2.0-alpha.1: - version "0.2.0-alpha.1" - resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.2.0-alpha.1.tgz#ab4b75ef4584551b8531b7b9cee3f9c64d5bd344" - integrity sha512-doJBc1Jx5xGEjsagNz3hOkDzAWDyTiJ7mBYsxkgDz0/49rCxjNdXBlfMioeoSSMVmyVUvY1hlAX8Q/I9jyUc+Q== +vscode-markdown-languageservice@^0.2.0-alpha.2: + version "0.2.0-alpha.2" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.2.0-alpha.2.tgz#ed08bc3f7f19c5fb0283547a7855542224ce377c" + integrity sha512-2/Mp/b63ohC8k0h1boWohf2G6SwLb3IA+c3UcqPs4FdaRpGqpf2wVXaT5aQ5qVRGpqvCwfyyyr2YEdqwuQc5KA== dependencies: picomatch "^2.3.1" vscode-languageserver-textdocument "^1.0.5" From 0a6a5912a5ba6d444250c26659dfe9b543fdfc8e Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 14 Oct 2022 13:22:54 -0700 Subject: [PATCH 598/599] Use editor scope contextkeyservice for fetching kernel source commands (#163693) --- .../editorStatusBar/editorStatusBar.ts | 2 +- .../notebook/browser/notebookBrowser.ts | 2 + .../notebook/browser/notebookEditorWidget.ts | 2 +- .../services/notebookExecutionServiceImpl.ts | 9 +- .../services/notebookKernelServiceImpl.ts | 104 +++++++++++------- .../notebookEditorWidgetContextKeys.ts | 2 +- .../viewParts/notebookKernelActionViewItem.ts | 7 +- .../common/notebookExecutionService.ts | 3 +- .../notebook/common/notebookKernelService.ts | 11 +- 9 files changed, 87 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts index 78a1fba167d..6e19f81fde4 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts @@ -209,7 +209,7 @@ registerAction2(class extends Action2 { }); } - const sourceActions = notebookKernelService.getSourceActions(); + const sourceActions = notebookKernelService.getSourceActions(notebook, editor.scopedContextKeyService); if (sourceActions.length) { quickPickItems.push({ type: 'separator', diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index fc1315f3426..3ccfcdb46cf 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -27,6 +27,7 @@ import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOp import { cellRangesToIndexes, ICellRange, reduceCellRanges } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { IWebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; //#region Shared commands export const EXPAND_CELL_INPUT_COMMAND_ID = 'notebook.cell.expandCellInput'; @@ -428,6 +429,7 @@ export interface INotebookEditor { readonly isDisposed: boolean; readonly activeKernel: INotebookKernel | undefined; readonly scrollTop: number; + readonly scopedContextKeyService: IContextKeyService; //#endregion getLength(): number; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index e625d88cf97..1c5bbf4861c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2060,7 +2060,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD if (!cells) { cells = this.viewModel.viewCells; } - return this.notebookExecutionService.executeNotebookCells(this.textModel, Array.from(cells).map(c => c.model)); + return this.notebookExecutionService.executeNotebookCells(this.textModel, Array.from(cells).map(c => c.model), this.scopedContextKeyService); } //#endregion diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionServiceImpl.ts index e2d7a240ced..ef959384ee2 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookExecutionServiceImpl.ts @@ -15,6 +15,7 @@ import { CellKind, INotebookTextModel, NotebookCellExecutionState } from 'vs/wor import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { INotebookCellExecution, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class NotebookExecutionService implements INotebookExecutionService, IDisposable { declare _serviceBrand: undefined; @@ -29,7 +30,7 @@ export class NotebookExecutionService implements INotebookExecutionService, IDis ) { } - async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable): Promise { + async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable, contextKeyService: IContextKeyService): Promise { const cellsArr = Array.from(cells); this._logService.debug(`NotebookExecutionService#executeNotebookCells ${JSON.stringify(cellsArr.map(c => c.handle))}`); const message = nls.localize('notebookRunTrust', "Executing a notebook cell will run code from this workspace."); @@ -50,7 +51,7 @@ export class NotebookExecutionService implements INotebookExecutionService, IDis let kernel = this._notebookKernelService.getSelectedOrSuggestedKernel(notebook); if (!kernel) { - kernel = await this.resolveSourceActions(notebook); + kernel = await this.resolveSourceActions(notebook, contextKeyService); } if (!kernel) { @@ -87,12 +88,12 @@ export class NotebookExecutionService implements INotebookExecutionService, IDis } } - private async resolveSourceActions(notebook: INotebookTextModel) { + private async resolveSourceActions(notebook: INotebookTextModel, contextKeyService: IContextKeyService) { let kernel: INotebookKernel | undefined; const info = this._notebookKernelService.getMatchingKernel(notebook); if (info.all.length === 0) { // no kernel at all - const sourceActions = this._notebookKernelService.getSourceActions(); + const sourceActions = this._notebookKernelService.getSourceActions(notebook, contextKeyService); const primaryActions = sourceActions.filter(action => action.isPrimary); const action = sourceActions.length === 1 ? sourceActions[0] diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts index fac4b35285c..5c3e2e06544 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookKernelServiceImpl.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { INotebookKernel, ISelectedNotebooksChangeEvent, INotebookKernelMatchResult, INotebookKernelService, INotebookTextModelLike, ISourceAction } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; +import { INotebookKernel, ISelectedNotebooksChangeEvent, INotebookKernelMatchResult, INotebookKernelService, INotebookTextModelLike, ISourceAction, INotebookSourceActionChangeEvent } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { LRUCache, ResourceMap } from 'vs/base/common/map'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; @@ -79,6 +79,12 @@ class SourceAction extends Disposable implements ISourceAction { } } +interface IKernelInfoCache { + menu: IMenu; + actions: [ISourceAction, IDisposable][]; + +} + export class NotebookKernelService extends Disposable implements INotebookKernelService { declare _serviceBrand: undefined; @@ -91,15 +97,14 @@ export class NotebookKernelService extends Disposable implements INotebookKernel private readonly _onDidAddKernel = this._register(new Emitter()); private readonly _onDidRemoveKernel = this._register(new Emitter()); private readonly _onDidChangeNotebookAffinity = this._register(new Emitter()); - private readonly _onDidChangeSourceActions = this._register(new Emitter()); - private readonly _sourceMenu: IMenu; - private _sourceActions: [ISourceAction, IDisposable][]; + private readonly _onDidChangeSourceActions = this._register(new Emitter()); + private readonly _kernelSources = new Map(); readonly onDidChangeSelectedNotebooks: Event = this._onDidChangeNotebookKernelBinding.event; readonly onDidAddKernel: Event = this._onDidAddKernel.event; readonly onDidRemoveKernel: Event = this._onDidRemoveKernel.event; readonly onDidChangeNotebookAffinity: Event = this._onDidChangeNotebookAffinity.event; - readonly onDidChangeSourceActions: Event = this._onDidChangeSourceActions.event; + readonly onDidChangeSourceActions: Event = this._onDidChangeSourceActions.event; private static _storageNotebookBinding = 'notebook.controller2NotebookBindings'; @@ -108,7 +113,7 @@ export class NotebookKernelService extends Disposable implements INotebookKernel @INotebookService private readonly _notebookService: INotebookService, @IStorageService private readonly _storageService: IStorageService, @IMenuService readonly _menuService: IMenuService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService readonly _contextKeyService: IContextKeyService ) { super(); @@ -121,10 +126,6 @@ export class NotebookKernelService extends Disposable implements INotebookKernel this.selectKernelForNotebook(undefined, notebook); } })); - this._sourceMenu = this._register(this._menuService.createMenu(MenuId.NotebookKernelSource, contextKeyService)); - this._sourceActions = []; - - this._initSourceActions(); // restore from storage try { @@ -135,34 +136,12 @@ export class NotebookKernelService extends Disposable implements INotebookKernel } } - private _initSourceActions() { - const loadActionsFromMenu = (menu: IMenu) => { - const groups = menu.getActions({ shouldForwardArgs: true }); - const sourceActions: [ISourceAction, IDisposable][] = []; - groups.forEach(group => { - const isPrimary = /^primary/.test(group[0]); - group[1].forEach(action => { - const sourceAction = new SourceAction(action, isPrimary); - const stateChangeListener = sourceAction.onDidChangeState(() => { - this._onDidChangeSourceActions.fire(); - }); - sourceActions.push([sourceAction, stateChangeListener]); - }); - }); - this._sourceActions = sourceActions; - this._onDidChangeSourceActions.fire(); - }; - - this._register(this._sourceMenu.onDidChange(() => { - loadActionsFromMenu(this._sourceMenu); - })); - - loadActionsFromMenu(this._sourceMenu); - } - override dispose() { this._kernels.clear(); - dispose(this._sourceActions.map(a => a[1])); + this._kernelSources.forEach(v => { + v.menu.dispose(); + v.actions.forEach(a => a[1].dispose()); + }); super.dispose(); } @@ -307,11 +286,54 @@ export class NotebookKernelService extends Disposable implements INotebookKernel this._onDidChangeNotebookAffinity.fire(); } - getRunningSourceActions() { - return this._sourceActions.filter(action => action[0].execution).map(action => action[0]); + getRunningSourceActions(notebook: INotebookTextModelLike) { + const id = NotebookTextModelLikeId.str(notebook); + const existingInfo = this._kernelSources.get(id); + if (existingInfo) { + return existingInfo.actions.filter(action => action[0].execution).map(action => action[0]); + } + + return []; } - getSourceActions(): ISourceAction[] { - return this._sourceActions.map(a => a[0]); + getSourceActions(notebook: INotebookTextModelLike, contextKeyService: IContextKeyService | undefined): ISourceAction[] { + contextKeyService = contextKeyService ?? this._contextKeyService; + const id = NotebookTextModelLikeId.str(notebook); + const existingInfo = this._kernelSources.get(id); + + if (existingInfo) { + return existingInfo.actions.map(a => a[0]); + } + + const sourceMenu = this._register(this._menuService.createMenu(MenuId.NotebookKernelSource, contextKeyService)); + const info: IKernelInfoCache = { menu: sourceMenu, actions: [] }; + + const loadActionsFromMenu = (menu: IMenu) => { + const groups = menu.getActions({ shouldForwardArgs: true }); + const sourceActions: [ISourceAction, IDisposable][] = []; + groups.forEach(group => { + const isPrimary = /^primary/.test(group[0]); + group[1].forEach(action => { + const sourceAction = new SourceAction(action, isPrimary); + const stateChangeListener = sourceAction.onDidChangeState(() => { + this._onDidChangeSourceActions.fire({ + notebook: notebook.uri + }); + }); + sourceActions.push([sourceAction, stateChangeListener]); + }); + }); + info.actions = sourceActions; + this._kernelSources.set(id, info); + this._onDidChangeSourceActions.fire({ notebook: notebook.uri }); + }; + + this._register(sourceMenu.onDidChange(() => { + loadActionsFromMenu(sourceMenu); + })); + + loadActionsFromMenu(sourceMenu); + + return info.actions.map(a => a[0]); } } diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts index 7d69d360871..7ee5fba6af6 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts @@ -169,7 +169,7 @@ export class NotebookEditorContextKeys { } const { selected, all } = this._notebookKernelService.getMatchingKernel(this._editor.textModel); - const sourceActions = this._notebookKernelService.getSourceActions(); + const sourceActions = this._notebookKernelService.getSourceActions(this._editor.textModel, this._editor.scopedContextKeyService); this._notebookKernelCount.set(all.length); this._notebookKernelSourceCount.set(sourceActions.length); this._interruptibleKernel.set(selected?.implementsInterrupt ?? false); diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem.ts index c461cd64a72..cf027f3af32 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem.ts @@ -13,6 +13,7 @@ import { INotebookKernel, INotebookKernelMatchResult, INotebookKernelService, IS import { Event } from 'vs/base/common/event'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class NotebooKernelActionViewItem extends ActionViewItem { @@ -20,7 +21,7 @@ export class NotebooKernelActionViewItem extends ActionViewItem { constructor( actualAction: IAction, - private readonly _editor: { onDidChangeModel: Event; textModel: NotebookTextModel | undefined } | INotebookEditor, + private readonly _editor: { onDidChangeModel: Event; textModel: NotebookTextModel | undefined; scopedContextKeyService?: IContextKeyService } | INotebookEditor, @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, ) { super( @@ -59,7 +60,7 @@ export class NotebooKernelActionViewItem extends ActionViewItem { return; } - const runningActions = this._notebookKernelService.getRunningSourceActions(); + const runningActions = this._notebookKernelService.getRunningSourceActions(notebook); if (runningActions.length) { return this._updateActionFromSourceAction(runningActions[0] /** TODO handle multiple actions state */, true); } @@ -82,7 +83,7 @@ export class NotebooKernelActionViewItem extends ActionViewItem { private _updateActionsFromSourceActions() { this._action.enabled = true; - const sourceActions = this._notebookKernelService.getSourceActions(); + const sourceActions = this._editor.textModel ? this._notebookKernelService.getSourceActions(this._editor.textModel, this._editor.scopedContextKeyService) : []; if (sourceActions.length === 1) { // exact one action this._updateActionFromSourceAction(sourceActions[0], false); diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts index 1a3b6ac9a94..b2c18f4f6b1 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { INotebookTextModel, IOutputDto, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -32,7 +33,7 @@ export const INotebookExecutionService = createDecorator): Promise; + executeNotebookCells(notebook: INotebookTextModel, cells: Iterable, contextKeyService: IContextKeyService): Promise; cancelNotebookCells(notebook: INotebookTextModel, cells: Iterable): Promise; cancelNotebookCellHandles(notebook: INotebookTextModel, cells: Iterable): Promise; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookKernelService.ts b/src/vs/workbench/contrib/notebook/common/notebookKernelService.ts index e674058c02b..81cf910e50c 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookKernelService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookKernelService.ts @@ -7,6 +7,7 @@ import { IAction } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -74,6 +75,10 @@ export interface ISourceAction { runAction: () => Promise; } +export interface INotebookSourceActionChangeEvent { + notebook: URI; +} + export interface INotebookTextModelLike { uri: URI; viewType: string } export const INotebookKernelService = createDecorator('INotebookKernelService'); @@ -111,8 +116,8 @@ export interface INotebookKernelService { updateKernelNotebookAffinity(kernel: INotebookKernel, notebook: URI, preference: number | undefined): void; //#region Kernel source actions - readonly onDidChangeSourceActions: Event; - getSourceActions(): ISourceAction[]; - getRunningSourceActions(): ISourceAction[]; + readonly onDidChangeSourceActions: Event; + getSourceActions(notebook: INotebookTextModelLike, contextKeyService: IContextKeyService | undefined): ISourceAction[]; + getRunningSourceActions(notebook: INotebookTextModelLike): ISourceAction[]; //#endregion } From 4c53499e8ab7530ce13ee09d36c115d1c6c91ef9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 14 Oct 2022 13:56:47 -0700 Subject: [PATCH 599/599] Revert "Make returned editor contributions an iterable instead of an array (#163309)" (#163689) This reverts commit 90054ae22fd6d01ef62f0120e17de358f70d9e00. --- src/vs/editor/browser/editorExtensions.ts | 17 ++++++++--------- .../editor/browser/widget/codeEditorWidget.ts | 9 +++++++-- .../editor/browser/widget/diffEditorWidget.ts | 4 ++-- .../browser/view/editors/baseCodeEditorView.ts | 5 ++--- .../browser/view/editors/codeEditorView.ts | 2 +- .../browser/view/editors/inputCodeEditorView.ts | 5 ++--- .../view/editors/resultCodeEditorView.ts | 5 ++--- .../contrib/notebook/browser/notebookBrowser.ts | 4 ++-- .../notebook/browser/notebookEditorWidget.ts | 12 ++++++++---- .../searchEditor/browser/searchEditor.ts | 5 ++--- 10 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 2676bb009b2..7cdfebe3ad7 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -24,7 +24,6 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ILogService } from 'vs/platform/log/common/log'; -import { Iterable } from 'vs/base/common/iterator'; export type ServicesAccessor = InstantiationServicesAccessor; @@ -491,15 +490,15 @@ export namespace EditorExtensionsRegistry { return EditorContributionRegistry.INSTANCE.getEditorActions(); } - export function getEditorContributions(): Iterable { + export function getEditorContributions(): IEditorContributionDescription[] { return EditorContributionRegistry.INSTANCE.getEditorContributions(); } - export function getSomeEditorContributions(ids: string[]): Iterable { - return Iterable.filter(EditorContributionRegistry.INSTANCE.getEditorContributions(), c => ids.indexOf(c.id) >= 0); + export function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] { + return EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0); } - export function getDiffEditorContributions(): Iterable { + export function getDiffEditorContributions(): IDiffEditorContributionDescription[] { return EditorContributionRegistry.INSTANCE.getDiffEditorContributions(); } } @@ -529,16 +528,16 @@ class EditorContributionRegistry { this.editorContributions.push({ id, ctor: ctor as IEditorContributionCtor }); } - public getEditorContributions(): Iterable { - return this.editorContributions; + public getEditorContributions(): IEditorContributionDescription[] { + return this.editorContributions.slice(0); } public registerDiffEditorContribution(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void { this.diffEditorContributions.push({ id, ctor: ctor as IDiffEditorContributionCtor }); } - public getDiffEditorContributions(): Iterable { - return this.diffEditorContributions; + public getDiffEditorContributions(): IDiffEditorContributionDescription[] { + return this.diffEditorContributions.slice(0); } public registerEditorAction(action: EditorAction) { diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index b851a0e6bd6..65ae5f61c9f 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -74,7 +74,7 @@ export interface ICodeEditorWidgetOptions { * Contributions to instantiate. * Defaults to EditorExtensionsRegistry.getEditorContributions(). */ - contributions?: Iterable; + contributions?: IEditorContributionDescription[]; /** * Telemetry data associated with this CodeEditorWidget. @@ -326,7 +326,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._contentWidgets = {}; this._overlayWidgets = {}; - const contributions = codeEditorWidgetOptions.contributions ?? EditorExtensionsRegistry.getEditorContributions(); + let contributions: IEditorContributionDescription[]; + if (Array.isArray(codeEditorWidgetOptions.contributions)) { + contributions = codeEditorWidgetOptions.contributions; + } else { + contributions = EditorExtensionsRegistry.getEditorContributions(); + } for (const desc of contributions) { if (this._contributions.has(desc.id)) { onUnexpectedError(new Error(`Cannot have two contributions with the same id ${desc.id}`)); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index d98a84f5ed6..90af6898315 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -42,7 +42,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { Constants } from 'vs/base/common/uint'; -import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; @@ -368,7 +368,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._options.renderSideBySide); })); - const contributions = EditorExtensionsRegistry.getDiffEditorContributions(); + const contributions: IDiffEditorContributionDescription[] = EditorExtensionsRegistry.getDiffEditorContributions(); for (const desc of contributions) { try { this._register(instantiationService.createInstance(desc.ctor, this)); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts index e318c62d385..2086fc1dcc9 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/baseCodeEditorView.ts @@ -6,7 +6,6 @@ import { h, reset } from 'vs/base/browser/dom'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { BugIndicatingError } from 'vs/base/common/errors'; -import { Iterable } from 'vs/base/common/iterator'; import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; @@ -158,7 +157,7 @@ export class BaseCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): Iterable | undefined { - return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): IEditorContributionDescription[] | undefined { + return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index 4ddab3078e0..4710408ef07 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -108,7 +108,7 @@ export abstract class CodeEditorView extends Disposable { } - protected getEditorContributions(): Iterable | undefined { + protected getEditorContributions(): IEditorContributionDescription[] | undefined { return undefined; } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index 684ec7d9067..9b61b9c9279 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -8,7 +8,6 @@ import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { Toggle } from 'vs/base/browser/ui/toggle/toggle'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { Codicon } from 'vs/base/common/codicons'; -import { Iterable } from 'vs/base/common/iterator'; import { Disposable } from 'vs/base/common/lifecycle'; import { clamp } from 'vs/base/common/numbers'; import { autorun, autorunWithStore, derived, IObservable, ISettableObservable, ITransaction, observableValue, transaction } from 'vs/base/common/observable'; @@ -209,8 +208,8 @@ export class InputCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): Iterable | undefined { - return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): IEditorContributionDescription[] | undefined { + return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts index dccc796b2ca..dd5641d28b5 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -8,7 +8,6 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { CompareResult } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; -import { Iterable } from 'vs/base/common/iterator'; import { toDisposable } from 'vs/base/common/lifecycle'; import { autorun, autorunWithStore, derived, IObservable } from 'vs/base/common/observable'; import { IEditorContributionDescription, EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; @@ -223,7 +222,7 @@ export class ResultCodeEditorView extends CodeEditorView { return result; }); - protected override getEditorContributions(): Iterable | undefined { - return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => c.id !== CodeLensContribution.ID); + protected override getEditorContributions(): IEditorContributionDescription[] | undefined { + return EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeLensContribution.ID); } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 3ccfcdb46cf..95df7696197 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -324,8 +324,8 @@ export interface INotebookEditorContributionDescription { export interface INotebookEditorCreationOptions { readonly isEmbedded?: boolean; readonly isReadOnly?: boolean; - readonly contributions?: Iterable; - readonly cellEditorContributions?: Iterable; + readonly contributions?: INotebookEditorContributionDescription[]; + readonly cellEditorContributions?: IEditorContributionDescription[]; readonly menuIds: { notebookToolbar: MenuId; cellTitleToolbar: MenuId; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 1c5bbf4861c..295e86ea211 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -46,7 +46,7 @@ import { contrastBorder, diffInserted, diffRemoved, editorBackground, errorForeg import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { EDITOR_PANE_BACKGROUND, PANEL_BORDER, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, CellRevealType, IActiveNotebookEditorDelegate, IBaseCellEditorOptions, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IInsetRenderOutput, IModelDecorationsChangeAccessor, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorCreationOptions, INotebookEditorDelegate, INotebookEditorMouseEvent, INotebookEditorOptions, INotebookEditorViewState, INotebookViewCellsUpdateEvent, INotebookWebviewMessage, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFindMatchWithIndex, CellFocusMode, CellLayoutContext, CellRevealType, 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/services/notebookEditorService'; import { notebookDebug } from 'vs/workbench/contrib/notebook/browser/notebookLogger'; @@ -85,14 +85,13 @@ import { NotebookPerfMarks } from 'vs/workbench/contrib/notebook/common/notebook import { BaseCellEditorOptions } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEditorOptions'; import { ILogService } from 'vs/platform/log/common/log'; import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor'; -import { Iterable } from 'vs/base/common/iterator'; const $ = DOM.$; export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOptions { // We inlined the id to avoid loading comment contrib in tests const skipContributions = ['editor.contrib.review', FloatingClickMenu.ID]; - const contributions = Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => skipContributions.indexOf(c.id) === -1); + const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); return { menuIds: { @@ -350,7 +349,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD this._editorEditable.set(!creationOptions.isReadOnly); - const contributions = this.creationOptions.contributions ?? NotebookEditorExtensionsRegistry.getEditorContributions(); + let contributions: INotebookEditorContributionDescription[]; + if (Array.isArray(this.creationOptions.contributions)) { + contributions = this.creationOptions.contributions; + } else { + contributions = NotebookEditorExtensionsRegistry.getEditorContributions(); + } for (const desc of contributions) { let contribution: INotebookEditorContribution | undefined; try { diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts index e1a91b5d71f..54be4156b6e 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts @@ -61,7 +61,6 @@ import { renderSearchMessage } from 'vs/workbench/contrib/search/browser/searchM import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { UnusualLineTerminatorsDetector } from 'vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators'; import { isHighContrast } from 'vs/platform/theme/common/theme'; -import { Iterable } from 'vs/base/common/iterator'; const RESULT_LINE_REGEX = /^(\s+)(\d+)(: | )(\s*)(.*)$/; const FILE_LINE_REGEX = /^(\S.*):$/; @@ -226,9 +225,9 @@ export class SearchEditor extends AbstractTextCodeEditor } } - private _getContributions(): Iterable { + private _getContributions(): IEditorContributionDescription[] { const skipContributions = [UnusualLineTerminatorsDetector.ID]; - return Iterable.filter(EditorExtensionsRegistry.getEditorContributions(), c => skipContributions.indexOf(c.id) === -1); + return EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); } protected override getCodeEditorWidgetOptions(): ICodeEditorWidgetOptions {