From d29ab10eb6fcf1247d9d3e3123eb5e575ea2a6e1 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 18 Jul 2022 16:55:11 +0200 Subject: [PATCH 001/179] Implements telemetry for bracket colorizer 2 extension usage --- build/lib/i18n.resources.json | 4 ++ ...ketPairColorizer2Telemetry.contribution.ts | 54 +++++++++++++++++++ src/vs/workbench/workbench.common.main.ts | 4 ++ 3 files changed, 62 insertions(+) create mode 100644 src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 7fa1a6519a7..dd949e618f2 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -298,6 +298,10 @@ "name": "vs/workbench/contrib/deprecatedExtensionMigrator", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/bracketPairColorizer2Telemetry", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/offline", "project": "vscode-workbench" diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts new file mode 100644 index 00000000000..cd8861746b0 --- /dev/null +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { onUnexpectedError } from 'vs/base/common/errors'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; +import { EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; + +class BracketPairColorizer2TelemetryContribution { + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService, + @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @ITelemetryService private readonly telemetryService: ITelemetryService + ) { + this.init().catch(onUnexpectedError); + } + + private async init(): Promise { + const bracketPairColorizerId = 'coenraads.bracket-pair-colorizer-2'; + + await this.extensionsWorkbenchService.queryLocal(); + const extension = this.extensionsWorkbenchService.installed.find(e => e.identifier.id === bracketPairColorizerId); + if ( + !extension || + ((extension.enablementState !== EnablementState.EnabledGlobally) && + (extension.enablementState !== EnablementState.EnabledWorkspace)) + ) { + return; + } + + const nativeBracketPairColorizationEnabledKey = 'editor.bracketPairColorization.enabled'; + const nativeColorizationEnabled = !!this.configurationService.getValue(nativeBracketPairColorizationEnabledKey); + + type BracketPairColorizer2InstalledClassification = { + owner: 'hediet'; + nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + }; + type BracketPairColorizer2Event = { + nativeColorizationEnabled: boolean; + }; + this.telemetryService.publicLog2('bracketPairColorizer2Usage', { + nativeColorizationEnabled + }); + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BracketPairColorizer2TelemetryContribution, LifecyclePhase.Restored); + diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 4800d7148ee..7d84444bc02 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -347,4 +347,8 @@ import 'vs/workbench/contrib/audioCues/browser/audioCues.contribution'; // Deprecated Extension Migrator import 'vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExtensionMigrator.contribution'; +// Bracket Pair Colorizer 2 Telemetry +import 'vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution'; + + //#endregion From 6519955afaa4fa55e10d5f695686c184485de538 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 20 Jul 2022 10:57:44 +0200 Subject: [PATCH 002/179] Fixes --- .../browser/bracketPairColorizer2Telemetry.contribution.ts | 3 ++- src/vs/workbench/workbench.common.main.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts index cd8861746b0..f1aaf14ce4d 100644 --- a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -39,7 +39,8 @@ class BracketPairColorizer2TelemetryContribution { type BracketPairColorizer2InstalledClassification = { owner: 'hediet'; - nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'See below' }; + comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.', }; type BracketPairColorizer2Event = { nativeColorizationEnabled: boolean; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 7d84444bc02..b0c26eacd7f 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -350,5 +350,4 @@ import 'vs/workbench/contrib/deprecatedExtensionMigrator/browser/deprecatedExten // Bracket Pair Colorizer 2 Telemetry import 'vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution'; - //#endregion From dbeae4310326eb503a68c7a467493e52d9820b38 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 20 Jul 2022 11:52:50 +0200 Subject: [PATCH 003/179] Skeleton of `editor.contrib.stickyScrolling` feature. --- .../semanticScroll/browser/stickyScroll.ts | 152 ++++++++++++++++++ src/vs/editor/editor.all.ts | 1 + 2 files changed, 153 insertions(+) create mode 100644 src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts diff --git a/src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts new file mode 100644 index 00000000000..05b797f5281 --- /dev/null +++ b/src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts @@ -0,0 +1,152 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/browser/outlineModel'; +import { CancellationToken, } from 'vs/base/common/cancellation'; +import { ITextModel } from 'vs/editor/common/model'; +import { Range } from 'vs/editor/common/core/range'; +import * as dom from 'vs/base/browser/dom'; + +class StickyScrollController implements IEditorContribution { + + static readonly ID = 'store.contrib.stickyScrollController'; + private readonly _editor: ICodeEditor; + private readonly stickyScrollWidget: StickyScrollWidget; + private readonly _languageFeaturesService: ILanguageFeaturesService; + private readonly _store: DisposableStore = new DisposableStore(); + private previousEnclosingElementStartLine: number; + private previousEnclosingElementEndLine: number; + + constructor( + editor: ICodeEditor, + @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService + ) { + + this._editor = editor; + this._languageFeaturesService = _languageFeaturesService; + this.previousEnclosingElementStartLine = 0; + this.previousEnclosingElementEndLine = 0; + + this.stickyScrollWidget = new StickyScrollWidget(); + this._editor.addOverlayWidget(this.stickyScrollWidget); + + this._store.add(this._editor.onDidChangeModel((e) => { + this.renderStickyScroll(); + })); + + this._store.add(this._editor.onDidScrollChange((e) => { + this.renderStickyScroll(); + + })); + + this._store.add(this._editor.onDidChangeModelContent((e) => { + this.renderStickyScroll(); + })); + } + + async createOutlineModel(model: ITextModel): Promise { + return await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, CancellationToken.None); + } + + private renderStickyScroll() { + + const range: Range[] = this._editor.getVisibleRanges(); + let outlineElement: OutlineElement | undefined; + let line: string; + + if (this._editor.hasModel()) { + const model = this._editor.getModel(); + this.createOutlineModel(model).then((outlineModel) => { + outlineElement = outlineModel.getItemEnclosingPosition({ lineNumber: range[0].startLineNumber, column: 1 }); + const currentEnclosingItemStartLine: number | undefined = outlineElement?.symbol.range.startLineNumber; + const currentEnclosingItemEndLine: number | undefined = outlineElement?.symbol.range.endLineNumber; + + if (outlineElement && currentEnclosingItemStartLine !== this.previousEnclosingElementStartLine && currentEnclosingItemEndLine !== this.previousEnclosingElementEndLine) { + this.stickyScrollWidget.emptyRootNode(); + while (outlineElement) { + line = model.getLineContent(outlineElement?.symbol?.range?.startLineNumber); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(line, outlineElement?.symbol.range.startLineNumber)); + if (outlineElement.parent instanceof OutlineElement) { + outlineElement = outlineElement.parent; + } else { + break; + } + } + this.stickyScrollWidget.updateRootNode(); + } else if (!outlineElement) { + this.stickyScrollWidget.emptyRootNode(); + } + }); + } + } + dispose(): void { + this._store.dispose(); + } +} + +class StickyScrollCodeLine { + constructor(public readonly line: string, public readonly lineNumber: number) { } + + getDomNode() { + const domTemplate = dom.h('div', [dom.h('span', { $: 'lineNumber' }), dom.h('span', { $: 'lineValue' })]); + domTemplate.lineNumber.innerText = this.lineNumber.toString(); + domTemplate.lineValue.innerText = this.line; + return domTemplate.root; + } +} + +class StickyScrollWidget implements IOverlayWidget { + + allowEditorOverflow?: boolean | undefined; + suppressMouseDown?: boolean | undefined; + arrayOfCodeLines: StickyScrollCodeLine[] = []; + readonly rootDomNode: HTMLElement = document.createElement('div'); + + + constructor() { + + this.rootDomNode = document.createElement('div'); + this.rootDomNode.style.background = 'var(--separator-border)'; + this.rootDomNode.style.width = '100%'; + } + + pushCodeLine(codeLine: StickyScrollCodeLine) { + this.arrayOfCodeLines.unshift(codeLine); + // this.rootDomNode.appendChild(codeLine.getDomNode()); + } + + updateRootNode() { + for (const line of this.arrayOfCodeLines) { + this.rootDomNode.appendChild(line.getDomNode()); + } + } + + emptyRootNode() { + this.arrayOfCodeLines = []; + dom.clearNode(this.rootDomNode); + } + + getId(): string { + return 'editor.contrib.stickyScrollWidget'; + } + + getDomNode(): HTMLElement { + return this.rootDomNode; + } + + getPosition(): IOverlayWidgetPosition | null { + return { + preference: null + }; + } +} + +registerEditorContribution(StickyScrollController.ID, StickyScrollController); + diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 1168ef7bb16..93a3a0963a0 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -41,6 +41,7 @@ import 'vs/editor/contrib/links/browser/links'; import 'vs/editor/contrib/multicursor/browser/multicursor'; import 'vs/editor/contrib/parameterHints/browser/parameterHints'; import 'vs/editor/contrib/rename/browser/rename'; +import 'vs/editor/contrib/semanticScroll/browser/stickyScroll'; import 'vs/editor/contrib/smartSelect/browser/smartSelect'; import 'vs/editor/contrib/snippet/browser/snippetController2'; import 'vs/editor/contrib/suggest/browser/suggestController'; From 9ed65fa535b03ecbb22db7b24a011f32b5dcd367 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 20 Jul 2022 12:18:07 +0200 Subject: [PATCH 004/179] Renamed the folder from semanticScroll to stickyScroll --- .../browser/stickyScroll.ts | 11 +++++++++++ src/vs/editor/editor.all.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) rename src/vs/editor/contrib/{semanticScroll => stickyScroll}/browser/stickyScroll.ts (92%) diff --git a/src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts similarity index 92% rename from src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts rename to src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 05b797f5281..c65ec88409b 100644 --- a/src/vs/editor/contrib/semanticScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -95,10 +95,21 @@ class StickyScrollCodeLine { constructor(public readonly line: string, public readonly lineNumber: number) { } getDomNode() { + /* Error with the type checking const domTemplate = dom.h('div', [dom.h('span', { $: 'lineNumber' }), dom.h('span', { $: 'lineValue' })]); domTemplate.lineNumber.innerText = this.lineNumber.toString(); domTemplate.lineValue.innerText = this.line; return domTemplate.root; + */ + + const root: HTMLElement = document.createElement('div'); + const lineNumberHTMLNode = document.createElement('span'); + const lineHTMLNode = document.createElement('span'); + lineNumberHTMLNode.innerText = this.lineNumber.toString(); + lineHTMLNode.innerText = this.line; + root.appendChild(lineNumberHTMLNode); + root.appendChild(lineHTMLNode); + return root; } } diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 93a3a0963a0..491f60141f5 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -41,7 +41,7 @@ import 'vs/editor/contrib/links/browser/links'; import 'vs/editor/contrib/multicursor/browser/multicursor'; import 'vs/editor/contrib/parameterHints/browser/parameterHints'; import 'vs/editor/contrib/rename/browser/rename'; -import 'vs/editor/contrib/semanticScroll/browser/stickyScroll'; +import 'vs/editor/contrib/stickyScroll/browser/stickyScroll'; import 'vs/editor/contrib/smartSelect/browser/smartSelect'; import 'vs/editor/contrib/snippet/browser/snippetController2'; import 'vs/editor/contrib/suggest/browser/suggestController'; From 3ffd13581fb94dca496eca81e32f0125840faf1b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 20 Jul 2022 13:55:08 +0200 Subject: [PATCH 005/179] , -> ; --- .../browser/bracketPairColorizer2Telemetry.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts index f1aaf14ce4d..743409102d0 100644 --- a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -40,7 +40,7 @@ class BracketPairColorizer2TelemetryContribution { type BracketPairColorizer2InstalledClassification = { owner: 'hediet'; nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'See below' }; - comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.', + comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.' }; type BracketPairColorizer2Event = { nativeColorizationEnabled: boolean; From 5cc2389265d25d49145bee56893f7e19588f8bf3 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 20 Jul 2022 14:00:58 +0200 Subject: [PATCH 006/179] Adds missing semicolon. --- .../browser/bracketPairColorizer2Telemetry.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts index 743409102d0..62aab189b5e 100644 --- a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -40,7 +40,7 @@ class BracketPairColorizer2TelemetryContribution { type BracketPairColorizer2InstalledClassification = { owner: 'hediet'; nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'See below' }; - comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.' + comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.'; }; type BracketPairColorizer2Event = { nativeColorizationEnabled: boolean; From d5c2d150b068f001f48d8abf7afe860f5ded4d87 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Thu, 21 Jul 2022 14:29:40 +0200 Subject: [PATCH 007/179] Can now click on sticky scroll overlay to go to a specific line, and the overlay is added into the settings. It is disabled by default. --- src/vs/editor/common/config/editorOptions.ts | 54 +++++++++++++ .../common/standalone/standaloneEnums.ts | 57 ++++++------- .../stickyScroll/browser/stickyScroll.ts | 80 ++++++++++++++----- src/vs/monaco.d.ts | 72 ++++++++++------- 4 files changed, 185 insertions(+), 78 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 31e39bf1cf4..826aa1a6a72 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -169,6 +169,10 @@ export interface IEditorOptions { * Control the behavior and rendering of the scrollbars. */ scrollbar?: IEditorScrollbarOptions; + /** + * Control the behavior of the sticky scroll + */ + stickyScroll?: IEditorStickyScrollOptions; /** * Control the behavior and rendering of the minimap. */ @@ -2504,6 +2508,54 @@ class EditorLightbulb extends BaseEditorOption>; + +class EditorStickyScroll extends BaseEditorOption { + + constructor() { + const defaults: EditorStickyScrollOptions = { enabled: false }; + super( + EditorOption.stickyScroll, 'stickyScroll', defaults, + { + 'editor.stickyScroll.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('editor.stickyScroll', "Enables the sticky scroll in the editor.") + }, + } + ); + } + + public validate(_input: any): EditorStickyScrollOptions { + if (!_input || typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorStickyScrollOptions; + return { + enabled: boolean(input.enabled, this.defaultValue.enabled) + }; + } +} + +//#endregion + //#region inlayHints /** @@ -4523,6 +4575,7 @@ export const enum EditorOption { smartSelect, smoothScrolling, stickyTabStops, + stickyScroll, stopRenderingLineAfter, suggest, suggestFontSize, @@ -5079,6 +5132,7 @@ export const EditorOptions = { EditorOption.smoothScrolling, 'smoothScrolling', false, { description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") } )), + stickyScroll: register(new EditorStickyScroll()), stopRenderingLineAfter: register(new EditorIntOption( EditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter', 10000, -1, Constants.MAX_SAFE_SMALL_INTEGER, diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 8d709286d5c..447a6366a57 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -273,34 +273,35 @@ export enum EditorOption { smartSelect = 103, smoothScrolling = 104, stickyTabStops = 105, - stopRenderingLineAfter = 106, - suggest = 107, - suggestFontSize = 108, - suggestLineHeight = 109, - suggestOnTriggerCharacters = 110, - suggestSelection = 111, - tabCompletion = 112, - tabIndex = 113, - unicodeHighlighting = 114, - unusualLineTerminators = 115, - useShadowDOM = 116, - useTabStops = 117, - wordSeparators = 118, - wordWrap = 119, - wordWrapBreakAfterCharacters = 120, - wordWrapBreakBeforeCharacters = 121, - wordWrapColumn = 122, - wordWrapOverride1 = 123, - wordWrapOverride2 = 124, - wrappingIndent = 125, - wrappingStrategy = 126, - showDeprecated = 127, - inlayHints = 128, - editorClassName = 129, - pixelRatio = 130, - tabFocusMode = 131, - layoutInfo = 132, - wrappingInfo = 133 + stickyScroll = 106, + stopRenderingLineAfter = 107, + suggest = 108, + suggestFontSize = 109, + suggestLineHeight = 110, + suggestOnTriggerCharacters = 111, + suggestSelection = 112, + tabCompletion = 113, + tabIndex = 114, + unicodeHighlighting = 115, + unusualLineTerminators = 116, + useShadowDOM = 117, + useTabStops = 118, + wordSeparators = 119, + wordWrap = 120, + wordWrapBreakAfterCharacters = 121, + wordWrapBreakBeforeCharacters = 122, + wordWrapColumn = 123, + wordWrapOverride1 = 124, + wordWrapOverride2 = 125, + wrappingIndent = 126, + wrappingStrategy = 127, + showDeprecated = 128, + inlayHints = 129, + editorClassName = 130, + pixelRatio = 131, + tabFocusMode = 132, + layoutInfo = 133, + wrappingInfo = 134 } /** diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index c65ec88409b..09938f96bc3 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -13,6 +13,10 @@ import { CancellationToken, } from 'vs/base/common/cancellation'; import { ITextModel } from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; import * as dom from 'vs/base/browser/dom'; +import { SymbolKind } from 'vs/editor/common/languages'; +import { Color } from 'vs/base/common/color'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + class StickyScrollController implements IEditorContribution { @@ -34,21 +38,29 @@ class StickyScrollController implements IEditorContribution { this.previousEnclosingElementStartLine = 0; this.previousEnclosingElementEndLine = 0; - this.stickyScrollWidget = new StickyScrollWidget(); + this.stickyScrollWidget = new StickyScrollWidget(this._editor); + this._editor.addOverlayWidget(this.stickyScrollWidget); - this._store.add(this._editor.onDidChangeModel((e) => { - this.renderStickyScroll(); + this._store.add(this._editor.onDidChangeModel(() => this._update())); + this._store.add(this._editor.onDidScrollChange(() => this._update())); + this._store.add(this._editor.onDidChangeModelContent(() => this._update())); + this._store.add(this._editor.onDidChangeConfiguration(e => { + if (e.hasChanged(EditorOption.stickyScroll)) { + this._update(); + } else { + this.stickyScrollWidget.emptyRootNode(); + } })); + this._update(); + } - this._store.add(this._editor.onDidScrollChange((e) => { - this.renderStickyScroll(); - - })); - - this._store.add(this._editor.onDidChangeModelContent((e) => { - this.renderStickyScroll(); - })); + private _update(): void { + const options = this._editor.getOption(EditorOption.stickyScroll); + if (options.enabled === false) { + return; + } + this.renderStickyScroll(); } async createOutlineModel(model: ITextModel): Promise { @@ -64,15 +76,16 @@ class StickyScrollController implements IEditorContribution { if (this._editor.hasModel()) { const model = this._editor.getModel(); this.createOutlineModel(model).then((outlineModel) => { - outlineElement = outlineModel.getItemEnclosingPosition({ lineNumber: range[0].startLineNumber, column: 1 }); + const nLinesStickyScroll = this.stickyScrollWidget.arrayOfCodeLines.length; + outlineElement = outlineModel.getItemEnclosingPosition({ lineNumber: range[0].startLineNumber + nLinesStickyScroll, column: 1 }); const currentEnclosingItemStartLine: number | undefined = outlineElement?.symbol.range.startLineNumber; const currentEnclosingItemEndLine: number | undefined = outlineElement?.symbol.range.endLineNumber; - if (outlineElement && currentEnclosingItemStartLine !== this.previousEnclosingElementStartLine && currentEnclosingItemEndLine !== this.previousEnclosingElementEndLine) { + if (outlineElement && currentEnclosingItemStartLine !== this.previousEnclosingElementStartLine && currentEnclosingItemEndLine !== this.previousEnclosingElementEndLine && (outlineElement.symbol.kind === SymbolKind.Class || outlineElement.symbol.kind === SymbolKind.Interface || outlineElement.symbol.kind === SymbolKind.Function || outlineElement.symbol.kind === SymbolKind.Method || outlineElement.symbol.kind === SymbolKind.Constructor)) { this.stickyScrollWidget.emptyRootNode(); while (outlineElement) { line = model.getLineContent(outlineElement?.symbol?.range?.startLineNumber); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(line, outlineElement?.symbol.range.startLineNumber)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(line, outlineElement?.symbol.range.startLineNumber, this._editor)); if (outlineElement.parent instanceof OutlineElement) { outlineElement = outlineElement.parent; } else { @@ -92,27 +105,52 @@ class StickyScrollController implements IEditorContribution { } class StickyScrollCodeLine { - constructor(public readonly line: string, public readonly lineNumber: number) { } + constructor(public readonly line: string, public readonly lineNumber: number, public readonly _editor: ICodeEditor) { } getDomNode() { - /* Error with the type checking + /* --- FOR SOME REASON THROWS AN ERROR const domTemplate = dom.h('div', [dom.h('span', { $: 'lineNumber' }), dom.h('span', { $: 'lineValue' })]); domTemplate.lineNumber.innerText = this.lineNumber.toString(); domTemplate.lineValue.innerText = this.line; return domTemplate.root; - */ + ---- */ const root: HTMLElement = document.createElement('div'); const lineNumberHTMLNode = document.createElement('span'); const lineHTMLNode = document.createElement('span'); + lineNumberHTMLNode.innerText = this.lineNumber.toString(); - lineHTMLNode.innerText = this.line; + + const modifiedLine = this.line.replace(/\s/g, '\xa0'); + lineHTMLNode.innerText = modifiedLine; + lineHTMLNode.onclick = e => { + e.stopPropagation(); + e.preventDefault(); + this._editor.revealLine(this.lineNumber); + }; + this._editor.applyFontInfo(lineHTMLNode); + + lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; + lineNumberHTMLNode.style.display = 'inline-block'; + lineNumberHTMLNode.style.textAlign = 'center'; + this._editor.applyFontInfo(lineNumberHTMLNode); + root.appendChild(lineNumberHTMLNode); root.appendChild(lineHTMLNode); return root; } } + +export interface IStickyScrollWidgetStyles { + stickyScrollBackground?: Color; + stickyScrollForeground?: Color; + stickyScrollHoverForeground?: Color; + stickyScrollFocusForeground?: Color; + stickyScrollFocusAndSelectionForeground?: Color; +} + + class StickyScrollWidget implements IOverlayWidget { allowEditorOverflow?: boolean | undefined; @@ -120,17 +158,15 @@ class StickyScrollWidget implements IOverlayWidget { arrayOfCodeLines: StickyScrollCodeLine[] = []; readonly rootDomNode: HTMLElement = document.createElement('div'); - - constructor() { + constructor(public readonly _editor: ICodeEditor) { this.rootDomNode = document.createElement('div'); - this.rootDomNode.style.background = 'var(--separator-border)'; this.rootDomNode.style.width = '100%'; + this.rootDomNode.style.backgroundColor = 'black'; } pushCodeLine(codeLine: StickyScrollCodeLine) { this.arrayOfCodeLines.unshift(codeLine); - // this.rootDomNode.appendChild(codeLine.getDomNode()); } updateRootNode() { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index f608381f9e4..3bff5517b6e 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2931,6 +2931,10 @@ declare namespace monaco.editor { * Control the behavior and rendering of the scrollbars. */ scrollbar?: IEditorScrollbarOptions; + /** + * Control the behavior of the sticky scroll + */ + stickyScroll?: IEditorStickyScrollOptions; /** * Control the behavior and rendering of the minimap. */ @@ -3789,6 +3793,16 @@ declare namespace monaco.editor { enabled?: boolean; } + /** + * Configuration options for editor sticky scroll + */ + export interface IEditorStickyScrollOptions { + /** + * Enable the sticky scroll + */ + enabled?: boolean; + } + /** * Configuration options for editor inlayHints */ @@ -4408,34 +4422,35 @@ declare namespace monaco.editor { smartSelect = 103, smoothScrolling = 104, stickyTabStops = 105, - stopRenderingLineAfter = 106, - suggest = 107, - suggestFontSize = 108, - suggestLineHeight = 109, - suggestOnTriggerCharacters = 110, - suggestSelection = 111, - tabCompletion = 112, - tabIndex = 113, - unicodeHighlighting = 114, - unusualLineTerminators = 115, - useShadowDOM = 116, - useTabStops = 117, - wordSeparators = 118, - wordWrap = 119, - wordWrapBreakAfterCharacters = 120, - wordWrapBreakBeforeCharacters = 121, - wordWrapColumn = 122, - wordWrapOverride1 = 123, - wordWrapOverride2 = 124, - wrappingIndent = 125, - wrappingStrategy = 126, - showDeprecated = 127, - inlayHints = 128, - editorClassName = 129, - pixelRatio = 130, - tabFocusMode = 131, - layoutInfo = 132, - wrappingInfo = 133 + stickyScroll = 106, + stopRenderingLineAfter = 107, + suggest = 108, + suggestFontSize = 109, + suggestLineHeight = 110, + suggestOnTriggerCharacters = 111, + suggestSelection = 112, + tabCompletion = 113, + tabIndex = 114, + unicodeHighlighting = 115, + unusualLineTerminators = 116, + useShadowDOM = 117, + useTabStops = 118, + wordSeparators = 119, + wordWrap = 120, + wordWrapBreakAfterCharacters = 121, + wordWrapBreakBeforeCharacters = 122, + wordWrapColumn = 123, + wordWrapOverride1 = 124, + wordWrapOverride2 = 125, + wrappingIndent = 126, + wrappingStrategy = 127, + showDeprecated = 128, + inlayHints = 129, + editorClassName = 130, + pixelRatio = 131, + tabFocusMode = 132, + layoutInfo = 133, + wrappingInfo = 134 } export const EditorOptions: { @@ -4546,6 +4561,7 @@ declare namespace monaco.editor { snippetSuggestions: IEditorOption; smartSelect: IEditorOption>>; smoothScrolling: IEditorOption; + stickyScroll: IEditorOption>>; stopRenderingLineAfter: IEditorOption; suggest: IEditorOption>>; inlineSuggest: IEditorOption>>; From 0664facf1b723d12e685f287887d3059586b98ed Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 22 Jul 2022 14:23:19 +0200 Subject: [PATCH 008/179] Added csp policy for the sticky scroll and theme coloring --- .../electron-sandbox/workbench/workbench.html | 2 +- .../stickyScroll/browser/stickyScroll.ts | 219 +++++++++++++----- src/vs/platform/theme/common/colorRegistry.ts | 7 +- 3 files changed, 173 insertions(+), 55 deletions(-) diff --git a/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-sandbox/workbench/workbench.html index 47066f520be..16e089df650 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.html +++ b/src/vs/code/electron-sandbox/workbench/workbench.html @@ -4,7 +4,7 @@ - + diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 09938f96bc3..8a3bf6ddef3 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -11,12 +11,21 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/browser/outlineModel'; import { CancellationToken, } from 'vs/base/common/cancellation'; import { ITextModel } from 'vs/editor/common/model'; -import { Range } from 'vs/editor/common/core/range'; import * as dom from 'vs/base/browser/dom'; -import { SymbolKind } from 'vs/editor/common/languages'; import { Color } from 'vs/base/common/color'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens'; +import * as colors from 'vs/platform/theme/common/colorRegistry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; + +enum ScrollDirection { + Down = 0, + Up = 1, + None = 2 +} class StickyScrollController implements IEditorContribution { @@ -24,88 +33,170 @@ class StickyScrollController implements IEditorContribution { private readonly _editor: ICodeEditor; private readonly stickyScrollWidget: StickyScrollWidget; private readonly _languageFeaturesService: ILanguageFeaturesService; + private readonly _store: DisposableStore = new DisposableStore(); - private previousEnclosingElementStartLine: number; - private previousEnclosingElementEndLine: number; + + private _ranges: number[][] = []; + private _outlineModel: OutlineModel | null = null; + private _lastScrollPositions: number[] = []; + private _lastScrollPositionsLength: number = 0; + private _scrollDirection: ScrollDirection = ScrollDirection.Down; + private _themeService: IThemeService; constructor( editor: ICodeEditor, - @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService + @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, + @IThemeService _themeService: IThemeService ) { this._editor = editor; this._languageFeaturesService = _languageFeaturesService; - this.previousEnclosingElementStartLine = 0; - this.previousEnclosingElementEndLine = 0; - - this.stickyScrollWidget = new StickyScrollWidget(this._editor); + this._themeService = _themeService; + this.stickyScrollWidget = new StickyScrollWidget(this._editor, this._themeService); this._editor.addOverlayWidget(this.stickyScrollWidget); - this._store.add(this._editor.onDidChangeModel(() => this._update())); - this._store.add(this._editor.onDidScrollChange(() => this._update())); - this._store.add(this._editor.onDidChangeModelContent(() => this._update())); + this._store.add(this._editor.onDidChangeModel(() => this._update(true))); + this._store.add(this._editor.onDidScrollChange(() => this._update(false))); + this._store.add(this._editor.onDidChangeModelContent(() => this._update(true))); this._store.add(this._editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.stickyScroll)) { - this._update(); + this._update(true); } else { this.stickyScrollWidget.emptyRootNode(); } })); this._update(); + + console.log('this editor : ', this._editor); + console.log('view model', this._editor._getViewModel()); + console.log('layout info', this._editor.getLayoutInfo()); + console.log('layout info', this._editor.getModel()); } - private _update(): void { + private _update(updateOutline: boolean = false): void { + if (updateOutline) { + this._updateOutlineModel(); + } const options = this._editor.getOption(EditorOption.stickyScroll); if (options.enabled === false) { return; } - this.renderStickyScroll(); + this._renderStickyScroll(); } - async createOutlineModel(model: ITextModel): Promise { + async _createOutlineModel(model: ITextModel): Promise { return await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, CancellationToken.None); } - private renderStickyScroll() { + private _findLineRanges(outlineElement: OutlineElement, depth: number) { - const range: Range[] = this._editor.getVisibleRanges(); - let outlineElement: OutlineElement | undefined; - let line: string; + if (outlineElement?.children.size) { + for (const outline of outlineElement?.children.values()) { + depth++; + this._findLineRanges(outline, depth); + } + } else { + let currentStartLine: number | undefined = 0; + let currentEndLine: number | undefined = 0; + while (outlineElement) { + currentStartLine = outlineElement?.symbol.range.startLineNumber as number; + currentEndLine = outlineElement?.symbol.range.endLineNumber as number; + this._ranges.push([currentStartLine, currentEndLine, depth]); + depth--; + if (outlineElement.parent instanceof OutlineElement) { + outlineElement = outlineElement.parent; + } else { + break; + } + } + } + } + private _updateOutlineModel() { if (this._editor.hasModel()) { const model = this._editor.getModel(); - this.createOutlineModel(model).then((outlineModel) => { - const nLinesStickyScroll = this.stickyScrollWidget.arrayOfCodeLines.length; - outlineElement = outlineModel.getItemEnclosingPosition({ lineNumber: range[0].startLineNumber + nLinesStickyScroll, column: 1 }); - const currentEnclosingItemStartLine: number | undefined = outlineElement?.symbol.range.startLineNumber; - const currentEnclosingItemEndLine: number | undefined = outlineElement?.symbol.range.endLineNumber; - - if (outlineElement && currentEnclosingItemStartLine !== this.previousEnclosingElementStartLine && currentEnclosingItemEndLine !== this.previousEnclosingElementEndLine && (outlineElement.symbol.kind === SymbolKind.Class || outlineElement.symbol.kind === SymbolKind.Interface || outlineElement.symbol.kind === SymbolKind.Function || outlineElement.symbol.kind === SymbolKind.Method || outlineElement.symbol.kind === SymbolKind.Constructor)) { - this.stickyScrollWidget.emptyRootNode(); - while (outlineElement) { - line = model.getLineContent(outlineElement?.symbol?.range?.startLineNumber); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(line, outlineElement?.symbol.range.startLineNumber, this._editor)); - if (outlineElement.parent instanceof OutlineElement) { - outlineElement = outlineElement.parent; - } else { - break; - } + this._lastScrollPositionsLength = 2; + this._createOutlineModel(model).then((outlineModel) => { + this._outlineModel = outlineModel; + this._ranges = []; + for (const outline of this._outlineModel?.children.values()) { + if (outline instanceof OutlineElement) { + this._findLineRanges(outline, 1); } - this.stickyScrollWidget.updateRootNode(); - } else if (!outlineElement) { - this.stickyScrollWidget.emptyRootNode(); } + this._ranges = this._ranges.sort(function (a, b) { + return a[0] - b[0]; + }); }); } } + + private _findScrollDirection(): ScrollDirection { + for (let i = 1; i <= this._lastScrollPositionsLength; i++) { + if (this._lastScrollPositions[i] < this._lastScrollPositions[i - 1]) { + for (let j = 1; j < this._lastScrollPositionsLength; j++) { + if (this._lastScrollPositions[j] > this._lastScrollPositions[j - 1]) { + return ScrollDirection.None; + } + } + return ScrollDirection.Up; + } + } + return ScrollDirection.Down; + } + + private _renderStickyScroll() { + + + const lineHeight = this._editor._getViewModel()?.cursorConfig.lineHeight || 0; + + if (this._editor.hasModel()) { + const model = this._editor.getModel(); + const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.arrayOfCodeLines.length * lineHeight; + if (this._lastScrollPositions.length === this._lastScrollPositionsLength) { + this._lastScrollPositions.shift(); + } + this._lastScrollPositions.push(this._editor.getScrollTop()); + this._scrollDirection = this._findScrollDirection(); + this.stickyScrollWidget.emptyRootNode(); + + for (const range of this._ranges) { + console.log('range : ', range); + console.log('scroll : ', currentScrollTop); + console.log('number of lines : ', this.stickyScrollWidget.arrayOfCodeLines.length); + console.log('second scroll position : ', this._editor.getScrollTop() + range[2] * lineHeight); + console.log('top pixel of bottom line : ', (range[1] - 1) * lineHeight); + console.log('bottom pixel of bottom line : ', range[1] * lineHeight); + + if (this._editor.getScrollTop() + range[2] * lineHeight >= range[1] * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight <= (range[1] + 1) * lineHeight) { + console.log('top if loop : ', this._editor.getScrollTop() + range[2] * lineHeight, ' where range[2] is : ', range[2]); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, -1, (range[2] - 1) * lineHeight + range[1] * lineHeight - this._editor.getScrollTop() - range[2] * lineHeight)); + } else if (this._editor.getScrollTop() + range[2] * lineHeight >= (range[1] - 1) * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight < range[1] * lineHeight) { + console.log('second top if loop : ', this._editor.getScrollTop() + range[2] * lineHeight, ' where range[2] is : ', range[2]); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); + } else if (this._scrollDirection === ScrollDirection.Down && currentScrollTop >= (range[0] - 1) * lineHeight && currentScrollTop < (range[1] - 1) * lineHeight) { + console.log('scroll going down: ', currentScrollTop); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); + } else if (this._scrollDirection === ScrollDirection.Up && currentScrollTop >= range[0] * lineHeight && currentScrollTop < (range[1] - 1) * lineHeight) { + console.log('scroll going up: ', currentScrollTop); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); + } + } + this.stickyScrollWidget.updateRootNode(); + } + } + dispose(): void { this._store.dispose(); } } +const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { createHTML: value => value }); + class StickyScrollCodeLine { - constructor(public readonly line: string, public readonly lineNumber: number, public readonly _editor: ICodeEditor) { } + constructor(public readonly line: string, public readonly lineNumber: number, public readonly _editor: ICodeEditor, public readonly _themeService: IThemeService, public readonly zIndex: number, public readonly position?: number) { } + getDomNode() { /* --- FOR SOME REASON THROWS AN ERROR @@ -116,13 +207,23 @@ class StickyScrollCodeLine { ---- */ const root: HTMLElement = document.createElement('div'); - const lineNumberHTMLNode = document.createElement('span'); - const lineHTMLNode = document.createElement('span'); - - lineNumberHTMLNode.innerText = this.lineNumber.toString(); - const modifiedLine = this.line.replace(/\s/g, '\xa0'); - lineHTMLNode.innerText = modifiedLine; + const lineRenderingData = this._editor._getViewModel()?.getViewLineRenderingData(this._editor.getVisibleRanges()[0], this.lineNumber); + // TODO : Parameters need to be tweaked and need to add line decorations for the bracket and brace pairs + const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData?.continuesWithWrappedLine as boolean, lineRenderingData?.isBasicASCII as boolean, lineRenderingData?.containsRTL as boolean, 0, lineRenderingData?.tokens as IViewLineTokens, [], lineRenderingData?.tabSize as number, lineRenderingData?.startVisibleColumn as number, 1, 1, 1, 50, 'all', true, false, []); + const sb = createStringBuilder(100000); + renderViewLine(renderLineInput, sb); + + let newLine; + if (_ttPolicy) { + newLine = _ttPolicy.createHTML(sb.build() as string); + } else { + newLine = sb.build(); + } + + const lineHTMLNode = document.createElement('span'); + lineHTMLNode.innerHTML = newLine as string; + lineHTMLNode.onclick = e => { e.stopPropagation(); e.preventDefault(); @@ -130,6 +231,8 @@ class StickyScrollCodeLine { }; this._editor.applyFontInfo(lineHTMLNode); + const lineNumberHTMLNode = document.createElement('span'); + lineNumberHTMLNode.innerText = this.lineNumber.toString(); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; lineNumberHTMLNode.style.display = 'inline-block'; lineNumberHTMLNode.style.textAlign = 'center'; @@ -137,11 +240,25 @@ class StickyScrollCodeLine { root.appendChild(lineNumberHTMLNode); root.appendChild(lineHTMLNode); + if (this.position) { + root.style.position = 'absolute'; + root.style.top = this.position.toString() + 'px'; + root.style.width = '100%'; + } + root.style.zIndex = this.zIndex.toString(); + + const color = colors.resolveColorValue({ + op: colors.ColorTransformType.Lighten, + value: colors.editorBackground, + factor: 0.2 + }, this._themeService.getColorTheme()) as Color; + + root.style.backgroundColor = Color.Format.CSS.formatHex(color); + return root; } } - export interface IStickyScrollWidgetStyles { stickyScrollBackground?: Color; stickyScrollForeground?: Color; @@ -150,7 +267,6 @@ export interface IStickyScrollWidgetStyles { stickyScrollFocusAndSelectionForeground?: Color; } - class StickyScrollWidget implements IOverlayWidget { allowEditorOverflow?: boolean | undefined; @@ -158,15 +274,13 @@ class StickyScrollWidget implements IOverlayWidget { arrayOfCodeLines: StickyScrollCodeLine[] = []; readonly rootDomNode: HTMLElement = document.createElement('div'); - constructor(public readonly _editor: ICodeEditor) { - + constructor(public readonly _editor: ICodeEditor, public readonly _themeService: IThemeService) { this.rootDomNode = document.createElement('div'); this.rootDomNode.style.width = '100%'; - this.rootDomNode.style.backgroundColor = 'black'; } pushCodeLine(codeLine: StickyScrollCodeLine) { - this.arrayOfCodeLines.unshift(codeLine); + this.arrayOfCodeLines.push(codeLine); } updateRootNode() { @@ -185,6 +299,7 @@ class StickyScrollWidget implements IOverlayWidget { } getDomNode(): HTMLElement { + this.rootDomNode.style.zIndex = '3'; return this.rootDomNode; } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index b26f20b529d..0db03726e0d 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -314,14 +314,17 @@ export const editorBackground = registerColor('editor.background', { light: '#ff */ export const editorForeground = registerColor('editor.foreground', { light: '#333333', dark: '#BBBBBB', hcDark: Color.white, hcLight: foreground }, nls.localize('editorForeground', "Editor default foreground color.")); +/** + * Sticky scroll + */ +export const stickyScrollBackground = registerColor('stickyScroll.background', { light: '#fffffe', dark: '#1E1E1E', hcDark: Color.black, hcLight: Color.white }, nls.localize('stickyScrollBackground', "Sticky scroll background color")); + /** * Editor widgets */ export const editorWidgetBackground = registerColor('editorWidget.background', { dark: '#252526', light: '#F3F3F3', hcDark: '#0C141F', hcLight: Color.white }, nls.localize('editorWidgetBackground', 'Background color of editor widgets, such as find/replace.')); export const editorWidgetForeground = registerColor('editorWidget.foreground', { dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground }, nls.localize('editorWidgetForeground', 'Foreground color of editor widgets, such as find/replace.')); - export const editorWidgetBorder = registerColor('editorWidget.border', { dark: '#454545', light: '#C8C8C8', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorWidgetBorder', 'Border color of editor widgets. The color is only used if the widget chooses to have a border and if the color is not overridden by a widget.')); - export const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder', { light: null, dark: null, hcDark: null, hcLight: null }, nls.localize('editorWidgetResizeBorder', "Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.")); /** From 7a7c760efcd11dc0f38cb4b470f516410fad7b17 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 22 Jul 2022 15:20:36 +0200 Subject: [PATCH 009/179] Cleaning code, work in progress --- .../stickyScroll/browser/stickyScroll.ts | 24 +++++++++---------- src/vs/platform/theme/common/colorRegistry.ts | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 8a3bf6ddef3..72fb2f3e3d6 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -66,7 +66,8 @@ class StickyScrollController implements IEditorContribution { this.stickyScrollWidget.emptyRootNode(); } })); - this._update(); + this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true)); + this._update(true); console.log('this editor : ', this._editor); console.log('view model', this._editor._getViewModel()); @@ -74,9 +75,9 @@ class StickyScrollController implements IEditorContribution { console.log('layout info', this._editor.getModel()); } - private _update(updateOutline: boolean = false): void { + private async _update(updateOutline: boolean = false): Promise { if (updateOutline) { - this._updateOutlineModel(); + await this._updateOutlineModel(); } const options = this._editor.getOption(EditorOption.stickyScroll); if (options.enabled === false) { @@ -113,11 +114,11 @@ class StickyScrollController implements IEditorContribution { } } - private _updateOutlineModel() { + private async _updateOutlineModel() { if (this._editor.hasModel()) { const model = this._editor.getModel(); this._lastScrollPositionsLength = 2; - this._createOutlineModel(model).then((outlineModel) => { + await this._createOutlineModel(model).then((outlineModel) => { this._outlineModel = outlineModel; this._ranges = []; for (const outline of this._outlineModel?.children.values()) { @@ -169,7 +170,9 @@ class StickyScrollController implements IEditorContribution { console.log('top pixel of bottom line : ', (range[1] - 1) * lineHeight); console.log('bottom pixel of bottom line : ', range[1] * lineHeight); - if (this._editor.getScrollTop() + range[2] * lineHeight >= range[1] * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight <= (range[1] + 1) * lineHeight) { + // onDidChangeTheme redraw + + if (this._editor.getScrollTop() + range[2] * lineHeight >= range[1] * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight < (range[1] + 1) * lineHeight) { console.log('top if loop : ', this._editor.getScrollTop() + range[2] * lineHeight, ' where range[2] is : ', range[2]); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, -1, (range[2] - 1) * lineHeight + range[1] * lineHeight - this._editor.getScrollTop() - range[2] * lineHeight)); } else if (this._editor.getScrollTop() + range[2] * lineHeight >= (range[1] - 1) * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight < range[1] * lineHeight) { @@ -237,6 +240,7 @@ class StickyScrollCodeLine { lineNumberHTMLNode.style.display = 'inline-block'; lineNumberHTMLNode.style.textAlign = 'center'; this._editor.applyFontInfo(lineNumberHTMLNode); + lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; root.appendChild(lineNumberHTMLNode); root.appendChild(lineHTMLNode); @@ -247,13 +251,7 @@ class StickyScrollCodeLine { } root.style.zIndex = this.zIndex.toString(); - const color = colors.resolveColorValue({ - op: colors.ColorTransformType.Lighten, - value: colors.editorBackground, - factor: 0.2 - }, this._themeService.getColorTheme()) as Color; - - root.style.backgroundColor = Color.Format.CSS.formatHex(color); + root.style.backgroundColor = `var(--vscode-stickyScroll-background)`; return root; } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 0db03726e0d..77995af0b0f 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -317,7 +317,7 @@ export const editorForeground = registerColor('editor.foreground', { light: '#33 /** * Sticky scroll */ -export const stickyScrollBackground = registerColor('stickyScroll.background', { light: '#fffffe', dark: '#1E1E1E', hcDark: Color.black, hcLight: Color.white }, nls.localize('stickyScrollBackground', "Sticky scroll background color")); +export const stickyScrollBackground = registerColor('stickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('stickyScrollBackground', "Sticky scroll background color")); /** * Editor widgets From 00b2aa16c92bace7820fa89615976e85d928ad88 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 22 Jul 2022 18:33:00 +0200 Subject: [PATCH 010/179] Cleaned the code --- .../stickyScroll/browser/stickyScroll.ts | 246 ++++++++---------- 1 file changed, 103 insertions(+), 143 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 72fb2f3e3d6..32c4fba4ee7 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -4,24 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/browser/outlineModel'; -import { CancellationToken, } from 'vs/base/common/cancellation'; -import { ITextModel } from 'vs/editor/common/model'; +import { CancellationToken, CancellationTokenSource, } from 'vs/base/common/cancellation'; import * as dom from 'vs/base/browser/dom'; -import { Color } from 'vs/base/common/color'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; -import { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens'; -import * as colors from 'vs/platform/theme/common/colorRegistry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; - -enum ScrollDirection { +const enum ScrollDirection { Down = 0, Up = 1, None = 2 @@ -35,63 +29,54 @@ class StickyScrollController implements IEditorContribution { private readonly _languageFeaturesService: ILanguageFeaturesService; private readonly _store: DisposableStore = new DisposableStore(); + private readonly _sessionStore: DisposableStore = new DisposableStore(); private _ranges: number[][] = []; - private _outlineModel: OutlineModel | null = null; - private _lastScrollPositions: number[] = []; - private _lastScrollPositionsLength: number = 0; - private _scrollDirection: ScrollDirection = ScrollDirection.Down; - private _themeService: IThemeService; + private _cts: CancellationTokenSource | undefined; + private _lastScrollPosition: number = -1; constructor( editor: ICodeEditor, @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, - @IThemeService _themeService: IThemeService ) { - this._editor = editor; this._languageFeaturesService = _languageFeaturesService; - this._themeService = _themeService; - this.stickyScrollWidget = new StickyScrollWidget(this._editor, this._themeService); - - this._editor.addOverlayWidget(this.stickyScrollWidget); - - this._store.add(this._editor.onDidChangeModel(() => this._update(true))); - this._store.add(this._editor.onDidScrollChange(() => this._update(false))); - this._store.add(this._editor.onDidChangeModelContent(() => this._update(true))); + this.stickyScrollWidget = new StickyScrollWidget(this._editor); this._store.add(this._editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.stickyScroll)) { - this._update(true); - } else { - this.stickyScrollWidget.emptyRootNode(); + this.onConfigurationChange(); } })); - this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true)); - this._update(true); + this.onConfigurationChange(); + } - console.log('this editor : ', this._editor); - console.log('view model', this._editor._getViewModel()); - console.log('layout info', this._editor.getLayoutInfo()); - console.log('layout info', this._editor.getModel()); + private onConfigurationChange() { + const options = this._editor.getOption(EditorOption.stickyScroll); + if (options.enabled === false) { + this.stickyScrollWidget.emptyRootNode(); + this._editor.removeOverlayWidget(this.stickyScrollWidget); + this._sessionStore.clear(); + return; + } else { + this._editor.addOverlayWidget(this.stickyScrollWidget); + this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); + this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); + this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._update(true))); + this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); + this._update(true); + } } private async _update(updateOutline: boolean = false): Promise { if (updateOutline) { - await this._updateOutlineModel(); - } - const options = this._editor.getOption(EditorOption.stickyScroll); - if (options.enabled === false) { - return; + this._cts?.dispose(true); + this._cts = new CancellationTokenSource(); + await this._updateOutlineModel(this._cts.token); } this._renderStickyScroll(); } - async _createOutlineModel(model: ITextModel): Promise { - return await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, CancellationToken.None); - } - private _findLineRanges(outlineElement: OutlineElement, depth: number) { - if (outlineElement?.children.size) { for (const outline of outlineElement?.children.values()) { depth++; @@ -114,107 +99,86 @@ class StickyScrollController implements IEditorContribution { } } - private async _updateOutlineModel() { + private async _updateOutlineModel(token: CancellationToken) { if (this._editor.hasModel()) { const model = this._editor.getModel(); - this._lastScrollPositionsLength = 2; - await this._createOutlineModel(model).then((outlineModel) => { - this._outlineModel = outlineModel; - this._ranges = []; - for (const outline of this._outlineModel?.children.values()) { - if (outline instanceof OutlineElement) { - this._findLineRanges(outline, 1); - } + const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token); + if (token.isCancellationRequested) { + return; + } + this._ranges = []; + for (const outline of outlineModel.children.values()) { + if (outline instanceof OutlineElement) { + this._findLineRanges(outline, 1); } - this._ranges = this._ranges.sort(function (a, b) { - return a[0] - b[0]; - }); + } + this._ranges = this._ranges.sort(function (a, b) { + return a[0] - b[0]; }); } } - private _findScrollDirection(): ScrollDirection { - for (let i = 1; i <= this._lastScrollPositionsLength; i++) { - if (this._lastScrollPositions[i] < this._lastScrollPositions[i - 1]) { - for (let j = 1; j < this._lastScrollPositionsLength; j++) { - if (this._lastScrollPositions[j] > this._lastScrollPositions[j - 1]) { - return ScrollDirection.None; - } - } - return ScrollDirection.Up; - } - } - return ScrollDirection.Down; - } - private _renderStickyScroll() { - - const lineHeight = this._editor._getViewModel()?.cursorConfig.lineHeight || 0; - - if (this._editor.hasModel()) { - const model = this._editor.getModel(); - const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.arrayOfCodeLines.length * lineHeight; - if (this._lastScrollPositions.length === this._lastScrollPositionsLength) { - this._lastScrollPositions.shift(); - } - this._lastScrollPositions.push(this._editor.getScrollTop()); - this._scrollDirection = this._findScrollDirection(); - this.stickyScrollWidget.emptyRootNode(); - - for (const range of this._ranges) { - console.log('range : ', range); - console.log('scroll : ', currentScrollTop); - console.log('number of lines : ', this.stickyScrollWidget.arrayOfCodeLines.length); - console.log('second scroll position : ', this._editor.getScrollTop() + range[2] * lineHeight); - console.log('top pixel of bottom line : ', (range[1] - 1) * lineHeight); - console.log('bottom pixel of bottom line : ', range[1] * lineHeight); - - // onDidChangeTheme redraw - - if (this._editor.getScrollTop() + range[2] * lineHeight >= range[1] * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight < (range[1] + 1) * lineHeight) { - console.log('top if loop : ', this._editor.getScrollTop() + range[2] * lineHeight, ' where range[2] is : ', range[2]); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, -1, (range[2] - 1) * lineHeight + range[1] * lineHeight - this._editor.getScrollTop() - range[2] * lineHeight)); - } else if (this._editor.getScrollTop() + range[2] * lineHeight >= (range[1] - 1) * lineHeight && this._editor.getScrollTop() + range[2] * lineHeight < range[1] * lineHeight) { - console.log('second top if loop : ', this._editor.getScrollTop() + range[2] * lineHeight, ' where range[2] is : ', range[2]); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); - } else if (this._scrollDirection === ScrollDirection.Down && currentScrollTop >= (range[0] - 1) * lineHeight && currentScrollTop < (range[1] - 1) * lineHeight) { - console.log('scroll going down: ', currentScrollTop); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); - } else if (this._scrollDirection === ScrollDirection.Up && currentScrollTop >= range[0] * lineHeight && currentScrollTop < (range[1] - 1) * lineHeight) { - console.log('scroll going up: ', currentScrollTop); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(range[0]), range[0], this._editor, this._themeService, 0)); - } - } - this.stickyScrollWidget.updateRootNode(); + if (!(this._editor.hasModel())) { + return; } + + const lineHeight = this._editor.getOption(EditorOption.lineHeight); + const model = this._editor.getModel(); + const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight; + + const scrollTop = this._editor.getScrollTop(); + let scrollDirection: ScrollDirection; + if (this._lastScrollPosition < scrollTop) { + scrollDirection = ScrollDirection.Down; + } else { + scrollDirection = ScrollDirection.Up; + } + this._lastScrollPosition = scrollTop; + + this.stickyScrollWidget.emptyRootNode(); + // TODO @Aiday: Find a way to iterate over only the ranges of interest, the position at which you start, use binary search + for (const [start, end, depth] of this._ranges) { + if (this._editor.getScrollTop() + depth * lineHeight >= end * lineHeight && this._editor.getScrollTop() + depth * lineHeight < (end + 1) * lineHeight) { + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + end * lineHeight - this._editor.getScrollTop() - depth * lineHeight)); + } else if (this._editor.getScrollTop() + depth * lineHeight >= (end - 1) * lineHeight && this._editor.getScrollTop() + depth * lineHeight < end * lineHeight) { + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } else if (scrollDirection === ScrollDirection.Down && currentScrollTop >= (start - 1) * lineHeight && currentScrollTop < (end - 1) * lineHeight) { + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } else if (scrollDirection === ScrollDirection.Up && currentScrollTop >= start * lineHeight && currentScrollTop < (end - 1) * lineHeight) { + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } + } + this.stickyScrollWidget.updateRootNode(); } dispose(): void { this._store.dispose(); + this._sessionStore.dispose(); } } const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { createHTML: value => value }); class StickyScrollCodeLine { - constructor(public readonly line: string, public readonly lineNumber: number, public readonly _editor: ICodeEditor, public readonly _themeService: IThemeService, public readonly zIndex: number, public readonly position?: number) { } + constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, + private readonly _zIndex: number, private readonly _position?: number) { } getDomNode() { - /* --- FOR SOME REASON THROWS AN ERROR - const domTemplate = dom.h('div', [dom.h('span', { $: 'lineNumber' }), dom.h('span', { $: 'lineValue' })]); - domTemplate.lineNumber.innerText = this.lineNumber.toString(); - domTemplate.lineValue.innerText = this.line; - return domTemplate.root; - ---- */ const root: HTMLElement = document.createElement('div'); - const modifiedLine = this.line.replace(/\s/g, '\xa0'); - const lineRenderingData = this._editor._getViewModel()?.getViewLineRenderingData(this._editor.getVisibleRanges()[0], this.lineNumber); - // TODO : Parameters need to be tweaked and need to add line decorations for the bracket and brace pairs - const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData?.continuesWithWrappedLine as boolean, lineRenderingData?.isBasicASCII as boolean, lineRenderingData?.containsRTL as boolean, 0, lineRenderingData?.tokens as IViewLineTokens, [], lineRenderingData?.tabSize as number, lineRenderingData?.startVisibleColumn as number, 1, 1, 1, 50, 'all', true, false, []); - const sb = createStringBuilder(100000); + const modifiedLine = this._line.replace(/\s/g, '\xa0'); + // TODO @Aiday: use _getViewModel() or other method + // TODO @Aiday: bracket decorations in RenderLineInput + const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRanges()[0], this._lineNumber); + + const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, + lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, [], lineRenderingData.tabSize, + lineRenderingData.startVisibleColumn, 1, 1, 1, 500, 'none', true, true, null); + + const sb = createStringBuilder(2000); renderViewLine(renderLineInput, sb); let newLine; @@ -227,56 +191,52 @@ class StickyScrollCodeLine { const lineHTMLNode = document.createElement('span'); lineHTMLNode.innerHTML = newLine as string; + // TODO @Aiday: needs to be disposed, add one listener to sticky scroll widget, e has property target with direct element or child of the element lineHTMLNode.onclick = e => { e.stopPropagation(); e.preventDefault(); - this._editor.revealLine(this.lineNumber); + this._editor.revealLine(this._lineNumber); }; this._editor.applyFontInfo(lineHTMLNode); const lineNumberHTMLNode = document.createElement('span'); - lineNumberHTMLNode.innerText = this.lineNumber.toString(); + lineNumberHTMLNode.innerText = this._lineNumber.toString(); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; lineNumberHTMLNode.style.display = 'inline-block'; lineNumberHTMLNode.style.textAlign = 'center'; - this._editor.applyFontInfo(lineNumberHTMLNode); lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; + this._editor.applyFontInfo(lineNumberHTMLNode); root.appendChild(lineNumberHTMLNode); root.appendChild(lineHTMLNode); - if (this.position) { - root.style.position = 'absolute'; - root.style.top = this.position.toString() + 'px'; - root.style.width = '100%'; - } - root.style.zIndex = this.zIndex.toString(); + root.style.zIndex = this._zIndex.toString(); root.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + // Last line of sticky scroll + if (this._position) { + root.style.position = 'absolute'; + root.style.top = this._position + 'px'; + root.style.width = '100%'; + } return root; } } -export interface IStickyScrollWidgetStyles { - stickyScrollBackground?: Color; - stickyScrollForeground?: Color; - stickyScrollHoverForeground?: Color; - stickyScrollFocusForeground?: Color; - stickyScrollFocusAndSelectionForeground?: Color; -} - class StickyScrollWidget implements IOverlayWidget { - allowEditorOverflow?: boolean | undefined; - suppressMouseDown?: boolean | undefined; - arrayOfCodeLines: StickyScrollCodeLine[] = []; - readonly rootDomNode: HTMLElement = document.createElement('div'); + private readonly arrayOfCodeLines: StickyScrollCodeLine[] = []; + private readonly rootDomNode: HTMLElement = document.createElement('div'); - constructor(public readonly _editor: ICodeEditor, public readonly _themeService: IThemeService) { + constructor(public readonly _editor: ICodeEditor) { this.rootDomNode = document.createElement('div'); this.rootDomNode.style.width = '100%'; } + get codeLineCount() { + return this.arrayOfCodeLines.length; + } + pushCodeLine(codeLine: StickyScrollCodeLine) { this.arrayOfCodeLines.push(codeLine); } @@ -288,7 +248,7 @@ class StickyScrollWidget implements IOverlayWidget { } emptyRootNode() { - this.arrayOfCodeLines = []; + this.arrayOfCodeLines.length = 0; dom.clearNode(this.rootDomNode); } @@ -297,7 +257,7 @@ class StickyScrollWidget implements IOverlayWidget { } getDomNode(): HTMLElement { - this.rootDomNode.style.zIndex = '3'; + this.rootDomNode.style.zIndex = '2'; return this.rootDomNode; } From 7f84501e328963839a50a224bcb9cc8841f46ee1 Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 22 Jul 2022 18:54:19 +0200 Subject: [PATCH 011/179] allow-list `stickyScroll` as tt-policy creator --- src/tsec.exemptions.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tsec.exemptions.json b/src/tsec.exemptions.json index 0bc41dc4d7e..7ae1cd574e0 100644 --- a/src/tsec.exemptions.json +++ b/src/tsec.exemptions.json @@ -15,6 +15,7 @@ "vs/base/browser/defaultWorkerFactory.ts", "vs/base/worker/workerMain.ts", "vs/editor/contrib/markdownRenderer/browser/markdownRenderer.ts", + "vs/editor/contrib/stickyScroll/browser/stickyScroll.ts", "vs/editor/browser/view/domLineBreaksComputer.ts", "vs/editor/browser/view/viewLayer.ts", "vs/editor/browser/widget/diffEditorWidget.ts", From afd5cc898fd77e9961c3bb3b68b983aca4a667a8 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Fri, 22 Jul 2022 21:58:16 +0200 Subject: [PATCH 012/179] Solved the problem where duplicate lines were appear on sticky scrolling --- .../stickyScroll/browser/stickyScroll.ts | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 32c4fba4ee7..e5078405699 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -14,6 +14,7 @@ import * as dom from 'vs/base/browser/dom'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { SymbolKind } from 'vs/editor/common/languages'; const enum ScrollDirection { Down = 0, @@ -78,23 +79,40 @@ class StickyScrollController implements IEditorContribution { private _findLineRanges(outlineElement: OutlineElement, depth: number) { if (outlineElement?.children.size) { + let didRecursion: boolean = false; for (const outline of outlineElement?.children.values()) { - depth++; - this._findLineRanges(outline, depth); + const kind: SymbolKind = outline.symbol.kind; + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { + didRecursion = true; + this._findLineRanges(outline, depth + 1); + } + } + if (!didRecursion) { + this._addOutlineRanges(outlineElement, depth); } } else { - let currentStartLine: number | undefined = 0; - let currentEndLine: number | undefined = 0; - while (outlineElement) { + this._addOutlineRanges(outlineElement, depth); + } + } + + private _addOutlineRanges(outlineElement: OutlineElement, depth: number) { + let currentStartLine: number | undefined = 0; + let currentEndLine: number | undefined = 0; + while (outlineElement) { + const kind: SymbolKind = outlineElement.symbol.kind; + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { currentStartLine = outlineElement?.symbol.range.startLineNumber as number; currentEndLine = outlineElement?.symbol.range.endLineNumber as number; - this._ranges.push([currentStartLine, currentEndLine, depth]); - depth--; - if (outlineElement.parent instanceof OutlineElement) { - outlineElement = outlineElement.parent; - } else { - break; + const alreadyAdded = this._ranges.some(array => (array[0] === currentStartLine && array[1] === currentEndLine)); + if (!alreadyAdded) { + this._ranges.push([currentStartLine, currentEndLine, depth]); } + depth--; + } + if (outlineElement.parent instanceof OutlineElement) { + outlineElement = outlineElement.parent; + } else { + break; } } } From 2705b50c359351e60a17c3bf24724e281e360a2e Mon Sep 17 00:00:00 2001 From: Letu Ren Date: Mon, 25 Jul 2022 00:15:47 +0800 Subject: [PATCH 013/179] Replace the deprecated canceled with Cancellation Error. Signed-off-by: Letu Ren --- src/vs/platform/request/node/requestService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index 640526f89a9..fd568328255 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -9,7 +9,7 @@ import { parse as parseUrl } from 'url'; import { Promises } from 'vs/base/common/async'; import { streamToBufferReadableStream } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { canceled } from 'vs/base/common/errors'; +import { CancellationError } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; import * as streams from 'vs/base/common/stream'; import { isBoolean, isNumber } from 'vs/base/common/types'; @@ -170,7 +170,7 @@ export class RequestService extends Disposable implements IRequestService { token.onCancellationRequested(() => { req.abort(); - e(canceled()); + e(new CancellationError()); }); }); } From 5f885d701d200554f15fcad540539aa22f8a5efe Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Sun, 24 Jul 2022 23:15:44 +0200 Subject: [PATCH 014/179] Aligned the number in the margin, smooth scrolling attained, added lighter color onhover --- .../stickyScroll/browser/stickyScroll.ts | 72 +++++++++++++------ src/vs/platform/theme/common/colorRegistry.ts | 1 + 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index e5078405699..37c781b3c4a 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -144,7 +144,6 @@ class StickyScrollController implements IEditorContribution { const lineHeight = this._editor.getOption(EditorOption.lineHeight); const model = this._editor.getModel(); - const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight; const scrollTop = this._editor.getScrollTop(); let scrollDirection: ScrollDirection; @@ -155,19 +154,26 @@ class StickyScrollController implements IEditorContribution { } this._lastScrollPosition = scrollTop; + const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight + 1; this.stickyScrollWidget.emptyRootNode(); - // TODO @Aiday: Find a way to iterate over only the ranges of interest, the position at which you start, use binary search + const beginningLinesConsidered = new Set(); for (const [start, end, depth] of this._ranges) { - if (this._editor.getScrollTop() + depth * lineHeight >= end * lineHeight && this._editor.getScrollTop() + depth * lineHeight < (end + 1) * lineHeight) { - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + end * lineHeight - this._editor.getScrollTop() - depth * lineHeight)); - } else if (this._editor.getScrollTop() + depth * lineHeight >= (end - 1) * lineHeight && this._editor.getScrollTop() + depth * lineHeight < end * lineHeight) { - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - } else if (scrollDirection === ScrollDirection.Down && currentScrollTop >= (start - 1) * lineHeight && currentScrollTop < (end - 1) * lineHeight) { - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - } else if (scrollDirection === ScrollDirection.Up && currentScrollTop >= start * lineHeight && currentScrollTop < (end - 1) * lineHeight) { - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + if (!beginningLinesConsidered.has(start)) { + if (this._editor.getScrollTop() + (depth - 1) * lineHeight + 1 >= (end - 1) * lineHeight && this._editor.getScrollTop() + (depth - 1) * lineHeight < end * lineHeight - 2) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + end * lineHeight - this._editor.getScrollTop() - depth * lineHeight)); + break; + } + else if (scrollDirection === ScrollDirection.Down && currentScrollTop > (start - 1) * lineHeight && currentScrollTop < end * lineHeight) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } else if (scrollDirection === ScrollDirection.Up && currentScrollTop >= start * lineHeight && currentScrollTop <= end * lineHeight) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } } } + this.stickyScrollWidget.updateRootNode(); } @@ -188,8 +194,6 @@ class StickyScrollCodeLine { const root: HTMLElement = document.createElement('div'); const modifiedLine = this._line.replace(/\s/g, '\xa0'); - // TODO @Aiday: use _getViewModel() or other method - // TODO @Aiday: bracket decorations in RenderLineInput const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRanges()[0], this._lineNumber); const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, @@ -206,24 +210,45 @@ class StickyScrollCodeLine { newLine = sb.build(); } - const lineHTMLNode = document.createElement('span'); + const lineHTMLNode = document.createElement('div'); + lineHTMLNode.style.paddingLeft = this._editor.getLayoutInfo().contentLeft - this._editor.getLayoutInfo().lineNumbersLeft - this._editor.getLayoutInfo().lineNumbersWidth + 'px'; + lineHTMLNode.style.float = 'left'; + lineHTMLNode.style.width = this._editor.getLayoutInfo().width - this._editor.getLayoutInfo().contentLeft + 'px'; + lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; lineHTMLNode.innerHTML = newLine as string; - // TODO @Aiday: needs to be disposed, add one listener to sticky scroll widget, e has property target with direct element or child of the element + const lineNumberHTMLNode = document.createElement('div'); + lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; + + const innerLineNumberHTML = document.createElement('div'); + innerLineNumberHTML.innerText = this._lineNumber.toString(); + innerLineNumberHTML.style.paddingLeft = this._editor.getLayoutInfo().lineNumbersLeft.toString() + 'px'; + innerLineNumberHTML.style.width = this._editor.getLayoutInfo().lineNumbersWidth.toString() + 'px'; + innerLineNumberHTML.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + innerLineNumberHTML.style.textAlign = 'right'; + innerLineNumberHTML.style.float = 'left'; + lineNumberHTMLNode.appendChild(innerLineNumberHTML); + lineHTMLNode.onclick = e => { e.stopPropagation(); e.preventDefault(); this._editor.revealLine(this._lineNumber); }; - this._editor.applyFontInfo(lineHTMLNode); + lineHTMLNode.onmouseover = e => { + innerLineNumberHTML.style.background = `var(--vscode-stickyScrollHover-background)`; + lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScrollHover-background)`; + innerLineNumberHTML.style.cursor = `pointer`; + lineHTMLNode.style.cursor = `pointer`; + }; + lineHTMLNode.onmouseleave = e => { + innerLineNumberHTML.style.background = `var(--vscode-stickyScroll-background)`; + lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + }; - const lineNumberHTMLNode = document.createElement('span'); - lineNumberHTMLNode.innerText = this._lineNumber.toString(); - lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; - lineNumberHTMLNode.style.display = 'inline-block'; - lineNumberHTMLNode.style.textAlign = 'center'; - lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; - this._editor.applyFontInfo(lineNumberHTMLNode); + this._editor.applyFontInfo(lineHTMLNode); + this._editor.applyFontInfo(innerLineNumberHTML); root.appendChild(lineNumberHTMLNode); root.appendChild(lineHTMLNode); @@ -231,7 +256,7 @@ class StickyScrollCodeLine { root.style.zIndex = this._zIndex.toString(); root.style.backgroundColor = `var(--vscode-stickyScroll-background)`; - // Last line of sticky scroll + // Special case for last line of sticky scroll if (this._position) { root.style.position = 'absolute'; root.style.top = this._position + 'px'; @@ -276,6 +301,7 @@ class StickyScrollWidget implements IOverlayWidget { getDomNode(): HTMLElement { this.rootDomNode.style.zIndex = '2'; + this.rootDomNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; return this.rootDomNode; } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 9fd9c3c7a44..83ad45a9fad 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -318,6 +318,7 @@ export const editorForeground = registerColor('editor.foreground', { light: '#33 * Sticky scroll */ export const stickyScrollBackground = registerColor('stickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('stickyScrollBackground', "Sticky scroll background color")); +export const stickyScrollHoverBackground = registerColor('stickyScrollHover.background', { light: darken(editorBackground, 0.4), dark: lighten(editorBackground, 0.4), hcDark: lighten(editorBackground, 0.4), hcLight: darken(editorBackground, 0.4) }, nls.localize('stickyScrollHoverBackground', "Sticky scroll on hover background color")); /** * Editor widgets From b5f77d110fb76cbe28c8f473865fe47fb98f4d1b Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Sun, 24 Jul 2022 18:14:07 -0700 Subject: [PATCH 015/179] fixed more styling and dom focus on widget --- .../codeAction/browser/codeActionMenu.ts | 26 +++++++++++++++++++ .../codeAction/browser/media/action.css | 1 + 2 files changed, 27 insertions(+) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index a2d66113907..ecfed31e9f5 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -146,6 +146,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { private focusedEnabledItem: number | undefined; private currSelectedItem: number = 0; private hasSeperator: boolean = false; + private block: HTMLElement | null = null; public static readonly ID: string = 'editor.contrib.codeActionMenu'; @@ -203,6 +204,21 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { const renderDisposables = new DisposableStore(); const renderMenu = document.createElement('div'); + // Render invisible div to block mouse interaction in the rest of the UI + const menuBlock = document.createElement('div'); + this.block = element.appendChild(menuBlock); + this.block.classList.add('context-view-block'); + this.block.style.position = 'fixed'; + this.block.style.cursor = 'initial'; + this.block.style.left = '0'; + this.block.style.top = '0'; + this.block.style.width = '100%'; + this.block.style.height = '100%'; + this.block.style.zIndex = '-1'; + + // TODO@Steven: this is never getting disposed + dom.addDisposableListener(this.block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation()); + renderMenu.id = 'codeActionMenuWidget'; renderMenu.classList.add('codeActionMenuWidget'); @@ -267,9 +283,19 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.currSelectedItem = this.viewItems[0].index; this.codeActionList.value.setFocus([this.currSelectedItem]); + + // const focusTracker = this._register(dom.trackFocus(element)); + // this._register(focusTracker.onDidBlur(() => { + // if (dom.getActiveElement() === element || !dom.isAncestor(dom.getActiveElement(), element)) { + // this.hideCodeActionWidget(); + // } + // })); + // List Focus this.codeActionList.value.domFocus(); const focusTracker = dom.trackFocus(element); + + element.focus(); const blurListener = focusTracker.onDidBlur(() => { this.hideCodeActionWidget(); // this._contextViewService.hideContextView({ source: this }); diff --git a/src/vs/editor/contrib/codeAction/browser/media/action.css b/src/vs/editor/contrib/codeAction/browser/media/action.css index 4068820413d..a32d77522f4 100644 --- a/src/vs/editor/contrib/codeAction/browser/media/action.css +++ b/src/vs/editor/contrib/codeAction/browser/media/action.css @@ -18,6 +18,7 @@ border-color: none; background-color: var(--vscode-menu-background); color: var(--vscode-menu-foreground); + box-shadow: rgb(0,0,0, 16%) 0px 2px 8px; } .codeActionMenuWidget .monaco-list:not(.element-focused):focus:before { From 8884ca80b65b19b8743785c90b4407ce45d7e0e1 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Sun, 24 Jul 2022 22:57:27 -0700 Subject: [PATCH 016/179] fixing #145058 and code clean up --- .../codeAction/browser/codeActionMenu.ts | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index ecfed31e9f5..9b73033541f 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -279,17 +279,13 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.codeActionList.value?.layout(height, maxWidth); // List selection - this.focusedEnabledItem = 0; - this.currSelectedItem = this.viewItems[0].index; - this.codeActionList.value.setFocus([this.currSelectedItem]); - - - // const focusTracker = this._register(dom.trackFocus(element)); - // this._register(focusTracker.onDidBlur(() => { - // if (dom.getActiveElement() === element || !dom.isAncestor(dom.getActiveElement(), element)) { - // this.hideCodeActionWidget(); - // } - // })); + if (this.viewItems.length <= 1 && this.viewItems[0].title === 'Learn more about JS/TS refactorings') { + this.currSelectedItem = 0; + } else { + this.focusedEnabledItem = 0; + this.currSelectedItem = this.viewItems[0].index; + this.codeActionList.value.setFocus([this.currSelectedItem]); + } // List Focus this.codeActionList.value.domFocus(); @@ -310,7 +306,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusPrevious() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems[0].index; - } else if (this.viewItems.length <= 1) { + } else if (this.viewItems.length <= 1 && this.viewItems[0].title !== 'Learn more about JS/TS refactorings') { return false; } @@ -333,7 +329,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusNext() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems.length - 1; - } else if (this.viewItems.length <= 1) { + } else if (this.viewItems.length <= 1 && this.viewItems[0].title !== 'Learn more about JS/TS refactorings') { return false; } From 2692ae4f7f21ffcf0d8caefb0f32a5ece42bba67 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Sun, 24 Jul 2022 23:27:20 -0700 Subject: [PATCH 017/179] added shortcuts for quickfix menu --- .../editor/contrib/codeAction/browser/codeActionCommands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 62647863cf5..f1c96816b3b 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -536,7 +536,7 @@ registerEditorCommand(new CodeActionContribution({ kbOpts: { weight: weight + 100000, primary: KeyCode.UpArrow, - secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow], + secondary: [KeyMod.CtrlCmd | KeyCode.KeyK], } })); @@ -549,7 +549,7 @@ registerEditorCommand(new CodeActionContribution({ kbOpts: { weight: weight + 100000, primary: KeyCode.DownArrow, - secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow], + secondary: [KeyMod.CtrlCmd | KeyCode.KeyJ], } })); From 21ca44d35b0291a677188c70c70950aec47cb3ce Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 25 Jul 2022 09:27:00 +0200 Subject: [PATCH 018/179] show remote indicator in web with websocket factory (#155734) --- src/vs/workbench/contrib/remote/browser/remoteIndicator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts index 91045b0fb95..bd8178fcec7 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts @@ -281,7 +281,7 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr } // Show for remote windows on the desktop, but not when in code server web - if (this.remoteAuthority && !isWeb) { + if (this.remoteAuthority && (!isWeb || this.environmentService.options?.webSocketFactory)) { const hostLabel = this.labelService.getHostLabel(Schemas.vscodeRemote, this.remoteAuthority) || this.remoteAuthority; switch (this.connectionState) { case 'initializing': From 2cae0a1b9b05fef80259181b7b70c1db289b6587 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 09:43:53 +0200 Subject: [PATCH 019/179] Added brace and bracket colorization --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 37c781b3c4a..0616be4385b 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -15,6 +15,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { SymbolKind } from 'vs/editor/common/languages'; +import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; const enum ScrollDirection { Down = 0, @@ -194,10 +195,10 @@ class StickyScrollCodeLine { const root: HTMLElement = document.createElement('div'); const modifiedLine = this._line.replace(/\s/g, '\xa0'); - const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRanges()[0], this._lineNumber); - + const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); + const actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, - lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, [], lineRenderingData.tabSize, + lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 500, 'none', true, true, null); const sb = createStringBuilder(2000); From 2390d2afdccaca549772359c2e3346679274ec88 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Jul 2022 10:45:17 +0200 Subject: [PATCH 020/179] editors - only warn for app root edits when running built product (#156030) --- src/vs/workbench/electron-sandbox/window.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 54779255d79..9e5dac68fbf 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -137,8 +137,11 @@ export class NativeWindow extends Disposable { // Touchbar this.updateTouchbarMenu(); - // Potential data loss - this.notifyOnAppRootEditors(appRootUri); + // Potential data loss when editing files + // from within the installation app root + if (this.environmentService.isBuilt) { + this.notifyOnAppRootEditors(appRootUri); + } })); // prevent opening a real URL inside the window From e7a5e2f09abe25031e8be4af0ec8690420570df6 Mon Sep 17 00:00:00 2001 From: Ping <5123601+pingren@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:07:47 +0800 Subject: [PATCH 021/179] Fix tab position when wrapping tabs (#156116) Fixes https://github.com/microsoft/vscode/issues/154432 --- src/vs/workbench/browser/parts/editor/tabsTitleControl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index facf063df26..44e9ed15b06 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -1154,9 +1154,9 @@ export class TabsTitleControl extends TitleControl { tabContainer.classList.toggle(`sticky-${option}`, isTabSticky && options.pinnedTabSizing === option); } - // Sticky compact/shrink tabs need a position to remain at their location + // If not wrapping tabs, sticky compact/shrink tabs need a position to remain at their location // when scrolling to stay in view (requirement for position: sticky) - if (isTabSticky && options.pinnedTabSizing !== 'normal') { + if (!options.wrapTabs && isTabSticky && options.pinnedTabSizing !== 'normal') { let stickyTabWidth = 0; switch (options.pinnedTabSizing) { case 'compact': From cd41274a1af830bb64c8e704f76874d3651fa78b Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 11:18:14 +0200 Subject: [PATCH 022/179] Fix: When two outline elements start on the same line, only the outer one is considered --- .../contrib/stickyScroll/browser/stickyScroll.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 0616be4385b..7846070e7ad 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -33,7 +33,7 @@ class StickyScrollController implements IEditorContribution { private readonly _store: DisposableStore = new DisposableStore(); private readonly _sessionStore: DisposableStore = new DisposableStore(); - private _ranges: number[][] = []; + private _ranges: any[][] = []; private _cts: CancellationTokenSource | undefined; private _lastScrollPosition: number = -1; @@ -99,6 +99,7 @@ class StickyScrollController implements IEditorContribution { private _addOutlineRanges(outlineElement: OutlineElement, depth: number) { let currentStartLine: number | undefined = 0; let currentEndLine: number | undefined = 0; + while (outlineElement) { const kind: SymbolKind = outlineElement.symbol.kind; if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { @@ -132,7 +133,11 @@ class StickyScrollController implements IEditorContribution { } } this._ranges = this._ranges.sort(function (a, b) { - return a[0] - b[0]; + if (a[0] !== b[0]) { + return a[0] - b[0]; + } else { + return b[1] - a[1]; + } }); } } @@ -158,7 +163,8 @@ class StickyScrollController implements IEditorContribution { const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight + 1; this.stickyScrollWidget.emptyRootNode(); const beginningLinesConsidered = new Set(); - for (const [start, end, depth] of this._ranges) { + for (const [index, arr] of this._ranges.entries()) { + const [start, end, depth] = arr; if (!beginningLinesConsidered.has(start)) { if (this._editor.getScrollTop() + (depth - 1) * lineHeight + 1 >= (end - 1) * lineHeight && this._editor.getScrollTop() + (depth - 1) * lineHeight < end * lineHeight - 2) { beginningLinesConsidered.add(start); @@ -172,6 +178,8 @@ class StickyScrollController implements IEditorContribution { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); } + } else { + this._ranges.splice(index, 1); } } From 55a267af739ab430a62b56b9e403fd61d9fdbfc7 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 25 Jul 2022 11:19:51 +0200 Subject: [PATCH 023/179] Move openTunnel in to workspace namespace (#156123) --- src/vs/workbench/browser/web.api.ts | 22 +++++++------- src/vs/workbench/browser/web.factory.ts | 13 +++++++- src/vs/workbench/browser/web.main.ts | 40 +++++++++++++------------ 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/browser/web.api.ts b/src/vs/workbench/browser/web.api.ts index 637b1af74cd..258b6880e1a 100644 --- a/src/vs/workbench/browser/web.api.ts +++ b/src/vs/workbench/browser/web.api.ts @@ -98,6 +98,18 @@ export interface IWorkbench { ): Promise; }; + workspace: { + /** + * Forwards a port. If the current embedder implements a tunnelFactory then that will be used to make the tunnel. + * By default, openTunnel only support localhost; however, a 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. + */ + openTunnel(tunnelOptions: ITunnelOptions): Thenable; + }; + /** * Triggers shutdown of the workbench programmatically. After this method is * called, the workbench is not usable anymore and the page needs to reload @@ -110,16 +122,6 @@ export interface IWorkbench { * has been persisted. */ shutdown: () => Promise; - - /** - * Forwards a port. If the current embedder implements a tunnelFactory then that will be used to make the tunnel. - * By default, openTunnel only support localhost; however, a 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. - */ - openTunnel(tunnelOptions: ITunnelOptions): Thenable; } export interface IWorkbenchConstructionOptions { diff --git a/src/vs/workbench/browser/web.factory.ts b/src/vs/workbench/browser/web.factory.ts index 993aa0ce071..eef12507e51 100644 --- a/src/vs/workbench/browser/web.factory.ts +++ b/src/vs/workbench/browser/web.factory.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbench, IWorkbenchConstructionOptions, Menu } from 'vs/workbench/browser/web.api'; +import { ITunnel, ITunnelOptions, IWorkbench, IWorkbenchConstructionOptions, Menu } from 'vs/workbench/browser/web.api'; import { BrowserMain } from 'vs/workbench/browser/web.main'; import { URI } from 'vs/base/common/uri'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -152,3 +152,14 @@ export namespace window { return workbench.window.withProgress(options, task); } } + +export namespace workspace { + + /** + * {@linkcode IWorkbench.workspace IWorkbench.workspace.openTunnel} + */ + export async function openTunnel(tunnelOptions: ITunnelOptions): Promise { + const workbench = await workbenchPromise.p; + return workbench.workspace.openTunnel(tunnelOptions); + } +} diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index d0791572ccf..0cdc6ba01d3 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -171,26 +171,28 @@ export class BrowserMain extends Disposable { window: { withProgress: (options, task) => progessService.withProgress(options, task) }, - shutdown: () => lifecycleService.shutdown(), - openTunnel: async (tunnelOptions) => { - const tunnel = await remoteExplorerService.forward({ - remote: tunnelOptions.remoteAddress, - local: tunnelOptions.localAddressPort, - name: tunnelOptions.label, - source: { - source: TunnelSource.Extension, - description: labelService.getHostLabel(Schemas.vscodeRemote, this.configuration.remoteAuthority) - }, - elevateIfNeeded: false - }); - if (!tunnel) { - throw new Error('cannot open tunnel'); - } + workspace: { + openTunnel: async (tunnelOptions) => { + const tunnel = await remoteExplorerService.forward({ + remote: tunnelOptions.remoteAddress, + local: tunnelOptions.localAddressPort, + name: tunnelOptions.label, + source: { + source: TunnelSource.Extension, + description: labelService.getHostLabel(Schemas.vscodeRemote, this.configuration.remoteAuthority) + }, + elevateIfNeeded: false + }); + if (!tunnel) { + throw new Error('cannot open tunnel'); + } - return new class extends DisposableTunnel implements ITunnel { - override localAddress!: string; - }({ port: tunnel.tunnelRemotePort, host: tunnel.tunnelRemoteHost }, tunnel.localAddress, () => tunnel.dispose()); - } + return new class extends DisposableTunnel implements ITunnel { + override localAddress!: string; + }({ port: tunnel.tunnelRemotePort, host: tunnel.tunnelRemoteHost }, tunnel.localAddress, () => tunnel.dispose()); + } + }, + shutdown: () => lifecycleService.shutdown() }; }); } From 4ca6be6e143f53d10e442d02fc1d3a485e1a943c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Jul 2022 11:20:21 +0200 Subject: [PATCH 024/179] update licenses (#156124) --- ThirdPartyNotices.txt | 6 +++--- cglicenses.json | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 9c691ad41e3..5c36a652b4b 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -31,7 +31,7 @@ This project incorporates components from the projects listed below. The origina 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.17 (https://github.com/jeff-hykin/better-cpp-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) @@ -47,7 +47,7 @@ This project incorporates components from the projects listed below. The origina 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.10.1 (https://github.com/microsoft/vscode-mssql) +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) @@ -73,7 +73,7 @@ This project incorporates components from the projects listed below. The origina 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.11.0 (https://github.com/emilast/vscode-logfile-highlighter) +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) diff --git a/cglicenses.json b/cglicenses.json index 4ce1e015e46..5612be62696 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -173,5 +173,32 @@ "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "SOFTWARE" ] + }, + { + // Reason: Waiting for https://github.com/microsoft/vscode-markdown-languageservice/pull/9 + "name": "vscode-markdown-languageservice", + "fullLicenseText": [ + "MIT License", + "", + "Copyright (c) Microsoft Corporation.", + "", + "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" + ] } ] From a5a44c5de367a54d469a4802ad365a81e025bec4 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 25 Jul 2022 11:40:46 +0200 Subject: [PATCH 025/179] Remote workspace from Ports view (#156130) Part of #153513 --- src/vs/workbench/contrib/remote/browser/tunnelView.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index f3d20816324..001c769f36a 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -1067,7 +1067,6 @@ export class TunnelPanelDescriptor implements IViewDescriptor { readonly ctorDescriptor: SyncDescriptor; readonly canToggleVisibility = true; readonly hideByDefault = false; - readonly workspace = true; // group is not actually used for views that are not extension contributed. Use order instead. readonly group = 'details@0'; // -500 comes from the remote explorer viewOrderDelegate From 77623768be8240b1ab6f48382a9cf29e4eb21f0b Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Mon, 25 Jul 2022 11:43:02 +0200 Subject: [PATCH 026/179] Allow to pass in a snapshot in `setValue` (#156128) Fixes #153922: Allow to pass in a snapshot in `setValue` --- src/vs/editor/common/model.ts | 12 ++++++++---- src/vs/editor/common/model/textModel.ts | 23 +++++++++++++---------- src/vs/monaco.d.ts | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index 354026fdcb5..b6361586bd8 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -528,13 +528,18 @@ export const enum TrackedRangeStickiness { * Text snapshot that works like an iterator. * Will try to return chunks of roughly ~64KB size. * Will return null when finished. - * - * @internal */ export interface ITextSnapshot { read(): string | null; } +/** + * @internal + */ +export function isITextSnapshot(obj: any): obj is ITextSnapshot { + return (obj && typeof obj.read === 'function'); +} + /** * A model. */ @@ -610,7 +615,7 @@ export interface ITextModel { /** * Replace the entire text buffer value contained in this model. */ - setValue(newValue: string): void; + setValue(newValue: string | ITextSnapshot): void; /** * Get the text stored in this model. @@ -624,7 +629,6 @@ export interface ITextModel { * Get the text stored in this model. * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed. * @return The text snapshot (it is safe to consume it asynchronously). - * @internal */ createSnapshot(preserveBOM?: boolean): ITextSnapshot; diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 690a2eab09a..59675e6d0c6 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -44,12 +44,8 @@ import { ITokenizationTextModelPart } from 'vs/editor/common/tokenizationTextMod import { IColorTheme, ThemeColor } from 'vs/platform/theme/common/themeService'; import { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo'; -function createTextBufferBuilder() { - return new PieceTreeTextBufferBuilder(); -} - export function createTextBufferFactory(text: string): model.ITextBufferFactory { - const builder = createTextBufferBuilder(); + const builder = new PieceTreeTextBufferBuilder(); builder.acceptChunk(text); return builder.finish(); } @@ -65,7 +61,7 @@ export function createTextBufferFactoryFromStream(stream: ITextStream): Promise< export function createTextBufferFactoryFromStream(stream: VSBufferReadableStream): Promise; export function createTextBufferFactoryFromStream(stream: ITextStream | VSBufferReadableStream): Promise { return new Promise((resolve, reject) => { - const builder = createTextBufferBuilder(); + const builder = new PieceTreeTextBufferBuilder(); let done = false; @@ -90,7 +86,7 @@ export function createTextBufferFactoryFromStream(stream: ITextStream | VSBuffer } export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapshot): model.ITextBufferFactory { - const builder = createTextBufferBuilder(); + const builder = new PieceTreeTextBufferBuilder(); let chunk: string | null; while (typeof (chunk = snapshot.read()) === 'string') { @@ -100,8 +96,15 @@ export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapsho return builder.finish(); } -export function createTextBuffer(value: string | model.ITextBufferFactory, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable } { - const factory = (typeof value === 'string' ? createTextBufferFactory(value) : value); +export function createTextBuffer(value: string | model.ITextBufferFactory | model.ITextSnapshot, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable } { + let factory: model.ITextBufferFactory; + if (typeof value === 'string') { + factory = createTextBufferFactory(value); + } else if (model.isITextSnapshot(value)) { + factory = createTextBufferFactoryFromSnapshot(value); + } else { + factory = value; + } return factory.create(defaultEOL); } @@ -424,7 +427,7 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change)); } - public setValue(value: string): void { + public setValue(value: string | model.ITextSnapshot): void { this._assertNotDisposed(); if (value === null) { // There's nothing to do diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index f608381f9e4..de84db6407d 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1738,6 +1738,15 @@ declare namespace monaco.editor { GrowsOnlyWhenTypingAfter = 3 } + /** + * Text snapshot that works like an iterator. + * Will try to return chunks of roughly ~64KB size. + * Will return null when finished. + */ + export interface ITextSnapshot { + read(): string | null; + } + /** * A model. */ @@ -1769,7 +1778,7 @@ declare namespace monaco.editor { /** * Replace the entire text buffer value contained in this model. */ - setValue(newValue: string): void; + setValue(newValue: string | ITextSnapshot): void; /** * Get the text stored in this model. * @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`. @@ -1777,6 +1786,12 @@ declare namespace monaco.editor { * @return The text. */ getValue(eol?: EndOfLinePreference, preserveBOM?: boolean): string; + /** + * Get the text stored in this model. + * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed. + * @return The text snapshot (it is safe to consume it asynchronously). + */ + createSnapshot(preserveBOM?: boolean): ITextSnapshot; /** * Get the length of the text stored in this model. */ From f9637d48404eefbd7d752f128c96890c3c7b5efb Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 25 Jul 2022 12:14:06 +0200 Subject: [PATCH 027/179] Adds commands AcceptAllInput1 and AcceptAllInput2 (#156047) * Adds commands AcceptAllInput1 and AcceptAllInput2 * fix compile Co-authored-by: Benjamin Pasero --- .../mergeEditor/browser/commands/commands.ts | 172 +++++++++++------- .../browser/mergeEditor.contribution.ts | 5 +- .../mergeEditor/browser/view/viewModel.ts | 13 ++ 3 files changed, 120 insertions(+), 70 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 3c028ec8ebd..36870ec2433 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -7,17 +7,37 @@ import { Codicon } from 'vs/base/common/codicons'; import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; -import { Action2, MenuId } from 'vs/platform/actions/common/actions'; +import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { IResourceMergeEditorInput } from 'vs/workbench/common/editor'; -import { MergeEditorInput, MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; +import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; +import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; import { ctxIsMergeEditor, ctxMergeEditorLayout } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +abstract class MergeEditorAction extends Action2 { + constructor(desc: Readonly) { + super(desc); + } + + run(accessor: ServicesAccessor): void { + const { activeEditorPane } = accessor.get(IEditorService); + if (activeEditorPane instanceof MergeEditor) { + const vm = activeEditorPane.viewModel.get(); + if (!vm) { + return; + } + this.runWithViewModel(vm, accessor); + } + } + + abstract runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void; +} + export class OpenMergeEditor extends Action2 { constructor() { super({ @@ -167,7 +187,7 @@ const mergeEditorCategory: ILocalizedString = { original: 'Merge Editor', }; -export class OpenResultResource extends Action2 { +export class OpenResultResource extends MergeEditorAction { constructor() { super({ id: 'merge.openResult', @@ -187,15 +207,13 @@ export class OpenResultResource extends Action2 { }); } - async run(accessor: ServicesAccessor): Promise { + override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { const editorService = accessor.get(IEditorService); - if (editorService.activeEditor instanceof MergeEditorInput) { - editorService.openEditor({ resource: editorService.activeEditor.result }); - } + editorService.openEditor({ resource: viewModel.model.result.uri }); } } -export class GoToNextConflict extends Action2 { +export class GoToNextConflict extends MergeEditorAction { constructor() { super({ id: 'merge.goToNextConflict', @@ -218,15 +236,12 @@ export class GoToNextConflict extends Action2 { }); } - run(accessor: ServicesAccessor): void { - const { activeEditorPane } = accessor.get(IEditorService); - if (activeEditorPane instanceof MergeEditor) { - activeEditorPane.viewModel.get()?.goToNextModifiedBaseRange(true); - } + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.goToNextModifiedBaseRange(true); } } -export class GoToPreviousConflict extends Action2 { +export class GoToPreviousConflict extends MergeEditorAction { constructor() { super({ id: 'merge.goToPreviousConflict', @@ -252,15 +267,12 @@ export class GoToPreviousConflict extends Action2 { }); } - run(accessor: ServicesAccessor): void { - const { activeEditorPane } = accessor.get(IEditorService); - if (activeEditorPane instanceof MergeEditor) { - activeEditorPane.viewModel.get()?.goToPreviousModifiedBaseRange(true); - } + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.goToPreviousModifiedBaseRange(true); } } -export class ToggleActiveConflictInput1 extends Action2 { +export class ToggleActiveConflictInput1 extends MergeEditorAction { constructor() { super({ id: 'merge.toggleActiveConflictInput1', @@ -277,19 +289,12 @@ export class ToggleActiveConflictInput1 extends Action2 { }); } - run(accessor: ServicesAccessor): void { - const { activeEditorPane } = accessor.get(IEditorService); - if (activeEditorPane instanceof MergeEditor) { - const vm = activeEditorPane.viewModel.get(); - if (!vm) { - return; - } - vm.toggleActiveConflict(1); - } + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.toggleActiveConflict(1); } } -export class ToggleActiveConflictInput2 extends Action2 { +export class ToggleActiveConflictInput2 extends MergeEditorAction { constructor() { super({ id: 'merge.toggleActiveConflictInput2', @@ -306,19 +311,12 @@ export class ToggleActiveConflictInput2 extends Action2 { }); } - run(accessor: ServicesAccessor): void { - const { activeEditorPane } = accessor.get(IEditorService); - if (activeEditorPane instanceof MergeEditor) { - const vm = activeEditorPane.viewModel.get(); - if (!vm) { - return; - } - vm.toggleActiveConflict(2); - } + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.toggleActiveConflict(2); } } -export class CompareInput1WithBaseCommand extends Action2 { +export class CompareInput1WithBaseCommand extends MergeEditorAction { constructor() { super({ id: 'mergeEditor.compareInput1WithBase', @@ -336,14 +334,14 @@ export class CompareInput1WithBaseCommand extends Action2 { menu: { id: MenuId.MergeInput1Toolbar } }); } - run(accessor: ServicesAccessor, ...args: unknown[]): void { - const editorService = accessor.get(IEditorService); + + override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { const commandService = accessor.get(ICommandService); - mergeEditorCompare(editorService, commandService, 1); + mergeEditorCompare(viewModel, commandService, 1); } } -export class CompareInput2WithBaseCommand extends Action2 { +export class CompareInput2WithBaseCommand extends MergeEditorAction { constructor() { super({ id: 'mergeEditor.compareInput2WithBase', @@ -361,32 +359,25 @@ export class CompareInput2WithBaseCommand extends Action2 { menu: { id: MenuId.MergeInput2Toolbar } }); } - run(accessor: ServicesAccessor, ...args: unknown[]): void { - const editorService = accessor.get(IEditorService); + + override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { const commandService = accessor.get(ICommandService); - mergeEditorCompare(editorService, commandService, 2); + mergeEditorCompare(viewModel, commandService, 2); } } -function mergeEditorCompare(editorService: IEditorService, commandService: ICommandService, inputNumber: 1 | 2) { - const { activeEditorPane } = editorService; - if (activeEditorPane instanceof MergeEditor) { - if (!activeEditorPane.model) { - return; - } - - const base = activeEditorPane.model.base.uri; - const input = inputNumber === 1 ? activeEditorPane.model.input1.uri : activeEditorPane.model.input2.uri; - - openDiffEditor(commandService, base, input); - } +function mergeEditorCompare(viewModel: MergeEditorViewModel, commandService: ICommandService, inputNumber: 1 | 2) { + const model = viewModel.model; + const base = model.base.uri; + const input = inputNumber === 1 ? model.input1.uri : model.input2.uri; + openDiffEditor(commandService, base, input); } function openDiffEditor(commandService: ICommandService, left: URI, right: URI, label?: string) { commandService.executeCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, left, right, label); } -export class OpenBaseFile extends Action2 { +export class OpenBaseFile extends MergeEditorAction { constructor() { super({ id: 'merge.openBaseEditor', @@ -400,15 +391,58 @@ export class OpenBaseFile extends Action2 { }); } - run(accessor: ServicesAccessor): void { + override runWithViewModel(viewModel: MergeEditorViewModel, accessor: ServicesAccessor): void { const openerService = accessor.get(IOpenerService); - const { activeEditorPane } = accessor.get(IEditorService); - if (activeEditorPane instanceof MergeEditor) { - const vm = activeEditorPane.viewModel.get(); - if (!vm) { - return; - } - openerService.open(vm.model.base.uri); - } + openerService.open(viewModel.model.base.uri); + } +} + +export class AcceptAllInput1 extends MergeEditorAction { + constructor() { + super({ + id: 'merge.acceptAllInput1', + category: mergeEditorCategory, + title: { + value: localize( + 'merge.acceptAllInput1', + 'Accept All Changes from Left' + ), + original: 'Accept All Changes from Left', + }, + f1: true, + precondition: ctxIsMergeEditor, + menu: [ + { id: MenuId.MergeInput1Toolbar, } + ] + }); + } + + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.acceptAll(1); + } +} + +export class AcceptAllInput2 extends MergeEditorAction { + constructor() { + super({ + id: 'merge.acceptAllInput2', + category: mergeEditorCategory, + title: { + value: localize( + 'merge.acceptAllInput2', + 'Accept All Changes from Right' + ), + original: 'Accept All Changes from Right', + }, + f1: true, + precondition: ctxIsMergeEditor, + menu: [ + { id: MenuId.MergeInput2Toolbar, } + ] + }); + } + + override runWithViewModel(viewModel: MergeEditorViewModel): void { + viewModel.acceptAll(2); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index c06a6e0447c..8120b688a8e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -10,7 +10,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 { CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextConflict, GoToPreviousConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, SetColumnLayout, SetMixedLayout, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; +import { AcceptAllInput1, AcceptAllInput2, CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextConflict, GoToPreviousConflict, OpenBaseFile, OpenMergeEditor, OpenResultResource, SetColumnLayout, SetMixedLayout, ToggleActiveConflictInput1, ToggleActiveConflictInput2 } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; import { MergeEditorCopyContentsToJSON, MergeEditorOpenContents } from 'vs/workbench/contrib/mergeEditor/browser/commands/devCommands'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor, MergeEditorResolverContribution, MergeEditorOpenHandlerContribution } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -51,6 +51,9 @@ registerAction2(ToggleActiveConflictInput2); registerAction2(CompareInput1WithBaseCommand); registerAction2(CompareInput2WithBaseCommand); +registerAction2(AcceptAllInput1); +registerAction2(AcceptAllInput2); + Registry .as(WorkbenchExtensions.Workbench) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts index de910cceaee..37643b3fb6b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts @@ -143,4 +143,17 @@ export class MergeEditorViewModel { ); }); } + + public acceptAll(inputNumber: 1 | 2): void { + transaction(tx => { + /** @description Toggle Active Conflict */ + for (const range of this.model.modifiedBaseRanges.get()) { + this.setState( + range, + this.model.getState(range).get().withInputValue(inputNumber, true), + tx + ); + } + }); + } } From f983ebca22c14bb687204402d8ef85fecf96049d Mon Sep 17 00:00:00 2001 From: Paul Landers Date: Mon, 25 Jul 2022 06:44:56 -0400 Subject: [PATCH 028/179] Add commands to scroll editor to top/bottom (#155861) --- src/vs/editor/browser/coreCommands.ts | 67 +++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/browser/coreCommands.ts b/src/vs/editor/browser/coreCommands.ts index ecc72a1a366..b5ab2a699e1 100644 --- a/src/vs/editor/browser/coreCommands.ts +++ b/src/vs/editor/browser/coreCommands.ts @@ -84,7 +84,7 @@ export namespace EditorScroll_ { \`\`\` * 'by': Unit to move. Default is computed based on 'to' value. \`\`\` - 'line', 'wrappedLine', 'page', 'halfPage' + 'line', 'wrappedLine', 'page', 'halfPage', 'editor' \`\`\` * 'value': Number of units to move. Default is '1'. * 'revealCursor': If 'true' reveals the cursor if it is outside view port. @@ -100,7 +100,7 @@ export namespace EditorScroll_ { }, 'by': { 'type': 'string', - 'enum': ['line', 'wrappedLine', 'page', 'halfPage'] + 'enum': ['line', 'wrappedLine', 'page', 'halfPage', 'editor'] }, 'value': { 'type': 'number', @@ -130,7 +130,8 @@ export namespace EditorScroll_ { Line: 'line', WrappedLine: 'wrappedLine', Page: 'page', - HalfPage: 'halfPage' + HalfPage: 'halfPage', + Editor: 'editor' }; /** @@ -172,6 +173,9 @@ export namespace EditorScroll_ { case RawUnit.HalfPage: unit = Unit.HalfPage; break; + case RawUnit.Editor: + unit = Unit.Editor; + break; default: unit = Unit.WrappedLine; } @@ -205,7 +209,8 @@ export namespace EditorScroll_ { Line = 1, WrappedLine = 2, Page = 3, - HalfPage = 4 + HalfPage = 4, + Editor = 5 } } @@ -1279,6 +1284,14 @@ export namespace CoreNavigationCommands { return viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber); } + if (args.unit === EditorScroll_.Unit.Editor) { + let desiredTopModelLineNumber = 0; + if (args.direction === EditorScroll_.Direction.Down) { + desiredTopModelLineNumber = viewModel.model.getLineCount() - viewModel.cursorConfig.pageSize; + } + return viewModel.viewLayout.getVerticalOffsetForLineNumber(desiredTopModelLineNumber); + } + let noOfLines: number; if (args.unit === EditorScroll_.Unit.Page) { noOfLines = viewModel.cursorConfig.pageSize * args.value; @@ -1345,6 +1358,29 @@ export namespace CoreNavigationCommands { } }); + export const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + constructor() { + super({ + id: 'scrollEditorTop', + precondition: undefined, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textInputFocus, + } + }); + } + + runCoreEditorCommand(viewModel: IViewModel, args: any): void { + EditorScroll._runEditorScroll(viewModel, args.source, { + direction: EditorScroll_.Direction.Up, + unit: EditorScroll_.Unit.Editor, + value: 1, + revealCursor: false, + select: false + }); + } + }); + export const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ @@ -1396,6 +1432,29 @@ export namespace CoreNavigationCommands { } }); + export const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + constructor() { + super({ + id: 'scrollEditorBottom', + precondition: undefined, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textInputFocus, + } + }); + } + + runCoreEditorCommand(viewModel: IViewModel, args: any): void { + EditorScroll._runEditorScroll(viewModel, args.source, { + direction: EditorScroll_.Direction.Down, + unit: EditorScroll_.Unit.Editor, + value: 1, + revealCursor: false, + select: false + }); + } + }); + class WordCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; From db1f5a2d02331d9de8ee4b64931ecba9bdabf2b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mangeonjean?= Date: Mon, 25 Jul 2022 12:45:12 +0200 Subject: [PATCH 029/179] Provide trigger and documentation to monaco code action provider (#149937) * Provide trigger to monaco code action provider * Provide documentation to monaco code action provider * Use an interface instead of a type --- src/vs/editor/common/languages.ts | 9 +++++---- .../editor/common/standalone/standaloneEnums.ts | 5 +++++ .../standalone/browser/standaloneLanguages.ts | 11 ++++++++++- src/vs/monaco.d.ts | 17 +++++++++++++++-- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index 10baf2667c9..a3d57455de4 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -669,9 +669,6 @@ export interface CodeAction { disabled?: string; } -/** - * @internal - */ export const enum CodeActionTriggerType { Invoke = 1, Auto = 2, @@ -1132,7 +1129,11 @@ export interface DocumentSymbolProvider { provideDocumentSymbols(model: model.ITextModel, token: CancellationToken): ProviderResult; } -export type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence }; +export interface TextEdit { + range: IRange; + text: string; + eol?: model.EndOfLineSequence; +} /** * Interface used to format a model diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 8d709286d5c..1589d641a32 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -15,6 +15,11 @@ export enum AccessibilitySupport { Enabled = 2 } +export enum CodeActionTriggerType { + Invoke = 1, + Auto = 2 +} + export enum CompletionItemInsertTextRule { /** * Adjust whitespace/indentation of multiline insert texts to diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index decc60790f5..56f84726c98 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -526,12 +526,13 @@ export function registerCodeActionProvider(languageSelector: LanguageSelector, p const languageFeaturesService = StandaloneServices.get(ILanguageFeaturesService); return languageFeaturesService.codeActionProvider.register(languageSelector, { providedCodeActionKinds: metadata?.providedCodeActionKinds, + documentation: metadata?.documentation, provideCodeActions: (model: model.ITextModel, range: Range, context: languages.CodeActionContext, token: CancellationToken): languages.ProviderResult => { const markerService = StandaloneServices.get(IMarkerService); const markers = markerService.read({ resource: model.uri }).filter(m => { return Range.areIntersectingOrTouching(m, range); }); - return provider.provideCodeActions(model, range, { markers, only: context.only }, token); + return provider.provideCodeActions(model, range, { markers, only: context.only, trigger: context.trigger }, token); }, resolveCodeAction: provider.resolveCodeAction }); @@ -664,6 +665,11 @@ export interface CodeActionContext { * Requested kind of actions to return. */ readonly only?: string; + + /** + * The reason why code actions were requested. + */ + readonly trigger: languages.CodeActionTriggerType; } /** @@ -697,6 +703,8 @@ export interface CodeActionProviderMetadata { * such as `["quickfix.removeLine", "source.fixAll" ...]`. */ readonly providedCodeActionKinds?: readonly string[]; + + readonly documentation?: ReadonlyArray<{ readonly kind: string; readonly command: languages.Command }>; } /** @@ -753,6 +761,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind, InlayHintKind: standaloneEnums.InlayHintKind, InlineCompletionTriggerKind: standaloneEnums.InlineCompletionTriggerKind, + CodeActionTriggerType: standaloneEnums.CodeActionTriggerType, // classes FoldingRangeKind: languages.FoldingRangeKind, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index de84db6407d..c3220ca5e15 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5848,6 +5848,10 @@ declare namespace monaco.languages { * Requested kind of actions to return. */ readonly only?: string; + /** + * The reason why code actions were requested. + */ + readonly trigger: CodeActionTriggerType; } /** @@ -5878,6 +5882,10 @@ declare namespace monaco.languages { * such as `["quickfix.removeLine", "source.fixAll" ...]`. */ readonly providedCodeActionKinds?: readonly string[]; + readonly documentation?: ReadonlyArray<{ + readonly kind: string; + readonly command: Command; + }>; } /** @@ -6450,6 +6458,11 @@ declare namespace monaco.languages { disabled?: string; } + export enum CodeActionTriggerType { + Invoke = 1, + Auto = 2 + } + export interface CodeActionList extends IDisposable { readonly actions: ReadonlyArray; } @@ -6786,11 +6799,11 @@ declare namespace monaco.languages { provideDocumentSymbols(model: editor.ITextModel, token: CancellationToken): ProviderResult; } - export type TextEdit = { + export interface TextEdit { range: IRange; text: string; eol?: editor.EndOfLineSequence; - }; + } /** * Interface used to format a model From 79a77abb40a0c5c831643782d2b22d61e932c096 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Jul 2022 12:45:37 +0200 Subject: [PATCH 030/179] :up: distro (#156134) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bdd7a1190ca..d6fffcc2807 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.70.0", - "distro": "990065ff739688c0d4ad94e172eeccd6bd5ef124", + "distro": "7b8f76c850c3f2553c14d1b5a068c5e12952f675", "author": { "name": "Microsoft Corporation" }, From a30ca5e37b39705eb981b8ddae61b214b71b77c7 Mon Sep 17 00:00:00 2001 From: Joshua Cole <43352055+joscol@users.noreply.github.com> Date: Mon, 25 Jul 2022 06:54:18 -0400 Subject: [PATCH 031/179] Allow CommentNode to change body text and enter edit mode at the same time (#155767) --- src/vs/workbench/contrib/comments/browser/commentNode.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 450c76ae8ad..674ea47d406 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -528,7 +528,11 @@ export class CommentNode extends Disposable { this.updateCommentBody(newComment.body); } - if (newComment.mode !== undefined && newComment.mode !== this.comment.mode) { + const isChangingMode: boolean = newComment.mode !== undefined && newComment.mode !== this.comment.mode; + + this.comment = newComment; + + if (isChangingMode) { if (newComment.mode === languages.CommentMode.Editing) { this.switchToEditMode(); } else { @@ -536,8 +540,6 @@ export class CommentNode extends Disposable { } } - this.comment = newComment; - if (newComment.label) { this._isPendingLabel.innerText = newComment.label; } else { From 38c96ef2652daad549be04430900fe88591649a5 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 25 Jul 2022 13:11:13 +0200 Subject: [PATCH 032/179] Bump distro (#156137) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6fffcc2807..838defde1cb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.70.0", - "distro": "7b8f76c850c3f2553c14d1b5a068c5e12952f675", + "distro": "25c5a766dec5d762c3205176fec650c6964c7763", "author": { "name": "Microsoft Corporation" }, From 8dec36388125d96286a5df336aaa6e594fa79840 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:24:34 +0200 Subject: [PATCH 033/179] Problems view - remove custom code for SCM input markers (#156145) * Revert "Problems view - Fix issue with the SCM input label provider when problems are displayed in a tree view (#155853)" This reverts commit e77fa1fb8bc6b239479d664d8db613761736311a. * Revert "LabelService - custom formatter function (#155641)" This reverts commit 28c40a970f6022e313bab06db508f8cccba30860. --- src/vs/platform/label/common/label.ts | 2 +- .../markers/browser/markersTreeViewer.ts | 4 +- .../workbench/contrib/scm/browser/activity.ts | 47 ----------------- .../contrib/scm/browser/scm.contribution.ts | 5 +- .../services/label/common/labelService.ts | 51 +++++++++---------- .../services/label/test/browser/label.test.ts | 12 ----- 6 files changed, 29 insertions(+), 92 deletions(-) diff --git a/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts index b9ee570c43e..e5b6b8a1045 100644 --- a/src/vs/platform/label/common/label.ts +++ b/src/vs/platform/label/common/label.ts @@ -51,7 +51,7 @@ export interface ResourceLabelFormatter { } export interface ResourceLabelFormatting { - label: string | ((resource: URI) => string); // myLabel:/${path} + label: string; // myLabel:/${path} separator: '/' | '\\' | ''; tildify?: boolean; normalizeDriveLetter?: boolean; diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 778ae2c5497..1652365c097 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -19,7 +19,7 @@ import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { QuickFixAction, QuickFixActionViewItem } from 'vs/workbench/contrib/markers/browser/markersViewActions'; import { ILabelService } from 'vs/platform/label/common/label'; -import { basename, isEqual } from 'vs/base/common/resources'; +import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeFilter, TreeVisibility, TreeFilterResult, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { FilterOptions } from 'vs/workbench/contrib/markers/browser/markersFilterOptions'; @@ -185,7 +185,7 @@ export class ResourceMarkersRenderer implements ITreeRenderer { - const match = /git\/(?scm[\d+])\/input/i.exec(resource.path); - - if (match?.groups === undefined) { - return resource.toString(); - } - - const { repositoryId } = match.groups; - const repository = this.scmService.getRepository(repositoryId); - - if (repository === undefined || repository.provider.rootUri === undefined) { - return resource.toString(); - } - - const folder = this.workspaceContextService.getWorkspaceFolder(repository.provider.rootUri); - const repositoryName = folder?.uri.toString() === repository.provider.rootUri.toString() ? folder.name : basename(repository.provider.rootUri); - - return `${repositoryName} (${repository.provider.label})`; - }; - - constructor( - @ISCMService private readonly scmService: ISCMService, - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - ) { } -} - -export class SCMInputTextDocumentContribution implements IWorkbenchContribution { - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @ILabelService labelService: ILabelService - ) { - labelService.registerFormatter({ - scheme: Schemas.vscode, - authority: 'scm', - formatting: instantiationService.createInstance(SCMInputTextDocumentLabelFormatter) - }); - } -} diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 6c0ceafb8ac..956e867a21f 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -10,7 +10,7 @@ import { DirtyDiffWorkbenchController } from './dirtydiffDecorator'; import { VIEWLET_ID, ISCMService, VIEW_PANE_ID, ISCMProvider, ISCMViewService, REPOSITORIES_VIEW_PANE_ID } from 'vs/workbench/contrib/scm/common/scm'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { SCMActiveResourceContextKeyController, SCMInputTextDocumentContribution, SCMStatusController } from './activity'; +import { SCMActiveResourceContextKeyController, SCMStatusController } from './activity'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -115,9 +115,6 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(SCMStatusController, LifecyclePhase.Restored); -Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(SCMInputTextDocumentContribution, LifecyclePhase.Restored); - Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'scm', order: 5, diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index b680533dabc..4135a251e94 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -402,33 +402,32 @@ export class LabelService extends Disposable implements ILabelService { } private formatUri(resource: URI, formatting: ResourceLabelFormatting, forceNoTildify?: boolean): string { - let label = typeof formatting.label !== 'string' ? formatting.label(resource) : - formatting.label.replace(labelMatchingRegexp, (match, token, qsToken, qsValue) => { - switch (token) { - case 'scheme': return resource.scheme; - case 'authority': return resource.authority; - case 'authoritySuffix': { - const i = resource.authority.indexOf('+'); - return i === -1 ? resource.authority : resource.authority.slice(i + 1); - } - case 'path': - return formatting.stripPathStartingSeparator - ? resource.path.slice(resource.path[0] === formatting.separator ? 1 : 0) - : resource.path; - default: { - if (qsToken === 'query') { - const { query } = resource; - if (query && query[0] === '{' && query[query.length - 1] === '}') { - try { - return JSON.parse(query)[qsValue] || ''; - } catch { } - } - } - - return ''; - } + let label = formatting.label.replace(labelMatchingRegexp, (match, token, qsToken, qsValue) => { + switch (token) { + case 'scheme': return resource.scheme; + case 'authority': return resource.authority; + case 'authoritySuffix': { + const i = resource.authority.indexOf('+'); + return i === -1 ? resource.authority : resource.authority.slice(i + 1); } - }); + case 'path': + return formatting.stripPathStartingSeparator + ? resource.path.slice(resource.path[0] === formatting.separator ? 1 : 0) + : resource.path; + default: { + if (qsToken === 'query') { + const { query } = resource; + if (query && query[0] === '{' && query[query.length - 1] === '}') { + try { + return JSON.parse(query)[qsValue] || ''; + } catch { } + } + } + + return ''; + } + } + }); // convert \c:\something => C:\something if (formatting.normalizeDriveLetter && hasDriveLetterIgnorePlatform(label)) { diff --git a/src/vs/workbench/services/label/test/browser/label.test.ts b/src/vs/workbench/services/label/test/browser/label.test.ts index 338660d225b..745055c930e 100644 --- a/src/vs/workbench/services/label/test/browser/label.test.ts +++ b/src/vs/workbench/services/label/test/browser/label.test.ts @@ -164,18 +164,6 @@ suite('URI Label', () => { assert.strictEqual(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: /END'); }); - test('custom formatting function', function () { - labelService.registerFormatter({ - scheme: 'vscode', - formatting: { - label: (resource) => { return resource.toString(); }, - separator: '/', - } - }); - - const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5'); - assert.strictEqual(labelService.getUriLabel(uri1), uri1.toString()); - }); test('label caching', () => { const m = new Memento('cachedResourceLabelFormatters', storageService).getMemento(StorageScope.PROFILE, StorageTarget.MACHINE); From 4ee88fc49f1ae6d09d7d904e10c68721dbbc8687 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:40:26 +0200 Subject: [PATCH 034/179] SCM - Create dedicated schema for the source control commit input (#155894) --- src/vs/base/common/network.ts | 5 +++++ src/vs/workbench/contrib/scm/browser/scmViewPane.ts | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 63d6a15b49e..20f6b38e629 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -101,6 +101,11 @@ export namespace Schemas { * Scheme used vs live share */ export const vsls = 'vsls'; + + /** + * Scheme used for the Source Control commit input's text document + */ + export const vscodeSourceControl = 'vscode-scm'; } export const connectionTokenCookieName = 'vscode-tkn'; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index e809b5cb465..f479781fba7 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -1788,9 +1788,8 @@ class SCMInputWidget { } const uri = URI.from({ - scheme: Schemas.vscode, - authority: 'scm', - path: `/${input.repository.provider.contextValue}/${input.repository.provider.id}/input`, + scheme: Schemas.vscodeSourceControl, + path: `${input.repository.provider.contextValue}/${input.repository.provider.id}/input`, query }); From a649d8f40448af19f4abe3af5097224f8b632f71 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Mon, 25 Jul 2022 15:07:54 +0200 Subject: [PATCH 035/179] Explicitly enqueue files that only forward symbols (#156150) Fixes #154083: Explicitly enqueue files that only forward symbols --- build/lib/treeshaking.js | 45 +++++++++++++++++++++++++++++++++---- build/lib/treeshaking.ts | 44 ++++++++++++++++++++++++++++++++---- src/vs/base/common/event.ts | 2 +- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 9a11c6fd9cc..ff18694436d 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -228,6 +228,12 @@ function getColor(node) { function setColor(node, color) { node.$$$color = color; } +function markNeededSourceFile(node) { + node.$$$neededSourceFile = true; +} +function isNeededSourceFile(node) { + return Boolean(node.$$$neededSourceFile); +} function nodeOrParentIsBlack(node) { while (node) { const color = getColor(node); @@ -353,6 +359,19 @@ function markNodes(ts, languageService, options) { } }); } + /** + * Return the parent of `node` which is an ImportDeclaration + */ + function findParentImportDeclaration(node) { + let _node = node; + do { + if (ts.isImportDeclaration(_node)) { + return _node; + } + _node = _node.parent; + } while (_node); + return null; + } function enqueue_gray(node) { if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* NodeColor.Gray */) { return; @@ -420,6 +439,8 @@ function markNodes(ts, languageService, options) { console.warn(`Cannot find source file ${filename}`); return; } + // This source file should survive even if it is empty + markNeededSourceFile(sourceFile); enqueue_black(sourceFile); } function enqueueImport(node, importText) { @@ -472,6 +493,10 @@ function markNodes(ts, languageService, options) { 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); + } } if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { for (let i = 0, len = symbol.declarations.length; i < len; i++) { @@ -663,11 +688,23 @@ function generateResult(ts, languageService, shakeLevel) { } if (getColor(sourceFile) !== 2 /* NodeColor.Black */) { if (!nodeOrChildIsBlack(sourceFile)) { - // none of the elements are reachable => don't write this file at all! - return; + // none of the elements are reachable + if (isNeededSourceFile(sourceFile)) { + // this source file must be written, even if nothing is used from it + // because there is an import somewhere for it. + // However, TS complains with empty files with the error "x" is not a module, + // so we will export a dummy variable + result = 'export const __dummy = 0;'; + } + else { + // don't write this file at all! + return; + } + } + else { + sourceFile.forEachChild(writeMarkedNodes); + result += sourceFile.endOfFileToken.getFullText(sourceFile); } - sourceFile.forEachChild(writeMarkedNodes); - result += sourceFile.endOfFileToken.getFullText(sourceFile); } else { result = text; diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index eb4f6f7767a..ef829426d94 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -307,6 +307,12 @@ function getColor(node: ts.Node): NodeColor { function setColor(node: ts.Node, color: NodeColor): void { (node).$$$color = color; } +function markNeededSourceFile(node: ts.SourceFile): void { + (node).$$$neededSourceFile = true; +} +function isNeededSourceFile(node: ts.SourceFile): boolean { + return Boolean((node).$$$neededSourceFile); +} function nodeOrParentIsBlack(node: ts.Node): boolean { while (node) { const color = getColor(node); @@ -449,6 +455,20 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language }); } + /** + * Return the parent of `node` which is an ImportDeclaration + */ + function findParentImportDeclaration(node: ts.Declaration): ts.ImportDeclaration | null { + let _node: ts.Node = node; + do { + if (ts.isImportDeclaration(_node)) { + return _node; + } + _node = _node.parent; + } while (_node); + return null; + } + function enqueue_gray(node: ts.Node): void { if (nodeOrParentIsBlack(node) || getColor(node) === NodeColor.Gray) { return; @@ -531,6 +551,8 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language console.warn(`Cannot find source file ${filename}`); return; } + // This source file should survive even if it is empty + markNeededSourceFile(sourceFile); enqueue_black(sourceFile); } @@ -590,6 +612,10 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language 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)) { @@ -802,11 +828,21 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan if (getColor(sourceFile) !== NodeColor.Black) { if (!nodeOrChildIsBlack(sourceFile)) { - // none of the elements are reachable => don't write this file at all! - return; + // none of the elements are reachable + if (isNeededSourceFile(sourceFile)) { + // this source file must be written, even if nothing is used from it + // because there is an import somewhere for it. + // However, TS complains with empty files with the error "x" is not a module, + // so we will export a dummy variable + result = 'export const __dummy = 0;'; + } else { + // don't write this file at all! + return; + } + } else { + sourceFile.forEachChild(writeMarkedNodes); + result += sourceFile.endOfFileToken.getFullText(sourceFile); } - sourceFile.forEachChild(writeMarkedNodes); - result += sourceFile.endOfFileToken.getFullText(sourceFile); } else { result = text; } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index d395e4a9f32..5ceab5b92a0 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -8,7 +8,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { once as onceFn } from 'vs/base/common/functional'; import { combinedDisposable, Disposable, DisposableStore, IDisposable, SafeDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; -import { IObservable, IObserver } from 'vs/base/common/observableImpl/base'; +import { IObservable, IObserver } from 'vs/base/common/observable'; import { StopWatch } from 'vs/base/common/stopwatch'; From 1a30c325e58c4a12cb749850b2f9cc76dad2eb93 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 25 Jul 2022 15:17:05 +0200 Subject: [PATCH 036/179] Problems view - do not show markers for SCM input (#156151) Filter out markers omitted for the text document of the SCM input field --- src/vs/platform/markers/common/markerService.ts | 2 +- src/vs/workbench/contrib/markers/browser/markersTable.ts | 2 +- src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/markers/common/markerService.ts b/src/vs/platform/markers/common/markerService.ts index e94d1f2bd74..6f6dd4e8810 100644 --- a/src/vs/platform/markers/common/markerService.ts +++ b/src/vs/platform/markers/common/markerService.ts @@ -103,7 +103,7 @@ class MarkerStats implements MarkerStatistics { const result: MarkerStatistics = { errors: 0, warnings: 0, infos: 0, unknowns: 0 }; // TODO this is a hack - if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet) { + if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet || resource.scheme === Schemas.vscodeSourceControl) { return result; } diff --git a/src/vs/workbench/contrib/markers/browser/markersTable.ts b/src/vs/workbench/contrib/markers/browser/markersTable.ts index 4d39773daed..3aaaa1c9df6 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTable.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTable.ts @@ -411,7 +411,7 @@ export class MarkersTable extends Disposable implements IProblemsWidget { const items: MarkerTableItem[] = []; for (const resourceMarker of this.resourceMarkers) { for (const marker of resourceMarker.markers) { - if (marker.resource.scheme === network.Schemas.walkThrough || marker.resource.scheme === network.Schemas.walkThroughSnippet) { + if (marker.resource.scheme === network.Schemas.walkThrough || marker.resource.scheme === network.Schemas.walkThroughSnippet || marker.resource.scheme === network.Schemas.vscodeSourceControl) { continue; } diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 1652365c097..103d6512066 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -456,7 +456,7 @@ export class Filter implements ITreeFilter { } private filterResourceMarkers(resourceMarkers: ResourceMarkers): TreeFilterResult { - if (resourceMarkers.resource.scheme === network.Schemas.walkThrough || resourceMarkers.resource.scheme === network.Schemas.walkThroughSnippet) { + if (resourceMarkers.resource.scheme === network.Schemas.walkThrough || resourceMarkers.resource.scheme === network.Schemas.walkThroughSnippet || resourceMarkers.resource.scheme === network.Schemas.vscodeSourceControl) { return false; } From b2d1545f1585c5b4f09c3369a78646edf27d9937 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 25 Jul 2022 15:29:31 +0200 Subject: [PATCH 037/179] Fix bug in merge editor dev commands (#156155) --- .../contrib/mergeEditor/browser/commands/devCommands.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts index 0f2b38ea5b4..42cd0f7cc5a 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts @@ -101,6 +101,7 @@ export class MergeEditorOpenContents extends Action2 { const inputService = accessor.get(IQuickInputService); const clipboardService = accessor.get(IClipboardService); const textModelService = accessor.get(ITextModelService); + const editorService = accessor.get(IEditorService); const result = await inputService.input({ prompt: localize('mergeEditor.enterJSON', 'Enter JSON'), @@ -157,6 +158,6 @@ export class MergeEditorOpenContents extends Action2 { input2: { resource: input2Uri, label: 'Input 2', description: 'Input 2', detail: '(from JSON)' }, result: { resource: resultUri }, }; - accessor.get(IEditorService).openEditor(input); + editorService.openEditor(input); } } From c47c24af30f835c92cd4457e552d6edfd0d326f4 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 25 Jul 2022 15:54:52 +0200 Subject: [PATCH 038/179] simplify fold merging (#155302) * tune _trySanitizeAndMerge * more simplifications * maually expanded icon * folding ranges css * also persist manual expanded ranges * rename isManualSelection -> isManual * isUserDefined & isRecovered * Remove Manual Folding Ranges command --- .../contrib/folding/browser/folding.css | 8 +- .../editor/contrib/folding/browser/folding.ts | 59 +++++-- .../folding/browser/foldingDecorations.ts | 41 +++-- .../contrib/folding/browser/foldingModel.ts | 94 ++++++----- .../contrib/folding/browser/foldingRanges.ts | 152 +++++++++--------- .../test/browser/foldingRanges.test.ts | 136 +++++++--------- 6 files changed, 279 insertions(+), 211 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.css b/src/vs/editor/contrib/folding/browser/folding.css index a68daff8155..232384ce3d5 100644 --- a/src/vs/editor/contrib/folding/browser/folding.css +++ b/src/vs/editor/contrib/folding/browser/folding.css @@ -2,7 +2,8 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - +.monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed, +.monaco-editor .margin-view-overlays .codicon-folding-manual-expanded, .monaco-editor .margin-view-overlays .codicon-folding-expanded, .monaco-editor .margin-view-overlays .codicon-folding-collapsed { cursor: pointer; @@ -17,6 +18,7 @@ .monaco-editor .margin-view-overlays:hover .codicon, .monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed, +.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-collapsed, .monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons { opacity: 1; } @@ -29,3 +31,7 @@ line-height: 1em; cursor: pointer; } + +.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-expanded::before { + transform: rotate(90deg); +} diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 64339450d95..279ab870eb5 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -31,8 +31,8 @@ import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/cont import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { editorSelectionBackground, iconForeground, registerColor, transparent } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { foldingCollapsedIcon, FoldingDecorationProvider, foldingExpandedIcon, foldingManualIcon } from './foldingDecorations'; -import { FoldingRegion, FoldingRegions, FoldRange } from './foldingRanges'; +import { foldingCollapsedIcon, FoldingDecorationProvider, foldingExpandedIcon, foldingManualCollapsedIcon, foldingManualExpandedIcon } from './foldingDecorations'; +import { FoldingRegion, FoldingRegions, FoldRange, ILineRange } from './foldingRanges'; import { SyntaxRangeProvider } from './syntaxRangeProvider'; import { INotificationService } from 'vs/platform/notification/common/notification'; import Severity from 'vs/base/common/severity'; @@ -222,7 +222,7 @@ export class FoldingController extends Disposable implements IEditorContribution } this._currentModelHasFoldedImports = false; - this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider, this.triggerFoldingModelChanged.bind(this)); + this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider); this.localToDispose.add(this.foldingModel); this.hiddenRangeModel = new HiddenRangeModel(this.foldingModel); @@ -293,7 +293,7 @@ export class FoldingController extends Disposable implements IEditorContribution this.triggerFoldingModelChanged(); } - private triggerFoldingModelChanged() { + public triggerFoldingModelChanged() { if (this.updateScheduler) { if (this.foldingRegionPromise) { this.foldingRegionPromise.cancel(); @@ -1066,13 +1066,13 @@ class GotoNextFoldAction extends FoldingAction { } } -class FoldSelectedAction extends FoldingAction { +class FoldRangeFromSelectionAction extends FoldingAction { constructor() { super({ - id: 'editor.foldSelected', - label: nls.localize('foldSelectedAction.label', "Fold Selected Lines"), - alias: 'Fold Selected Lines', + id: 'editor.createFoldingRangeFromSelection', + label: nls.localize('createManualFoldRange.label', "Create Manual Folding Range from Selection"), + alias: 'Create Folding Range from Selection', precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, @@ -1097,7 +1097,8 @@ class FoldSelectedAction extends FoldingAction { endLineNumber: endLineNumber, type: undefined, isCollapsed: true, - isManualSelection: true + isUserDefined: true, + isRecovered: false }); editor.setSelection({ startLineNumber: selection.startLineNumber, @@ -1118,6 +1119,40 @@ class FoldSelectedAction extends FoldingAction { } } +class RemoveFoldRangeFromSelectionAction extends FoldingAction { + + constructor() { + super({ + id: 'editor.removeManualFoldingRanges', + label: nls.localize('removeManualFoldingRanges.label', "Remove Manual Folding Ranges"), + alias: 'Remove Manual Folding Ranges', + precondition: CONTEXT_FOLDING_ENABLED, + kbOpts: { + kbExpr: EditorContextKeys.editorTextFocus, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Period), + weight: KeybindingWeight.EditorContrib + } + }); + } + + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { + const selections = editor.getSelections(); + if (selections) { + const ranges: ILineRange[] = []; + for (const selection of selections) { + let endLineNumber = selection.endLineNumber; + if (selection.endColumn === 1) { + --endLineNumber; + } + const startLineNumber = selection.startLineNumber; + ranges.push(endLineNumber >= selection.startLineNumber ? { startLineNumber, endLineNumber } : { endLineNumber, startLineNumber }); + } + foldingModel.removeManualRanges(ranges); + foldingController.triggerFoldingModelChanged(); + } + } +} + registerEditorContribution(FoldingController.ID, FoldingController); registerEditorAction(UnfoldAction); @@ -1135,7 +1170,8 @@ registerEditorAction(ToggleFoldAction); registerEditorAction(GotoParentFoldAction); registerEditorAction(GotoPreviousFoldAction); registerEditorAction(GotoNextFoldAction); -registerEditorAction(FoldSelectedAction); +registerEditorAction(FoldRangeFromSelectionAction); +registerEditorAction(RemoveFoldRangeFromSelectionAction); for (let i = 1; i <= 7; i++) { registerInstantiatedEditorAction( @@ -1167,7 +1203,8 @@ registerThemingParticipant((theme, collector) => { collector.addRule(` .monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingExpandedIcon)}, .monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingCollapsedIcon)}, - .monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualIcon)} { + .monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualExpandedIcon)}, + .monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualCollapsedIcon)} { color: ${editorFoldColor} !important; } `); diff --git a/src/vs/editor/contrib/folding/browser/foldingDecorations.ts b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts index 132dd19a9fa..9ad6cb77605 100644 --- a/src/vs/editor/contrib/folding/browser/foldingDecorations.ts +++ b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts @@ -14,12 +14,14 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; export const foldingExpandedIcon = registerIcon('folding-expanded', Codicon.chevronDown, localize('foldingExpandedIcon', 'Icon for expanded ranges in the editor glyph margin.')); export const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.chevronRight, localize('foldingCollapsedIcon', 'Icon for collapsed ranges in the editor glyph margin.')); -export const foldingManualIcon = registerIcon('folding-manual', Codicon.ellipsis, localize('foldingManualIcon', 'Icon for manually collapsed ranges in the editor glyph margin.')); +export const foldingManualCollapsedIcon = registerIcon('folding-manual-collapsed', Codicon.ellipsis, localize('foldingManualCollapedIcon', 'Icon for manually collapsed ranges in the editor glyph margin.')); +export const foldingManualExpandedIcon = registerIcon('folding-manual-expanded', Codicon.ellipsis, localize('foldingManualExpandedIcon', 'Icon for manually expanded ranges in the editor glyph margin.')); + export class FoldingDecorationProvider implements IDecorationProvider { private static readonly COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ description: 'folding-collapsed-visual-decoration', - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', isWholeLine: true, firstLineDecorationClassName: ThemeIcon.asClassName(foldingCollapsedIcon) @@ -27,7 +29,7 @@ export class FoldingDecorationProvider implements IDecorationProvider { private static readonly COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({ description: 'folding-collapsed-highlighted-visual-decoration', - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', className: 'folded-background', isWholeLine: true, @@ -36,19 +38,19 @@ export class FoldingDecorationProvider implements IDecorationProvider { private static readonly MANUALLY_COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ description: 'folding-manually-collapsed-visual-decoration', - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', isWholeLine: true, - firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualIcon) + firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon) }); private static readonly MANUALLY_COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({ description: 'folding-manually-collapsed-highlighted-visual-decoration', - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', className: 'folded-background', isWholeLine: true, - firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualIcon) + firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualCollapsedIcon) }); private static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ @@ -65,6 +67,21 @@ export class FoldingDecorationProvider implements IDecorationProvider { firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon) }); + private static readonly MANUALLY_EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-manually-expanded-visual-decoration', + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, + isWholeLine: true, + firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingManualExpandedIcon) + }); + + private static readonly MANUALLY_EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-manually-expanded-visual-decoration', + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, + isWholeLine: true, + firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualExpandedIcon) + }); + + private static readonly HIDDEN_RANGE_DECORATION = ModelDecorationOptions.register({ description: 'folding-hidden-range-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges @@ -77,19 +94,19 @@ export class FoldingDecorationProvider implements IDecorationProvider { constructor(private readonly editor: ICodeEditor) { } - getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManualSelection: boolean): IModelDecorationOptions { + getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManual: boolean): IModelDecorationOptions { if (isHidden // is inside another collapsed region - || this.showFoldingControls === 'never' || (isManualSelection && !isCollapsed)) { // + || this.showFoldingControls === 'never') { return FoldingDecorationProvider.HIDDEN_RANGE_DECORATION; } if (isCollapsed) { - return isManualSelection ? + return isManual ? (this.showFoldingHighlights ? FoldingDecorationProvider.MANUALLY_COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION : FoldingDecorationProvider.MANUALLY_COLLAPSED_VISUAL_DECORATION) : (this.showFoldingHighlights ? FoldingDecorationProvider.COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION : FoldingDecorationProvider.COLLAPSED_VISUAL_DECORATION); } else if (this.showFoldingControls === 'mouseover') { - return FoldingDecorationProvider.EXPANDED_AUTO_HIDE_VISUAL_DECORATION; + return isManual ? FoldingDecorationProvider.MANUALLY_EXPANDED_AUTO_HIDE_VISUAL_DECORATION : FoldingDecorationProvider.EXPANDED_AUTO_HIDE_VISUAL_DECORATION; } else { - return FoldingDecorationProvider.EXPANDED_VISUAL_DECORATION; + return isManual ? FoldingDecorationProvider.MANUALLY_EXPANDED_VISUAL_DECORATION : FoldingDecorationProvider.EXPANDED_VISUAL_DECORATION; } } diff --git a/src/vs/editor/contrib/folding/browser/foldingModel.ts b/src/vs/editor/contrib/folding/browser/foldingModel.ts index 59083ae1d3e..f5b7a59f173 100644 --- a/src/vs/editor/contrib/folding/browser/foldingModel.ts +++ b/src/vs/editor/contrib/folding/browser/foldingModel.ts @@ -9,7 +9,7 @@ import { FoldingRegion, FoldingRegions, ILineRange, FoldRange } from './foldingR import { hash } from 'vs/base/common/hash'; export interface IDecorationProvider { - getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManualSelection: boolean): IModelDecorationOptions; + getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManual: boolean): IModelDecorationOptions; changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null; removeDecorations(decorationIds: string[]): void; } @@ -21,6 +21,8 @@ export interface FoldingModelChangeEvent { interface ILineMemento extends ILineRange { checksum?: number; + isCollapsed?: boolean; + isUserDefined?: boolean; } export type CollapseMemento = ILineMemento[]; @@ -28,7 +30,6 @@ export type CollapseMemento = ILineMemento[]; export class FoldingModel { private readonly _textModel: ITextModel; private readonly _decorationProvider: IDecorationProvider; - private readonly _triggerRecomputeRanges: (() => void) | undefined; private _regions: FoldingRegions; private _editorDecorationIds: string[]; @@ -40,10 +41,9 @@ export class FoldingModel { public get textModel() { return this._textModel; } public get decorationProvider() { return this._decorationProvider; } - constructor(textModel: ITextModel, decorationProvider: IDecorationProvider, triggerRecomputeRanges?: () => void) { + constructor(textModel: ITextModel, decorationProvider: IDecorationProvider) { this._textModel = textModel; this._decorationProvider = decorationProvider; - this._triggerRecomputeRanges = triggerRecomputeRanges; this._regions = new FoldingRegions(new Uint32Array(0), new Uint32Array(0)); this._editorDecorationIds = []; } @@ -55,7 +55,6 @@ export class FoldingModel { toggledRegions = toggledRegions.sort((r1, r2) => r1.regionIndex - r2.regionIndex); const processed: { [key: string]: boolean | undefined } = {}; - const manualExpanded = false; this._decorationProvider.changeDecorations(accessor => { let k = 0; // index from [0 ... this.regions.length] let dirtyRegionEndLine = -1; // end of the range where decorations need to be updated @@ -64,9 +63,9 @@ export class FoldingModel { while (k < index) { const endLineNumber = this._regions.getEndLineNumber(k); const isCollapsed = this._regions.isCollapsed(k); - const isManualSelection = this.regions.isManualSelection(k); if (endLineNumber <= dirtyRegionEndLine) { - accessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManualSelection)); + const isManual = this.regions.isUserDefined(k) || this.regions.isRecovered(k); + accessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual)); } if (isCollapsed && endLineNumber > lastHiddenLine) { lastHiddenLine = endLineNumber; @@ -91,16 +90,30 @@ export class FoldingModel { updateDecorationsUntil(this._regions.length); }); this._updateEventEmitter.fire({ model: this, collapseStateChanged: toggledRegions }); - if (manualExpanded && this._triggerRecomputeRanges) { - // expanding a range which didn't originate from range provider might now enable ranges - // from the provider which were previously dropped due to the collapsed range - this._triggerRecomputeRanges(); + } + + public removeManualRanges(ranges: ILineRange[]) { + const newFoldingRanges: FoldRange[] = new Array(); + const containedBy = (foldRange: FoldRange) => { + for (const range of ranges) { + if (range.startLineNumber <= foldRange.startLineNumber && range.endLineNumber >= foldRange.endLineNumber) { + return true; + } + } + return false; + }; + for (let i = 0; i < this._regions.length; i++) { + const foldRange = this._regions.toFoldRange(i); + if (!foldRange.isUserDefined && !foldRange.isRecovered || !containedBy(foldRange)) { + newFoldingRanges.push(foldRange); + } } + this.updatePost(FoldingRegions.fromFoldRanges(newFoldingRanges)); } public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void { - const hiddenRanges = this._currentHiddenRegions(blockedLineNumers); - const newRanges = FoldingRegions.sanitizeAndMerge(newRegions, hiddenRanges, this._textModel.getLineCount()); + const foldedOrManualRanges = this._currentFoldedOrManualRanges(blockedLineNumers); + const newRanges = FoldingRegions.sanitizeAndMerge(newRegions, foldedOrManualRanges, this._textModel.getLineCount()); this.updatePost(FoldingRegions.fromFoldRanges(newRanges)); } @@ -111,14 +124,14 @@ export class FoldingModel { const startLineNumber = newRegions.getStartLineNumber(index); const endLineNumber = newRegions.getEndLineNumber(index); const isCollapsed = newRegions.isCollapsed(index); - const isManualSelection = newRegions.isManualSelection(index); + const isManual = newRegions.isUserDefined(index) || newRegions.isRecovered(index); const decorationRange = { startLineNumber: startLineNumber, startColumn: this._textModel.getLineMaxColumn(startLineNumber), endLineNumber: endLineNumber, endColumn: this._textModel.getLineMaxColumn(endLineNumber) + 1 }; - newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManualSelection) }); + newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual) }); if (isCollapsed && endLineNumber > lastHiddenLine) { lastHiddenLine = endLineNumber; } @@ -128,7 +141,7 @@ export class FoldingModel { this._updateEventEmitter.fire({ model: this }); } - private _currentHiddenRegions(blockedLineNumers: number[] = []): FoldRange[] { + private _currentFoldedOrManualRanges(blockedLineNumers: number[] = []): FoldRange[] { const isBlocked = (startLineNumber: number, endLineNumber: number) => { for (const blockedLineNumber of blockedLineNumers) { @@ -139,42 +152,47 @@ export class FoldingModel { return false; }; - const hiddenRanges: FoldRange[] = []; + const foldedRanges: FoldRange[] = []; for (let i = 0, limit = this._regions.length; i < limit; i++) { - if (this.regions.isCollapsed(i)) { - const hiddenRange = this._regions.toFoldRange(i); + let isCollapsed = this.regions.isCollapsed(i); + const isUserDefined = this.regions.isUserDefined(i); + const isRecovered = this.regions.isRecovered(i); + if (isCollapsed || isUserDefined || isRecovered) { + const foldRange = this._regions.toFoldRange(i); const decRange = this._textModel.getDecorationRange(this._editorDecorationIds[i]); - if (decRange - && !isBlocked(decRange.startLineNumber, decRange.endLineNumber) - // if not same length user has modified it, skip and auto-expand - && decRange.endLineNumber - decRange.startLineNumber - === hiddenRange.endLineNumber - hiddenRange.startLineNumber) { - hiddenRanges.push({ + if (decRange) { + if (isCollapsed && (isBlocked(decRange.startLineNumber, decRange.endLineNumber) || decRange.endLineNumber - decRange.startLineNumber !== foldRange.endLineNumber - foldRange.startLineNumber)) { + isCollapsed = false; // uncollapse is the range is blocked or there has been lines removed or added + } + foldedRanges.push({ startLineNumber: decRange.startLineNumber, endLineNumber: decRange.endLineNumber, - type: hiddenRange.type, - isCollapsed: true, - isManualSelection: hiddenRange.isManualSelection + type: foldRange.type, + isCollapsed, + isUserDefined, + isRecovered }); } } } - return hiddenRanges; + return foldedRanges; } /** * Collapse state memento, for persistence only */ public getMemento(): CollapseMemento | undefined { - const hiddenRegions = this._currentHiddenRegions(); + const foldedOrManualRanges = this._currentFoldedOrManualRanges(); const result: ILineMemento[] = []; - for (let i = 0, limit = hiddenRegions.length; i < limit; i++) { - const range = hiddenRegions[i]; + for (let i = 0, limit = foldedOrManualRanges.length; i < limit; i++) { + const range = foldedOrManualRanges[i]; const checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber); result.push({ startLineNumber: range.startLineNumber, endLineNumber: range.endLineNumber, + isCollapsed: range.isCollapsed, + isUserDefined: range.isRecovered, checksum: checksum }); } @@ -188,7 +206,7 @@ export class FoldingModel { if (!Array.isArray(state)) { return; } - const hiddenRanges: FoldRange[] = []; + const rangesToRestore: FoldRange[] = []; const maxLineNumber = this._textModel.getLineCount(); for (const range of state) { if (range.startLineNumber >= range.endLineNumber || range.startLineNumber < 1 || range.endLineNumber > maxLineNumber) { @@ -196,17 +214,19 @@ export class FoldingModel { } const checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber); if (!range.checksum || checksum === range.checksum) { - hiddenRanges.push({ + const isUserDefined = range.isUserDefined === true; + rangesToRestore.push({ startLineNumber: range.startLineNumber, endLineNumber: range.endLineNumber, type: undefined, - isCollapsed: true, - isManualSelection: true // converts to false when provider sends a match + isCollapsed: range.isCollapsed ?? true, + isUserDefined, + isRecovered: !isUserDefined }); } } - const newRanges = FoldingRegions.sanitizeAndMerge(this._regions, hiddenRanges, maxLineNumber); + const newRanges = FoldingRegions.sanitizeAndMerge(this._regions, rangesToRestore, maxLineNumber); this.updatePost(FoldingRegions.fromFoldRanges(newRanges)); } diff --git a/src/vs/editor/contrib/folding/browser/foldingRanges.ts b/src/vs/editor/contrib/folding/browser/foldingRanges.ts index b45c3222349..2dfb1e50003 100644 --- a/src/vs/editor/contrib/folding/browser/foldingRanges.ts +++ b/src/vs/editor/contrib/folding/browser/foldingRanges.ts @@ -13,7 +13,8 @@ export interface FoldRange { endLineNumber: number; type: string | undefined; isCollapsed: boolean; - isManualSelection: boolean; + isUserDefined: boolean; + isRecovered: boolean; } export const MAX_FOLDING_REGIONS = 0xFFFF; @@ -21,11 +22,38 @@ export const MAX_LINE_NUMBER = 0xFFFFFF; const MASK_INDENT = 0xFF000000; +class BitField { + private readonly _states: Uint32Array; + constructor(size: number) { + const numWords = Math.ceil(size / 32); + this._states = new Uint32Array(numWords); + } + + public get(index: number): boolean { + const arrayIndex = (index / 32) | 0; + const bit = index % 32; + return (this._states[arrayIndex] & (1 << bit)) !== 0; + } + + public set(index: number, newState: boolean) { + const arrayIndex = (index / 32) | 0; + const bit = index % 32; + const value = this._states[arrayIndex]; + if (newState) { + this._states[arrayIndex] = value | (1 << bit); + } else { + this._states[arrayIndex] = value & ~(1 << bit); + } + } +} + export class FoldingRegions { private readonly _startIndexes: Uint32Array; private readonly _endIndexes: Uint32Array; - private readonly _collapseStates: Uint32Array; - private readonly _manualStates: Uint32Array; + private readonly _collapseStates: BitField; + private readonly _userDefinedStates: BitField; + private readonly _recoveredStates: BitField; + private _parentsComputed: boolean; private readonly _types: Array | undefined; @@ -35,9 +63,9 @@ export class FoldingRegions { } this._startIndexes = startIndexes; this._endIndexes = endIndexes; - const numWords = Math.ceil(startIndexes.length / 32); - this._collapseStates = new Uint32Array(numWords); - this._manualStates = new Uint32Array(numWords); + this._collapseStates = new BitField(startIndexes.length); + this._userDefinedStates = new BitField(startIndexes.length); + this._recoveredStates = new BitField(startIndexes.length); this._types = types; this._parentsComputed = false; } @@ -88,37 +116,27 @@ export class FoldingRegions { } public isCollapsed(index: number): boolean { - const arrayIndex = (index / 32) | 0; - const bit = index % 32; - return (this._collapseStates[arrayIndex] & (1 << bit)) !== 0; + return this._collapseStates.get(index); } public setCollapsed(index: number, newState: boolean) { - const arrayIndex = (index / 32) | 0; - const bit = index % 32; - const value = this._collapseStates[arrayIndex]; - if (newState) { - this._collapseStates[arrayIndex] = value | (1 << bit); - } else { - this._collapseStates[arrayIndex] = value & ~(1 << bit); - } + this._collapseStates.set(index, newState); } - public isManualSelection(index: number): boolean { - const arrayIndex = (index / 32) | 0; - const bit = index % 32; - return (this._manualStates[arrayIndex] & (1 << bit)) !== 0; + public isUserDefined(index: number): boolean { + return this._userDefinedStates.get(index); } - public setManualSelection(index: number, newState: boolean) { - const arrayIndex = (index / 32) | 0; - const bit = index % 32; - const value = this._manualStates[arrayIndex]; - if (newState) { - this._manualStates[arrayIndex] = value | (1 << bit); - } else { - this._manualStates[arrayIndex] = value & ~(1 << bit); - } + public setUserDefined(index: number, newState: boolean) { + return this._userDefinedStates.set(index, newState); + } + + public isRecovered(index: number): boolean { + return this._recoveredStates.get(index); + } + + public setRecovered(index: number, newState: boolean) { + return this._recoveredStates.set(index, newState); } public setCollapsedAllOfType(type: string, newState: boolean) { @@ -188,7 +206,7 @@ export class FoldingRegions { public toString() { const res: string[] = []; for (let i = 0; i < this.length; i++) { - res[i] = `[${this.isManualSelection(i) ? '*' : ' '}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`; + res[i] = `[${this.isUserDefined(i) ? '*' : ' '}${this.isRecovered(i) ? 'r' : ' '}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`; } return res.join(', '); } @@ -199,7 +217,8 @@ export class FoldingRegions { endLineNumber: this._endIndexes[index] & MAX_LINE_NUMBER, type: this._types ? this._types[index] : undefined, isCollapsed: this.isCollapsed(index), - isManualSelection: this.isManualSelection(index) + isUserDefined: this.isUserDefined(index), + isRecovered: this.isRecovered(index) }; } @@ -226,8 +245,11 @@ export class FoldingRegions { if (ranges[i].isCollapsed) { regions.setCollapsed(i, true); } - if (ranges[i].isManualSelection) { - regions.setManualSelection(i, true); + if (ranges[i].isUserDefined) { + regions.setUserDefined(i, true); + } + if (ranges[i].isRecovered) { + regions.setRecovered(i, true); } } return regions; @@ -237,11 +259,10 @@ export class FoldingRegions { * Two inputs, each a FoldingRegions or a FoldRange[], are merged. * Each input must be pre-sorted on startLineNumber. * The first list is assumed to always include all regions currently defined by range providers. - * The second list only contains hidden ranges. + * The second list only contains the previously collapsed and all manual ranges. + * If the line position matches, the range of the new range is taken, and the range is no longer manual * When an entry in one list overlaps an entry in the other, the second list's entry "wins" and - * overlapping entries in the first list are discarded. With one exception: when there is just - * one such second list entry and it is not manual it is discarded, on the assumption that - * user editing has resulted in the range no longer existing. + * overlapping entries in the first list are discarded. * Invalid entries are discarded. An entry is invalid if: * the start and end line numbers aren't a valid range of line numbers, * it is out of sequence or has the same start line as a preceding entry, @@ -252,18 +273,6 @@ export class FoldingRegions { rangesB: FoldingRegions | FoldRange[], maxLineNumber: number | undefined): FoldRange[] { maxLineNumber = maxLineNumber ?? Number.MAX_VALUE; - let result = this._trySanitizeAndMerge(1, rangesA, rangesB, maxLineNumber); - if (!result) { // try again, converting hidden ranges to manually selected - result = this._trySanitizeAndMerge(2, rangesA, rangesB, maxLineNumber); - } - return result!; - } - - private static _trySanitizeAndMerge( - passNumber: number, // it can take two passes to get this done - rangesA: FoldingRegions | FoldRange[], - rangesB: FoldingRegions | FoldRange[], - maxLineNumber: number): FoldRange[] | null { const getIndexedFunction = (r: FoldingRegions | FoldRange[], limit: number) => { return Array.isArray(r) @@ -281,41 +290,34 @@ export class FoldingRegions { let topStackedRange: FoldRange | undefined; let prevLineNumber = 0; const resultRanges: FoldRange[] = []; - let numberAutoExpand = 0; while (nextA || nextB) { let useRange: FoldRange | undefined = undefined; if (nextB && (!nextA || nextA.startLineNumber >= nextB.startLineNumber)) { - // nextB is next - if (nextA - && nextA.startLineNumber === nextB.startLineNumber - && nextA.endLineNumber === nextB.endLineNumber) { - // same range in both lists, merge the details - useRange = nextB; - useRange.isCollapsed = useRange.isCollapsed || nextA.isCollapsed; - // next line removes manual flag when range provider has matching range - useRange.isManualSelection = nextA.isManualSelection && nextB.isManualSelection; - if (!useRange.type) { - useRange.type = nextA.type; + if (nextA && nextA.startLineNumber === nextB.startLineNumber) { + if (nextB.isUserDefined) { + // a user defined range (possibly unfolded) + useRange = nextB; + } else { + // a previously folded range or a (possibly unfolded) recovered range + useRange = nextA; + useRange.isCollapsed = nextB.isCollapsed && nextA.endLineNumber === nextB.endLineNumber; + useRange.isUserDefined = false; + useRange.isRecovered = false; } nextA = getA(++indexA); // not necessary, just for speed - } else if (nextB.isCollapsed && !nextB.isManualSelection && passNumber === 1) { - if (++numberAutoExpand > 1) { - // do second pass keeping these, assuming something like an unmatched /* - return null; - } - // skip nextB (auto expand) by not setting useRange, assuming it was edited - } else { // use nextB + } else { useRange = nextB; - if (useRange.isCollapsed) { - // doesn't match nextA, convert to a manual selection if it wasn't already - useRange.isManualSelection = true; + if (nextB.isCollapsed && !nextB.isUserDefined && !nextB.isRecovered) { + // a previously collapsed range + useRange.isRecovered = true; + useRange.isUserDefined = false; } } nextB = getB(++indexB); } else { - // nextA is next. The B set takes precedence and we sometimes need to look + // nextA is next. The user folded B set takes precedence and we sometimes need to look // ahead in it to check for an upcoming conflict. let scanIndex = indexB; let prescanB = nextB; @@ -324,8 +326,8 @@ export class FoldingRegions { useRange = nextA; break; // no conflict, use this nextA } - if (prescanB.endLineNumber > nextA!.endLineNumber - && (!prescanB.isCollapsed || prescanB.isManualSelection || passNumber === 2)) { + if (prescanB.isUserDefined && prescanB.endLineNumber > nextA!.endLineNumber) { + // we found a user folded range, it wins break; // without setting nextResult, so this nextA gets skipped } prescanB = getB(++scanIndex); diff --git a/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts b/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts index a1979da3c22..671277579ee 100644 --- a/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts +++ b/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts @@ -14,22 +14,30 @@ const markers: FoldingMarkers = { end: /^\s*#endregion\b/ }; +enum State { + none = 0, + userDefined = 1, + recovered = 2 +} + suite('FoldingRanges', () => { - const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, manual: boolean | undefined = undefined, type: string | undefined = undefined) => + const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, state: State = State.none, type: string | undefined = undefined) => { startLineNumber: from, endLineNumber: to, type: type, isCollapsed: collapsed || false, - isManualSelection: manual || false + isUserDefined: state === State.userDefined, + isRecovered: state === State.recovered, }; const assertEqualRanges = (range1: FoldRange, range2: FoldRange, msg: string) => { assert.strictEqual(range1.startLineNumber, range2.startLineNumber, msg + ' start'); assert.strictEqual(range1.endLineNumber, range2.endLineNumber, msg + ' end'); assert.strictEqual(range1.type, range2.type, msg + ' type'); assert.strictEqual(range1.isCollapsed, range2.isCollapsed, msg + ' collapsed'); - assert.strictEqual(range1.isManualSelection, range2.isManualSelection, msg + ' manual'); + assert.strictEqual(range1.isUserDefined, range2.isUserDefined, msg + ' userDefined'); + assert.strictEqual(range1.isRecovered, range2.isRecovered, msg + ' recovered'); }; test('test max folding regions', () => { @@ -122,110 +130,88 @@ suite('FoldingRanges', () => { test('sanitizeAndMerge1', () => { const regionSet1: FoldRange[] = [ foldRange(0, 100), // invalid, should be removed - foldRange(1, 100, false, false, 'A'), // valid - foldRange(1, 100, false, false, 'Z'), // invalid, duplicate start + foldRange(1, 100, false, State.none, 'A'), // valid + foldRange(1, 100, false, State.none, 'Z'), // invalid, duplicate start foldRange(10, 10, false), // invalid, should be removed - foldRange(20, 80, false, false, 'C1'), // valid inside 'B' - foldRange(22, 80, true, false, 'D1'), // valid inside 'C1' + foldRange(20, 80, false, State.none, 'C1'), // valid inside 'B' + foldRange(22, 80, true, State.none, 'D1'), // valid inside 'C1' foldRange(90, 101), // invalid, should be removed ]; const regionSet2: FoldRange[] = [ - foldRange(2, 100, false, false, 'B'), // valid, inside 'A' foldRange(20, 80, true), // should merge with C1 foldRange(18, 80, true), // invalid, out of order - foldRange(21, 81, true, false, 'Z'), // invalid, overlapping - foldRange(22, 80, false, false, 'D2'), // should merge with D1 + foldRange(21, 81, true, State.none, 'Z'), // invalid, overlapping + foldRange(22, 80, true, State.none, 'D2'), // should merge with D1 ]; - let result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); - assert.strictEqual(result.length, 4, 'result length1'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'A'), 'A1'); - assertEqualRanges(result[1], foldRange(2, 100, false, false, 'B'), 'B1'); - assertEqualRanges(result[2], foldRange(20, 80, true, false, 'C1'), 'C1'); - assertEqualRanges(result[3], foldRange(22, 80, true, false, 'D2'), 'D1'); - const regionClass1 = FoldingRegions.fromFoldRanges(regionSet1); - const regionClass2 = FoldingRegions.fromFoldRanges(regionSet2); - // same tests again with inputs as FoldingRegions instead of FoldRange[] - result = FoldingRegions.sanitizeAndMerge(regionClass1, regionClass2, 100); - assert.strictEqual(result.length, 4, 'result length2'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'A'), 'A2'); - assertEqualRanges(result[1], foldRange(2, 100, false, false, 'B'), 'B2'); - assertEqualRanges(result[2], foldRange(20, 80, true, false, 'C1'), 'C2'); - assertEqualRanges(result[3], foldRange(22, 80, true, false, 'D2'), 'D2'); + const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); + assert.strictEqual(result.length, 3, 'result length1'); + assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'A'), 'A1'); + assertEqualRanges(result[1], foldRange(20, 80, true, State.none, 'C1'), 'C1'); + assertEqualRanges(result[2], foldRange(22, 80, true, State.none, 'D1'), 'D1'); }); test('sanitizeAndMerge2', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, false, 'a1'), // valid - foldRange(2, 100, false, false, 'a2'), // valid - foldRange(3, 19, false, false, 'a3'), // valid - foldRange(20, 71, false, false, 'a4'), // overlaps b3 - foldRange(21, 29, false, false, 'a5'), // valid - foldRange(81, 91, false, false, 'a6'), // overlaps b4 + foldRange(1, 100, false, State.none, 'a1'), // valid + foldRange(2, 100, false, State.none, 'a2'), // valid + foldRange(3, 19, false, State.none, 'a3'), // valid + foldRange(20, 71, false, State.none, 'a4'), // overlaps b3 + foldRange(21, 29, false, State.none, 'a5'), // valid + foldRange(81, 91, false, State.none, 'a6'), // overlaps b4 ]; const regionSet2: FoldRange[] = [ - foldRange(30, 39, false, false, 'b1'), // valid - foldRange(40, 49, false, false, 'b2'), // valid - foldRange(50, 100, false, false, 'b3'), // overlaps a4 - foldRange(80, 90, false, false, 'b4'), // overlaps a6 - foldRange(92, 100, false, false, 'b5'), // valid + foldRange(30, 39, true, State.none, 'b1'), // valid, will be recovered + foldRange(40, 49, true, State.userDefined, 'b2'), // valid + foldRange(50, 100, true, State.userDefined, 'b3'), // overlaps a4 + foldRange(80, 90, true, State.userDefined, 'b4'), // overlaps a6 + foldRange(92, 100, true, State.userDefined, 'b5'), // valid ]; - let result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); + const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 9, 'result length1'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'P1'); - assertEqualRanges(result[1], foldRange(2, 100, false, false, 'a2'), 'P2'); - assertEqualRanges(result[2], foldRange(3, 19, false, false, 'a3'), 'P3'); - assertEqualRanges(result[3], foldRange(21, 29, false, false, 'a5'), 'P4'); - assertEqualRanges(result[4], foldRange(30, 39, false, false, 'b1'), 'P5'); - assertEqualRanges(result[5], foldRange(40, 49, false, false, 'b2'), 'P6'); - assertEqualRanges(result[6], foldRange(50, 100, false, false, 'b3'), 'P7'); - assertEqualRanges(result[7], foldRange(80, 90, false, false, 'b4'), 'P8'); - assertEqualRanges(result[8], foldRange(92, 100, false, false, 'b5'), 'P9'); - // reverse the two inputs - result = FoldingRegions.sanitizeAndMerge(regionSet2, regionSet1, 100); - assert.strictEqual(result.length, 9, 'result length2'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'Q1'); - assertEqualRanges(result[1], foldRange(2, 100, false, false, 'a2'), 'Q2'); - assertEqualRanges(result[2], foldRange(3, 19, false, false, 'a3'), 'Q3'); - assertEqualRanges(result[3], foldRange(20, 71, false, false, 'a4'), 'Q4'); - assertEqualRanges(result[4], foldRange(21, 29, false, false, 'a5'), 'Q5'); - assertEqualRanges(result[5], foldRange(30, 39, false, false, 'b1'), 'Q6'); - assertEqualRanges(result[6], foldRange(40, 49, false, false, 'b2'), 'Q7'); - assertEqualRanges(result[7], foldRange(81, 91, false, false, 'a6'), 'Q8'); - assertEqualRanges(result[8], foldRange(92, 100, false, false, 'b5'), 'Q9'); + assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'P1'); + assertEqualRanges(result[1], foldRange(2, 100, false, State.none, 'a2'), 'P2'); + assertEqualRanges(result[2], foldRange(3, 19, false, State.none, 'a3'), 'P3'); + assertEqualRanges(result[3], foldRange(21, 29, false, State.none, 'a5'), 'P4'); + assertEqualRanges(result[4], foldRange(30, 39, true, State.recovered, 'b1'), 'P5'); + assertEqualRanges(result[5], foldRange(40, 49, true, State.userDefined, 'b2'), 'P6'); + assertEqualRanges(result[6], foldRange(50, 100, true, State.userDefined, 'b3'), 'P7'); + assertEqualRanges(result[7], foldRange(80, 90, true, State.userDefined, 'b4'), 'P8'); + assertEqualRanges(result[8], foldRange(92, 100, true, State.userDefined, 'b5'), 'P9'); }); test('sanitizeAndMerge3', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, false, 'a1'), // valid - foldRange(10, 29, false, false, 'a2'), // matches manual hidden - foldRange(35, 39, true, true, 'a3'), // valid + foldRange(1, 100, false, State.none, 'a1'), // valid + foldRange(10, 29, false, State.none, 'a2'), // matches manual hidden + foldRange(35, 39, true, State.recovered, 'a3'), // valid ]; const regionSet2: FoldRange[] = [ - foldRange(10, 29, true, true, 'b1'), // matches a - foldRange(20, 28, true, false, 'b2'), // should get dropped - foldRange(30, 39, true, true, 'b3'), // should remain + foldRange(10, 29, true, State.recovered, 'b1'), // matches a + foldRange(20, 28, true, State.none, 'b2'), // should remain + foldRange(30, 39, true, State.recovered, 'b3'), // should remain ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); - assert.strictEqual(result.length, 4, 'result length3'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'R1'); - assertEqualRanges(result[1], foldRange(10, 29, true, false, 'b1'), 'R2'); - assertEqualRanges(result[2], foldRange(30, 39, true, true, 'b3'), 'R3'); - assertEqualRanges(result[3], foldRange(35, 39, true, true, 'a3'), 'R4'); + assert.strictEqual(result.length, 5, 'result length3'); + assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'R1'); + assertEqualRanges(result[1], foldRange(10, 29, true, State.none, 'a2'), 'R2'); + assertEqualRanges(result[2], foldRange(20, 28, true, State.recovered, 'b2'), 'R3'); + assertEqualRanges(result[3], foldRange(30, 39, true, State.recovered, 'b3'), 'R3'); + assertEqualRanges(result[4], foldRange(35, 39, true, State.recovered, 'a3'), 'R4'); }); test('sanitizeAndMerge4', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, false, 'a1'), // valid + foldRange(1, 100, false, State.none, 'a1'), // valid ]; const regionSet2: FoldRange[] = [ - foldRange(20, 28, true, false, 'b1'), // hidden - foldRange(30, 38, true, false, 'b2'), // hidden + foldRange(20, 28, true, State.none, 'b1'), // hidden + foldRange(30, 38, true, State.none, 'b2'), // hidden ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 3, 'result length4'); - assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'R1'); - assertEqualRanges(result[1], foldRange(20, 28, true, true, 'b1'), 'R2'); - assertEqualRanges(result[2], foldRange(30, 38, true, true, 'b2'), 'R3'); + assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'R1'); + assertEqualRanges(result[1], foldRange(20, 28, true, State.recovered, 'b1'), 'R2'); + assertEqualRanges(result[2], foldRange(30, 38, true, State.recovered, 'b2'), 'R3'); }); }); From 087b9f7c4238caafe01f7e7b646aa8120d20ad49 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 16:02:17 +0200 Subject: [PATCH 039/179] Fix: implementing sticky scroll for when several outline elements end on the same line --- .../stickyScroll/browser/stickyScroll.ts | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 7846070e7ad..b658a0dafd1 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -105,10 +105,7 @@ class StickyScrollController implements IEditorContribution { if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { currentStartLine = outlineElement?.symbol.range.startLineNumber as number; currentEndLine = outlineElement?.symbol.range.endLineNumber as number; - const alreadyAdded = this._ranges.some(array => (array[0] === currentStartLine && array[1] === currentEndLine)); - if (!alreadyAdded) { - this._ranges.push([currentStartLine, currentEndLine, depth]); - } + this._ranges.push([currentStartLine, currentEndLine, depth]); depth--; } if (outlineElement.parent instanceof OutlineElement) { @@ -135,10 +132,21 @@ class StickyScrollController implements IEditorContribution { this._ranges = this._ranges.sort(function (a, b) { if (a[0] !== b[0]) { return a[0] - b[0]; - } else { + } else if (a[1] !== b[1]) { return b[1] - a[1]; + } else { + return a[2] - b[2]; } }); + let previous: number[] = []; + for (const [index, arr] of this._ranges.entries()) { + const [start, end, _depth] = arr; + if (previous[0] === start && previous[1] === end) { + this._ranges.splice(index, 1); + } else { + previous = arr; + } + } } } @@ -160,21 +168,26 @@ class StickyScrollController implements IEditorContribution { } this._lastScrollPosition = scrollTop; - const currentScrollTop: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight + 1; + const scrollTopFromLengthOfArray: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight + 1; this.stickyScrollWidget.emptyRootNode(); const beginningLinesConsidered = new Set(); + for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; + const scrollTopFromDepth: number = this._editor.getScrollTop() + depth * lineHeight + 1; + if (!beginningLinesConsidered.has(start)) { if (this._editor.getScrollTop() + (depth - 1) * lineHeight + 1 >= (end - 1) * lineHeight && this._editor.getScrollTop() + (depth - 1) * lineHeight < end * lineHeight - 2) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + end * lineHeight - this._editor.getScrollTop() - depth * lineHeight)); break; } - else if (scrollDirection === ScrollDirection.Down && currentScrollTop > (start - 1) * lineHeight && currentScrollTop < end * lineHeight) { + else if (scrollDirection === ScrollDirection.Down && scrollTopFromDepth > start * lineHeight && scrollTopFromDepth < end * lineHeight) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - } else if (scrollDirection === ScrollDirection.Up && currentScrollTop >= start * lineHeight && currentScrollTop <= end * lineHeight) { + + } else if (scrollDirection === ScrollDirection.Up && scrollTopFromLengthOfArray > start * lineHeight && scrollTopFromLengthOfArray < end * lineHeight || + scrollDirection === ScrollDirection.Up && scrollTopFromDepth >= start * lineHeight && scrollTopFromDepth < (end - 1) * lineHeight) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); } From 7d7df31b8ee43f21773db0de1ce5fdc8cb2f3441 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 25 Jul 2022 10:24:26 -0400 Subject: [PATCH 040/179] Temporarily remove explorer expand all (#156162) Remove expand all --- .../files/browser/views/explorerView.ts | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index e90d052ae29..6e15cf4d9c8 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -989,7 +989,7 @@ registerAction2(class extends Action2 { menu: { id: MenuId.ViewTitle, group: 'navigation', - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), ViewHasSomeCollapsibleRootItemContext), + when: ContextKeyExpr.equals('view', VIEW_ID), order: 40 } }); @@ -1001,26 +1001,3 @@ registerAction2(class extends Action2 { explorerView.collapseAll(); } }); - -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'workbench.files.action.expandExplorerFolders', - title: { value: nls.localize('expandExplorerFolders', "Expand Folders in Explorer"), original: 'Expand Folders in Explorer' }, - f1: true, - icon: Codicon.expandAll, - menu: { - id: MenuId.ViewTitle, - group: 'navigation', - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), ViewHasSomeCollapsibleRootItemContext.toNegated()), - order: 40 - } - }); - } - - run(accessor: ServicesAccessor) { - const viewsService = accessor.get(IViewsService); - const explorerView = viewsService.getViewWithId(VIEW_ID) as ExplorerView; - explorerView.expandAll(); - } -}); From 2af49c5bea16250ca4feea573c56ec1c81255257 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 25 Jul 2022 10:27:25 -0400 Subject: [PATCH 041/179] Revert "Support multiple partial registrations to resolver (#155859)" (#156157) * Revert "Support multiple partial registrations to resolver (#155859)" This reverts commit a3c4e5ffcee85677f1dd7e208cbd32bc84fee4d5. * Fix compilation --- src/vs/base/common/types.ts | 6 -- src/vs/workbench/browser/layout.ts | 2 +- src/vs/workbench/common/editor.ts | 6 +- .../mergeEditor/browser/commands/commands.ts | 23 +++---- .../browser/commands/devCommands.ts | 23 ++++--- .../mergeEditor/browser/mergeEditorInput.ts | 4 +- .../mergeEditor/browser/view/mergeEditor.ts | 43 ++++++++++--- .../userDataSync/browser/userDataSync.ts | 16 +++-- src/vs/workbench/electron-sandbox/window.ts | 2 +- .../editor/browser/editorResolverService.ts | 61 ++---------------- .../editor/common/editorResolverService.ts | 10 +-- .../browser/editorResolverService.test.ts | 63 ------------------- .../host/browser/browserHostService.ts | 2 +- 13 files changed, 84 insertions(+), 177 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index e3844cd39e8..3e1cb2a7354 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -275,9 +275,3 @@ export type UriDto = { [K in keyof T]: T[K] extends URI export function assertNever(value: never, message = 'Unreachable'): never { throw new Error(message); } - -/** - * Given an object with all optional properties, requires at least one to be defined. - * i.e. AtLeastOne; - */ -export type AtLeastOne }> = Partial & U[keyof U]; diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index d5f339775a3..9151c945a6c 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -578,7 +578,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi input2: { resource: filesToMerge[1].resource }, base: { resource: filesToMerge[2].resource }, result: { resource: filesToMerge[3].resource }, - options: { pinned: true } + options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready }]; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index a886ffaee13..6f6ab509248 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -484,8 +484,6 @@ export interface IResourceDiffEditorInput extends IBaseUntypedEditorInput { readonly modified: IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput; } -export type IResourceMergeEditorInputSide = (IResourceEditorInput | ITextResourceEditorInput) & { detail?: string }; - /** * A resource merge editor input compares multiple editors * highlighting the differences for merging. @@ -498,12 +496,12 @@ export interface IResourceMergeEditorInput extends IBaseUntypedEditorInput { /** * The one changed version of the file. */ - readonly input1: IResourceMergeEditorInputSide; + readonly input1: IResourceEditorInput | ITextResourceEditorInput; /** * The second changed version of the file. */ - readonly input2: IResourceMergeEditorInputSide; + readonly input2: IResourceEditorInput | ITextResourceEditorInput; /** * The base common ancestor of the file to merge. diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 36870ec2433..2f1dfdaef94 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -9,11 +9,11 @@ import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { EditorResolution } from 'vs/platform/editor/common/editor'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { IResourceMergeEditorInput } from 'vs/workbench/common/editor'; -import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; +import { MergeEditorInput, MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; import { ctxIsMergeEditor, ctxMergeEditorLayout } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; @@ -48,14 +48,15 @@ export class OpenMergeEditor extends Action2 { run(accessor: ServicesAccessor, ...args: unknown[]): void { const validatedArgs = IRelaxedOpenArgs.validate(args[0]); - const input: IResourceMergeEditorInput = { - base: { resource: validatedArgs.base }, - input1: { resource: validatedArgs.input1.uri, label: validatedArgs.input1.title, description: validatedArgs.input1.description, detail: validatedArgs.input1.detail }, - input2: { resource: validatedArgs.input2.uri, label: validatedArgs.input2.title, description: validatedArgs.input2.description, detail: validatedArgs.input2.detail }, - result: { resource: validatedArgs.output }, - options: { preserveFocus: true } - }; - accessor.get(IEditorService).openEditor(input); + const instaService = accessor.get(IInstantiationService); + const input = instaService.createInstance( + MergeEditorInput, + validatedArgs.base, + validatedArgs.input1, + validatedArgs.input2, + validatedArgs.output, + ); + accessor.get(IEditorService).openEditor(input, { preserveFocus: true, override: EditorResolution.DISABLED }); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts index 42cd0f7cc5a..17df90e7d26 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts @@ -10,15 +10,16 @@ import { localize } from 'vs/nls'; import { Action2 } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchFileService } from 'vs/workbench/services/files/common/files'; import { URI } from 'vs/base/common/uri'; -import { IResourceMergeEditorInput } from 'vs/workbench/common/editor'; +import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { ctxIsMergeEditor } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; +import { EditorResolution } from 'vs/platform/editor/common/editor'; interface MergeEditorContents { languageId: string; @@ -98,10 +99,11 @@ export class MergeEditorOpenContents extends Action2 { async run(accessor: ServicesAccessor): Promise { const service = accessor.get(IWorkbenchFileService); + const instaService = accessor.get(IInstantiationService); + const editorService = accessor.get(IEditorService); const inputService = accessor.get(IQuickInputService); const clipboardService = accessor.get(IClipboardService); const textModelService = accessor.get(ITextModelService); - const editorService = accessor.get(IEditorService); const result = await inputService.input({ prompt: localize('mergeEditor.enterJSON', 'Enter JSON'), @@ -152,12 +154,13 @@ export class MergeEditorOpenContents extends Action2 { setLanguageId(resultUri, content.languageId), ]); - const input: IResourceMergeEditorInput = { - base: { resource: baseUri }, - input1: { resource: input1Uri, label: 'Input 1', description: 'Input 1', detail: '(from JSON)' }, - input2: { resource: input2Uri, label: 'Input 2', description: 'Input 2', detail: '(from JSON)' }, - result: { resource: resultUri }, - }; - editorService.openEditor(input); + const input = instaService.createInstance( + MergeEditorInput, + baseUri, + { uri: input1Uri, title: 'Input 1', description: 'Input 1', detail: '(from JSON)' }, + { uri: input2Uri, title: 'Input 2', description: 'Input 2', detail: '(from JSON)' }, + resultUri, + ); + editorService.openEditor(input, { override: EditorResolution.DISABLED }); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 50470d8df66..9a4286f26b6 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -140,8 +140,8 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements override toUntyped(): IResourceMergeEditorInput { return { - input1: { resource: this.input1.uri, label: this.input1.title, description: this.input1.description, detail: this.input1.detail }, - input2: { resource: this.input2.uri, label: this.input2.title, description: this.input2.description, detail: this.input2.detail }, + input1: { resource: this.input1.uri, label: this.input1.title, description: this.input1.description }, + input2: { resource: this.input2.uri, label: this.input2.title, description: this.input2.description }, base: { resource: this.base }, result: { resource: this.result }, options: { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 46aee59e160..b17a1e8eebf 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -47,7 +47,7 @@ import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/v import { ctxMergeBaseUri, ctxIsMergeEditor, ctxMergeEditorLayout, ctxMergeResultUri, MergeEditorLayoutTypes } 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 { EditorInputFactoryFunction, IEditorResolverService, MergeEditorInputFactoryFunction, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import './colors'; import { InputCodeEditorView } from './editors/inputCodeEditorView'; @@ -559,6 +559,28 @@ export class MergeEditorResolverContribution extends Disposable { ) { super(); + const editorInputFactory: EditorInputFactoryFunction = (editor) => { + return { + editor: instantiationService.createInstance( + MergeEditorInput, + editor.resource, + { + uri: editor.resource, + title: '', + description: '', + detail: '' + }, + { + uri: editor.resource, + title: '', + description: '', + detail: '' + }, + editor.resource + ) + }; + }; + const mergeEditorInputFactory: MergeEditorInputFactoryFunction = (mergeEditor: IResourceMergeEditorInput): EditorInputWithOptions => { return { editor: instantiationService.createInstance( @@ -566,15 +588,15 @@ export class MergeEditorResolverContribution extends Disposable { mergeEditor.base.resource, { uri: mergeEditor.input1.resource, - title: mergeEditor.input1.label ?? basename(mergeEditor.input1.resource), - description: mergeEditor.input1.description ?? '', - detail: mergeEditor.input1.detail + title: basename(mergeEditor.input1.resource), + description: '', + detail: '' }, { uri: mergeEditor.input2.resource, - title: mergeEditor.input2.label ?? basename(mergeEditor.input2.resource), - description: mergeEditor.input2.description ?? '', - detail: mergeEditor.input2.detail + title: basename(mergeEditor.input2.resource), + description: '', + detail: '' }, mergeEditor.result.resource ) @@ -584,13 +606,14 @@ export class MergeEditorResolverContribution extends Disposable { this._register(editorResolverService.registerEditor( `*`, { - id: DEFAULT_EDITOR_ASSOCIATION.id, - label: DEFAULT_EDITOR_ASSOCIATION.displayName, + id: MergeEditorInput.ID, + label: localize('editor.mergeEditor.label', "Merge Editor"), detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName, - priority: RegisteredEditorPriority.builtin + priority: RegisteredEditorPriority.option }, {}, { + createEditorInput: editorInputFactory, createMergeEditorInput: mergeEditorInputFactory } )); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index d201a99a8a6..55f61b3c685 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -57,8 +57,10 @@ import { IUserDataInitializationService } from 'vs/workbench/services/userData/b import { MarkdownString } from 'vs/base/common/htmlContent'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ctxIsMergeEditor, ctxMergeBaseUri } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor'; +import { EditorResolution } from 'vs/platform/editor/common/editor'; const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', ''); @@ -728,12 +730,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo for (const conflict of conflicts) { const remoteResourceName = localize({ key: 'remoteResourceName', comment: ['remote as in file in cloud'] }, "{0} (Remote)", basename(conflict.remoteResource)); const localResourceName = localize('localResourceName', "{0} (Local)", basename(conflict.remoteResource)); - await this.editorService.openEditor({ - input1: { resource: conflict.remoteResource, label: localize('Theirs', 'Theirs'), description: remoteResourceName }, - input2: { resource: conflict.localResource, label: localize('Yours', 'Yours'), description: localResourceName }, - base: { resource: conflict.baseResource }, - result: { resource: conflict.previewResource } - }); + const input = this.instantiationService.createInstance( + MergeEditorInput, + conflict.baseResource, + { title: localize('Yours', 'Yours'), description: localResourceName, detail: undefined, uri: conflict.localResource }, + { title: localize('Theirs', 'Theirs'), description: remoteResourceName, detail: undefined, uri: conflict.remoteResource }, + conflict.previewResource, + ); + await this.editorService.openEditor(input, { override: EditorResolution.DISABLED }); } } diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 9e5dac68fbf..0d197e84c16 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -915,7 +915,7 @@ export class NativeWindow extends Disposable { input2: { resource: resources[1].resource }, base: { resource: resources[2].resource }, result: { resource: resources[3].resource }, - options: { pinned: true } + options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready }; editors.push(mergeEditor); } else if (diffMode && isResourceEditorInput(resources[0]) && isResourceEditorInput(resources[1])) { diff --git a/src/vs/workbench/services/editor/browser/editorResolverService.ts b/src/vs/workbench/services/editor/browser/editorResolverService.ts index c00b46869c6..ec9fc2b563b 100644 --- a/src/vs/workbench/services/editor/browser/editorResolverService.ts +++ b/src/vs/workbench/services/editor/browser/editorResolverService.ts @@ -51,8 +51,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver private static readonly conflictingDefaultsStorageID = 'editorOverrideService.conflictingDefaults'; // Data Stores - private _editors: Map> = new Map>(); - private _flattenedEditors: Map = new Map(); + private _editors: Map = new Map(); private cache: Set | undefined; constructor( @@ -236,29 +235,18 @@ export class EditorResolverService extends Disposable implements IEditorResolver ): IDisposable { let registeredEditor = this._editors.get(globPattern); if (registeredEditor === undefined) { - registeredEditor = new Map(); + registeredEditor = []; this._editors.set(globPattern, registeredEditor); } - - let editorsWithId = registeredEditor.get(editorInfo.id); - if (editorsWithId === undefined) { - editorsWithId = []; - } - const remove = insert(editorsWithId, { + const remove = insert(registeredEditor, { globPattern, editorInfo, options, editorFactoryObject }); - registeredEditor.set(editorInfo.id, editorsWithId); - this._flattenedEditors = this._flattenEditorsMap(); this._onDidChangeEditorRegistrations.fire(); return toDisposable(() => { remove(); - if (editorsWithId && editorsWithId.length === 0) { - registeredEditor?.delete(editorInfo.id); - } - this._flattenedEditors = this._flattenEditorsMap(); this._onDidChangeEditorRegistrations.fire(); }); } @@ -293,43 +281,11 @@ export class EditorResolverService extends Disposable implements IEditorResolver return associations; } - /** - * Given the nested nature of the editors map, we should merge factories of the same glob and id to make it flat - */ - private _flattenEditorsMap() { - const editors = new Map(); - for (const [glob, value] of this._editors) { - const registeredEditors: RegisteredEditors = []; - for (const editors of value.values()) { - let registeredEditor: RegisteredEditor | undefined = undefined; - // Merge all editors with the same id and glob pattern together - for (const editor of editors) { - if (!registeredEditor) { - registeredEditor = { - editorInfo: editor.editorInfo, - globPattern: editor.globPattern, - options: {}, - editorFactoryObject: {} - }; - } - // Merge options and factories - registeredEditor.options = { ...registeredEditor.options, ...editor.options }; - registeredEditor.editorFactoryObject = { ...registeredEditor.editorFactoryObject, ...editor.editorFactoryObject }; - } - if (registeredEditor) { - registeredEditors.push(registeredEditor); - } - } - editors.set(glob, registeredEditors); - } - return editors; - } - /** * Returns all editors as an array. Possible to contain duplicates */ private get _registeredEditors(): RegisteredEditors { - return flatten(Array.from(this._flattenedEditors.values())); + return flatten(Array.from(this._editors.values())); } updateUserAssociations(globPattern: string, editorID: string): void { @@ -350,7 +306,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver const userSettings = this.getAssociationsForResource(resource); const matchingEditors: RegisteredEditor[] = []; // Then all glob patterns - for (const [key, editors] of this._flattenedEditors) { + for (const [key, editors] of this._editors) { for (const editor of editors) { const foundInSettings = userSettings.find(setting => setting.viewType === editor.editorInfo.id); if ((foundInSettings && editor.editorInfo.priority !== RegisteredEditorPriority.exclusive) || globMatchesResource(key, resource)) { @@ -490,11 +446,6 @@ export class EditorResolverService extends Disposable implements IEditorResolver } } - // If no factory is above, return flow back to caller letting them know we could not resolve it - if (!selectedEditor.editorFactoryObject.createEditorInput) { - return; - } - // Respect options passed back const inputWithOptions = await selectedEditor.editorFactoryObject.createEditorInput(editor, group); options = inputWithOptions.options ?? options; @@ -788,7 +739,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver const cacheStorage: Set = new Set(); // Store just the relative pattern pieces without any path info - for (const [globPattern, contribPoint] of this._flattenedEditors) { + for (const [globPattern, contribPoint] of this._editors) { const nonOptional = !!contribPoint.find(c => c.editorInfo.priority !== RegisteredEditorPriority.option && c.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id); // Don't keep a cache of the optional ones as those wouldn't be opened on start anyways if (!nonOptional) { diff --git a/src/vs/workbench/services/editor/common/editorResolverService.ts b/src/vs/workbench/services/editor/common/editorResolverService.ts index 9de7b992657..b4e47e8d4f2 100644 --- a/src/vs/workbench/services/editor/common/editorResolverService.ts +++ b/src/vs/workbench/services/editor/common/editorResolverService.ts @@ -19,7 +19,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorInputWithOptions, EditorInputWithOptionsAndGroup, IResourceDiffEditorInput, IResourceMergeEditorInput, IUntitledTextResourceEditorInput, IUntypedEditorInput } from 'vs/workbench/common/editor'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { PreferredGroup } from 'vs/workbench/services/editor/common/editorService'; -import { AtLeastOne } from 'vs/base/common/types'; export const IEditorResolverService = createDecorator('editorResolverService'); @@ -110,15 +109,13 @@ export type DiffEditorInputFactoryFunction = (diffEditorInput: IResourceDiffEdit export type MergeEditorInputFactoryFunction = (mergeEditorInput: IResourceMergeEditorInput, group: IEditorGroup) => EditorInputFactoryResult; -type EditorInputFactories = { - createEditorInput?: EditorInputFactoryFunction; +export type EditorInputFactoryObject = { + createEditorInput: EditorInputFactoryFunction; createUntitledEditorInput?: UntitledEditorInputFactoryFunction; createDiffEditorInput?: DiffEditorInputFactoryFunction; createMergeEditorInput?: MergeEditorInputFactoryFunction; }; -export type EditorInputFactoryObject = AtLeastOne; - export interface IEditorResolverService { readonly _serviceBrand: undefined; /** @@ -141,8 +138,7 @@ export interface IEditorResolverService { readonly onDidChangeEditorRegistrations: Event; /** - * Registers a specific editor. Editors with the same glob pattern and ID will be grouped together by the resolver. - * This allows for registration of the factories in different locations + * Registers a specific editor. * @param globPattern The glob pattern for this registration * @param editorInfo Information about the registration * @param options Specific options which apply to this registration diff --git a/src/vs/workbench/services/editor/test/browser/editorResolverService.test.ts b/src/vs/workbench/services/editor/test/browser/editorResolverService.test.ts index 2b3a585ed5c..5bfe40ad314 100644 --- a/src/vs/workbench/services/editor/test/browser/editorResolverService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorResolverService.test.ts @@ -382,67 +382,4 @@ suite('EditorResolverService', () => { assert.strictEqual(service.getEditors().length, editors.length); assert.strictEqual(service.getEditors().some(editor => editor.id === 'TEST_EDITOR'), false); }); - - test('Multiple registrations to same glob and id #155859', async () => { - const [part, service, accessor] = await createEditorResolverService(); - const testEditorInfo = { - id: 'TEST_EDITOR', - label: 'Test Editor Label', - detail: 'Test Editor Details', - priority: RegisteredEditorPriority.default - }; - const registeredSingleEditor = service.registerEditor('*.test', - testEditorInfo, - {}, - { - createEditorInput: ({ resource, options }, group) => ({ editor: new TestFileEditorInput(URI.parse(resource.toString()), TEST_EDITOR_INPUT_ID) }) - } - ); - - const registeredDiffEditor = service.registerEditor('*.test', - testEditorInfo, - {}, - { - createDiffEditorInput: ({ modified, original, options }, group) => ({ - editor: accessor.instantiationService.createInstance( - DiffEditorInput, - 'name', - 'description', - new TestFileEditorInput(URI.parse(original.toString()), TEST_EDITOR_INPUT_ID), - new TestFileEditorInput(URI.parse(modified.toString()), TEST_EDITOR_INPUT_ID), - undefined) - }) - } - ); - - // Resolve a diff - let resultingResolution = await service.resolveEditor({ - original: { resource: URI.file('my://resource-basics.test') }, - modified: { resource: URI.file('my://resource-basics.test') } - }, part.activeGroup); - assert.ok(resultingResolution); - assert.notStrictEqual(typeof resultingResolution, 'number'); - if (resultingResolution !== ResolvedStatus.ABORT && resultingResolution !== ResolvedStatus.NONE) { - assert.strictEqual(resultingResolution.editor.typeId, 'workbench.editors.diffEditorInput'); - resultingResolution.editor.dispose(); - } else { - assert.fail(); - } - - // Remove diff registration - registeredDiffEditor.dispose(); - - // Resolve a diff again, expected failure - resultingResolution = await service.resolveEditor({ - original: { resource: URI.file('my://resource-basics.test') }, - modified: { resource: URI.file('my://resource-basics.test') } - }, part.activeGroup); - assert.ok(resultingResolution); - assert.strictEqual(typeof resultingResolution, 'number'); - if (resultingResolution !== ResolvedStatus.NONE) { - assert.fail(); - } - - registeredSingleEditor.dispose(); - }); }); diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index 25fca6a0136..0aebd31d5b9 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -268,7 +268,7 @@ export class BrowserHostService extends Disposable implements IHostService { input2: { resource: editors[1].resource }, base: { resource: editors[2].resource }, result: { resource: editors[3].resource }, - options: { pinned: true } + options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready }); } From 58dd7331a203211ea0a2ad99dbcdd2410c816e62 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 25 Jul 2022 16:34:39 +0200 Subject: [PATCH 042/179] Update src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts --- .../browser/bracketPairColorizer2Telemetry.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts index 62aab189b5e..c1051e9d4cf 100644 --- a/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts +++ b/src/vs/workbench/contrib/bracketPairColorizer2Telemetry/browser/bracketPairColorizer2Telemetry.contribution.ts @@ -39,7 +39,7 @@ class BracketPairColorizer2TelemetryContribution { type BracketPairColorizer2InstalledClassification = { owner: 'hediet'; - nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'See below' }; + nativeColorizationEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether or not built-in bracket pair colorization is being used' }; comment: 'We use this to understand how many users have the bracket pair colorizer extension installed (and how many of them have native bracket pair colorization enabled), as the extension does not do anything if native bracket pair colorization is enabled.'; }; type BracketPairColorizer2Event = { From 1a7d1b4230ea418f2261b1efe716513bca1d7b32 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 25 Jul 2022 10:37:32 -0400 Subject: [PATCH 043/179] Fix missing label changes (#156164) --- .github/workflows/deep-classifier-runner.yml | 2 +- .github/workflows/english-please.yml | 2 +- .github/workflows/needs-more-info-closer.yml | 6 +++--- .github/workflows/on-label.yml | 2 +- .github/workflows/on-open.yml | 2 +- .vscode/notebooks/inbox.github-issues | 2 +- .vscode/notebooks/my-work.github-issues | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml index bae2eeb1967..a966318ddef 100644 --- a/.github/workflows/deep-classifier-runner.yml +++ b/.github/workflows/deep-classifier-runner.yml @@ -46,7 +46,7 @@ jobs: uses: ./actions/classifier-deep/apply/apply-labels with: configPath: classifier - allowLabels: "needs more info|new release|error-telemetry|*english-please|translation-required" + allowLabels: "info-needed|new release|error-telemetry|*english-please|translation-required" appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} manifestDbConnectionString: ${{secrets.MANIFEST_DB_CONNECTION_STRING}} token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml index da8ca03ddd8..2f24b039125 100644 --- a/.github/workflows/english-please.yml +++ b/.github/workflows/english-please.yml @@ -24,6 +24,6 @@ jobs: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/needs-more-info-closer.yml b/.github/workflows/needs-more-info-closer.yml index 5e1f5b5c548..65805be0d51 100644 --- a/.github/workflows/needs-more-info-closer.yml +++ b/.github/workflows/needs-more-info-closer.yml @@ -1,4 +1,4 @@ -name: Needs More Info Closer +name: info-needed Closer on: schedule: - cron: 20 11 * * * # 4:20am Redmond @@ -17,12 +17,12 @@ jobs: ref: stable - name: Install Actions run: npm install --production --prefix ./actions - - name: Run Needs More Info Closer + - name: Run info-needed Closer uses: ./actions/needs-more-info-closer with: appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - label: needs more info + label: info-needed closeDays: 7 additionalTeam: "cleidigh|usernamehw|gjsjohnmurray|IllusionMH" closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" diff --git a/.github/workflows/on-label.yml b/.github/workflows/on-label.yml index 25f7a67c7a1..ae4c6f1419c 100644 --- a/.github/workflows/on-label.yml +++ b/.github/workflows/on-label.yml @@ -85,6 +85,6 @@ jobs: token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/on-open.yml b/.github/workflows/on-open.yml index af70c86caa0..3d800514a94 100644 --- a/.github/workflows/on-open.yml +++ b/.github/workflows/on-open.yml @@ -59,6 +59,6 @@ jobs: appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "needs more info" + needsMoreInfoLabel: "info-needed" translatorRequestedLabelPrefix: "translation-required-" translatorRequestedLabelColor: "c29cff" diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index ad451a6f91a..10d7fd63e54 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox -label:\"needs more info\" sort:created-desc" + "value": "$inbox -label:\"info-needed\" sort:created-desc" }, { "kind": 2, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index f50570078e6..f3c7a9c7c91 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -92,7 +92,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry" + "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"info-needed\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry" }, { "kind": 1, @@ -102,7 +102,7 @@ { "kind": 2, "language": "github-issues", - "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"needs more info\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:code-lens -label:color-palette -label:comments -label:config -label:context-keys -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-RTL -label:editor-scrollbar -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:engineering -label:error-list -label:extension-host -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:gpu -label:grammar -label:grid-view -label:html -label:i18n -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-window -label:ipc -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keyboard-layout -label:L10N -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list -label:live-server -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:network -label:notebook -label:notebook-api -label:notebook-celltoolbar -label:notebook-diff -label:notebook-dnd -label:notebook-folding -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-keybinding -label:notebook-layout -label:notebook-markdown -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-statusbar -label:open-editors -label:opener -label:outline -label:output -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remotehub -label:rename -label:sandbox -label:sash -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview -label:suggest -label:sync-error-handling -label:table -label:tasks -label:telemetry -label:terminal -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-links -label:terminal-local-echo -label:terminal-profiles -label:terminal-reconnection -label:terminal-rendering -label:terminal-tabs -label:terminal-winpty -label:testing -label:themes -label:timeline -label:timeline-git -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typehierarchy -label:typescript -label:undo-redo -label:uri -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-build -label:vscode-website -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-feedback -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom" + "value": "repo:microsoft/vscode assignee:@me is:open type:issue -label:\"info-needed\" -label:api -label:api-finalization -label:api-proposal -label:authentication -label:bisect-ext -label:bracket-pair-colorization -label:bracket-pair-guides -label:breadcrumbs -label:callhierarchy -label:chrome-devtools -label:code-lens -label:color-palette -label:comments -label:config -label:context-keys -label:css-less-scss -label:custom-editors -label:debug -label:debug-disassembly -label:dialogs -label:diff-editor -label:dropdown -label:editor -label:editor-autoclosing -label:editor-autoindent -label:editor-bracket-matching -label:editor-clipboard -label:editor-code-actions -label:editor-color-picker -label:editor-columnselect -label:editor-commands -label:editor-comments -label:editor-contrib -label:editor-core -label:editor-drag-and-drop -label:editor-error-widget -label:editor-find -label:editor-folding -label:editor-highlight -label:editor-hover -label:editor-indent-detection -label:editor-indent-guides -label:editor-input -label:editor-input-IME -label:editor-insets -label:editor-minimap -label:editor-multicursor -label:editor-parameter-hints -label:editor-render-whitespace -label:editor-rendering -label:editor-RTL -label:editor-scrollbar -label:editor-symbols -label:editor-synced-region -label:editor-textbuffer -label:editor-theming -label:editor-wordnav -label:editor-wrapping -label:emmet -label:engineering -label:error-list -label:extension-host -label:extension-recommendations -label:extensions -label:extensions-development -label:file-decorations -label:file-encoding -label:file-explorer -label:file-glob -label:file-io -label:file-watcher -label:font-rendering -label:formatting -label:getting-started -label:ghost-text -label:git -label:github -label:gpu -label:grammar -label:grid-view -label:html -label:i18n -label:icon-brand -label:icons-product -label:image-preview -label:inlay-hints -label:inline-completions -label:install-update -label:intellisense-config -label:interactive-window -label:ipc -label:issue-bot -label:issue-reporter -label:javascript -label:json -label:keybindings -label:keybindings-editor -label:keyboard-layout -label:L10N -label:label-provider -label:languages-basic -label:languages-diagnostics -label:languages-guessing -label:layout -label:lcd-text-rendering -label:list -label:live-server -label:log -label:markdown -label:marketplace -label:menus -label:merge-conflict -label:network -label:notebook -label:notebook-api -label:notebook-celltoolbar -label:notebook-diff -label:notebook-dnd -label:notebook-folding -label:notebook-globaltoolbar -label:notebook-ipynb -label:notebook-kernel -label:notebook-keybinding -label:notebook-layout -label:notebook-markdown -label:notebook-minimap -label:notebook-multiselect -label:notebook-output -label:notebook-perf -label:notebook-statusbar -label:open-editors -label:opener -label:outline -label:output -label:perf -label:perf-bloat -label:perf-startup -label:php -label:portable-mode -label:proxy -label:quick-open -label:quick-pick -label:references-viewlet -label:release-notes -label:remote -label:remote-connection -label:remote-explorer -label:remotehub -label:rename -label:sandbox -label:sash -label:scm -label:screencast-mode -label:search -label:search-api -label:search-editor -label:search-replace -label:semantic-tokens -label:settings-editor -label:settings-sync -label:settings-sync-server -label:shared-process -label:simple-file-dialog -label:smart-select -label:snap -label:snippets -label:splitview -label:suggest -label:sync-error-handling -label:table -label:tasks -label:telemetry -label:terminal -label:terminal-conpty -label:terminal-editors -label:terminal-external -label:terminal-links -label:terminal-local-echo -label:terminal-profiles -label:terminal-reconnection -label:terminal-rendering -label:terminal-tabs -label:terminal-winpty -label:testing -label:themes -label:timeline -label:timeline-git -label:titlebar -label:tokenization -label:touch/pointer -label:trackpad/scroll -label:tree-views -label:tree-widget -label:typehierarchy -label:typescript -label:undo-redo -label:uri -label:ux -label:variable-resolving -label:VIM -label:virtual-workspaces -label:vscode-build -label:vscode-website -label:web -label:webview -label:webview-views -label:workbench-actions -label:workbench-cli -label:workbench-diagnostics -label:workbench-dnd -label:workbench-editor-grid -label:workbench-editor-groups -label:workbench-editor-resolver -label:workbench-editors -label:workbench-electron -label:workbench-feedback -label:workbench-history -label:workbench-hot-exit -label:workbench-hover -label:workbench-launch -label:workbench-link -label:workbench-multiroot -label:workbench-notifications -label:workbench-os-integration -label:workbench-rapid-render -label:workbench-run-as-admin -label:workbench-state -label:workbench-status -label:workbench-tabs -label:workbench-touchbar -label:workbench-untitled-editors -label:workbench-views -label:workbench-welcome -label:workbench-window -label:workbench-zen -label:workspace-edit -label:workspace-symbols -label:workspace-trust -label:zoom" }, { "kind": 1, @@ -112,7 +112,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:\"needs more info\"" + "value": "$repos assignee:@me is:open label:\"info-needed\"" }, { "kind": 1, From ba6088a21a924991f4972c7519bb19e1d7466a55 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 25 Jul 2022 08:09:58 -0700 Subject: [PATCH 044/179] Use loading for running tests window progress (#155957) Fixes #155955 --- .../contrib/testing/browser/testingProgressUiService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/testing/browser/testingProgressUiService.ts b/src/vs/workbench/contrib/testing/browser/testingProgressUiService.ts index 69b323858b3..e8f1733a68f 100644 --- a/src/vs/workbench/contrib/testing/browser/testingProgressUiService.ts +++ b/src/vs/workbench/contrib/testing/browser/testingProgressUiService.ts @@ -129,6 +129,7 @@ export class TestingProgressUiService extends Disposable implements ITestingProg if (!this.windowProg.value) { this.windowProg.value = this.instantiaionService.createInstance(UnmanagedProgress, { location: ProgressLocation.Window, + type: 'loading' }); this.testViewProg.value = this.instantiaionService.createInstance(UnmanagedProgress, { location: Testing.ViewletId, From ac4d678fb94b50235aa6071e89b56d4e17607bb6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 25 Jul 2022 08:39:27 -0700 Subject: [PATCH 045/179] Support --locate-shell-integration-path in server CLI (#155870) * Fix shell-integration remote cli * Don't silently fail based on TERM_PROGRAM We want this to work even in terminals where TERM_PROGRAM may not exist, such as in a regular ssh session. The manual install recommends using an if before sourcing anyway. * Handle shell integration option on server cli * Move shell integration option handling higher --- src/vs/code/node/cli.ts | 4 ---- src/vs/server/node/server.cli.ts | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index c64e6fe0503..3a006e635a3 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -63,10 +63,6 @@ export async function main(argv: string[]): Promise { // Shell integration else if (args['locate-shell-integration-path']) { - // Silently fail when the terminal is not VS Code's integrated terminal - if (process.env['TERM_PROGRAM'] !== 'vscode') { - return; - } let file: string; switch (args['locate-shell-integration-path']) { // Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path bash)"` diff --git a/src/vs/server/node/server.cli.ts b/src/vs/server/node/server.cli.ts index 4c5ec7e1e2a..837b0b500d4 100644 --- a/src/vs/server/node/server.cli.ts +++ b/src/vs/server/node/server.cli.ts @@ -44,7 +44,6 @@ const isSupportedForCmd = (optionId: keyof RemoteParsedArgs) => { case 'enable-smoke-test-driver': case 'extensions-download-dir': case 'builtin-extensions-dir': - case 'locate-shell-integration-path': case 'telemetry': return false; default: @@ -74,6 +73,7 @@ const isSupportedForPipe = (optionId: keyof RemoteParsedArgs) => { case 'category': case 'verbose': case 'remote': + case 'locate-shell-integration-path': return true; default: return false; @@ -135,6 +135,20 @@ export function main(desc: ProductDescription, args: string[]): void { console.log(buildVersionMessage(desc.version, desc.commit)); return; } + if (parsedArgs['locate-shell-integration-path']) { + let file: string; + switch (parsedArgs['locate-shell-integration-path']) { + // Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path bash)"` + case 'bash': file = 'shellIntegration-bash.sh'; break; + // Usage: `if ($env:TERM_PROGRAM -eq "vscode") { . "$(code --locate-shell-integration-path pwsh)" }` + case 'pwsh': file = 'shellIntegration.ps1'; break; + // Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path zsh)"` + case 'zsh': file = 'shellIntegration-rc.zsh'; break; + default: throw new Error('Error using --locate-shell-integration-path: Invalid shell type'); + } + console.log(resolve(__dirname, '../..', 'workbench', 'contrib', 'terminal', 'browser', 'media', file)); + return; + } if (cliPipe) { if (parsedArgs['openExternal']) { openInBrowser(parsedArgs['_'], verbose); @@ -218,7 +232,6 @@ export function main(desc: ProductDescription, args: string[]): void { return; } - const newCommandline: string[] = []; for (const key in parsedArgs) { const val = parsedArgs[key as keyof typeof parsedArgs]; From 62f7d899511819c0a73239d9e229006c2bc57287 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 17:40:21 +0200 Subject: [PATCH 046/179] cleaning the code with the review --- .../stickyScroll/browser/stickyScroll.ts | 47 +++++++++++-------- src/vs/platform/theme/common/colorRegistry.ts | 4 +- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index b658a0dafd1..253932714eb 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -33,7 +33,7 @@ class StickyScrollController implements IEditorContribution { private readonly _store: DisposableStore = new DisposableStore(); private readonly _sessionStore: DisposableStore = new DisposableStore(); - private _ranges: any[][] = []; + private _ranges: [number, number, number][] = []; private _cts: CancellationTokenSource | undefined; private _lastScrollPosition: number = -1; @@ -156,7 +156,7 @@ class StickyScrollController implements IEditorContribution { return; } - const lineHeight = this._editor.getOption(EditorOption.lineHeight); + const lineHeight: number = this._editor.getOption(EditorOption.lineHeight); const model = this._editor.getModel(); const scrollTop = this._editor.getScrollTop(); @@ -168,26 +168,35 @@ class StickyScrollController implements IEditorContribution { } this._lastScrollPosition = scrollTop; - const scrollTopFromLengthOfArray: number = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight + 1; + const scrollToBottomOfWidget = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight; this.stickyScrollWidget.emptyRootNode(); - const beginningLinesConsidered = new Set(); + const beginningLinesConsidered: Set = new Set(); + let topOfElementAtDepth: number; + let bottomOfElementAtDepth: number; + let bottomOfBeginningLine: number; + let topOfEndLine: number; + let bottomOfEndLine: number; for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; - const scrollTopFromDepth: number = this._editor.getScrollTop() + depth * lineHeight + 1; + topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; + bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; + bottomOfBeginningLine = start * lineHeight; + topOfEndLine = (end - 1) * lineHeight; + bottomOfEndLine = end * lineHeight; if (!beginningLinesConsidered.has(start)) { - if (this._editor.getScrollTop() + (depth - 1) * lineHeight + 1 >= (end - 1) * lineHeight && this._editor.getScrollTop() + (depth - 1) * lineHeight < end * lineHeight - 2) { + if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + end * lineHeight - this._editor.getScrollTop() - depth * lineHeight)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + bottomOfEndLine - bottomOfElementAtDepth)); break; } - else if (scrollDirection === ScrollDirection.Down && scrollTopFromDepth > start * lineHeight && scrollTopFromDepth < end * lineHeight) { + else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - } else if (scrollDirection === ScrollDirection.Up && scrollTopFromLengthOfArray > start * lineHeight && scrollTopFromLengthOfArray < end * lineHeight || - scrollDirection === ScrollDirection.Up && scrollTopFromDepth >= start * lineHeight && scrollTopFromDepth < (end - 1) * lineHeight) { + } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || + scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); } @@ -236,19 +245,19 @@ class StickyScrollCodeLine { lineHTMLNode.style.paddingLeft = this._editor.getLayoutInfo().contentLeft - this._editor.getLayoutInfo().lineNumbersLeft - this._editor.getLayoutInfo().lineNumbersWidth + 'px'; lineHTMLNode.style.float = 'left'; lineHTMLNode.style.width = this._editor.getLayoutInfo().width - this._editor.getLayoutInfo().contentLeft + 'px'; - lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineHTMLNode.innerHTML = newLine as string; const lineNumberHTMLNode = document.createElement('div'); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; - lineNumberHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; const innerLineNumberHTML = document.createElement('div'); innerLineNumberHTML.innerText = this._lineNumber.toString(); innerLineNumberHTML.style.paddingLeft = this._editor.getLayoutInfo().lineNumbersLeft.toString() + 'px'; innerLineNumberHTML.style.width = this._editor.getLayoutInfo().lineNumbersWidth.toString() + 'px'; - innerLineNumberHTML.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + innerLineNumberHTML.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; innerLineNumberHTML.style.textAlign = 'right'; innerLineNumberHTML.style.float = 'left'; lineNumberHTMLNode.appendChild(innerLineNumberHTML); @@ -259,14 +268,14 @@ class StickyScrollCodeLine { this._editor.revealLine(this._lineNumber); }; lineHTMLNode.onmouseover = e => { - innerLineNumberHTML.style.background = `var(--vscode-stickyScrollHover-background)`; - lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScrollHover-background)`; + innerLineNumberHTML.style.background = `var(--vscode-editorStickyScrollHover-background)`; + lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; innerLineNumberHTML.style.cursor = `pointer`; lineHTMLNode.style.cursor = `pointer`; }; lineHTMLNode.onmouseleave = e => { - innerLineNumberHTML.style.background = `var(--vscode-stickyScroll-background)`; - lineHTMLNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + innerLineNumberHTML.style.background = `var(--vscode-editorStickyScroll-background)`; + lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; }; this._editor.applyFontInfo(lineHTMLNode); @@ -276,7 +285,7 @@ class StickyScrollCodeLine { root.appendChild(lineHTMLNode); root.style.zIndex = this._zIndex.toString(); - root.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; // Special case for last line of sticky scroll if (this._position) { @@ -323,7 +332,7 @@ class StickyScrollWidget implements IOverlayWidget { getDomNode(): HTMLElement { this.rootDomNode.style.zIndex = '2'; - this.rootDomNode.style.backgroundColor = `var(--vscode-stickyScroll-background)`; + this.rootDomNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; return this.rootDomNode; } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 83ad45a9fad..b7c105aa09d 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -317,8 +317,8 @@ export const editorForeground = registerColor('editor.foreground', { light: '#33 /** * Sticky scroll */ -export const stickyScrollBackground = registerColor('stickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('stickyScrollBackground', "Sticky scroll background color")); -export const stickyScrollHoverBackground = registerColor('stickyScrollHover.background', { light: darken(editorBackground, 0.4), dark: lighten(editorBackground, 0.4), hcDark: lighten(editorBackground, 0.4), hcLight: darken(editorBackground, 0.4) }, nls.localize('stickyScrollHoverBackground', "Sticky scroll on hover background color")); +export const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('editorStickyScrollBackground', "Sticky scroll background color for the editor")); +export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { light: darken(editorBackground, 0.4), dark: lighten(editorBackground, 0.4), hcDark: lighten(editorBackground, 0.4), hcLight: darken(editorBackground, 0.4) }, nls.localize('editorStickyScrollHoverBackground', "Sticky scroll on hover background color for the editor")); /** * Editor widgets From c4141cf1cb6a05d76eb8f861b3e14d989e13806f Mon Sep 17 00:00:00 2001 From: Svante Boberg Date: Mon, 25 Jul 2022 17:53:14 +0200 Subject: [PATCH 047/179] Add missing disposals (#155976) * Add missing disposals I did some V8 heap profiling and found a few more places where references to closed terminals prevents them from being garbage collected. * Let closed terminals be garbage collected Action bars are not disposed when a terminal is closed, they are cached in the list until you open a new terminal, so manually clear it to make it possible to garbage collect the closed terminal directly. --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 6 +++--- .../workbench/contrib/terminal/browser/terminalTabsList.ts | 2 ++ .../contrib/terminal/browser/xterm/decorationAddon.ts | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 09736ecd0b0..a2993cbc0fa 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -537,7 +537,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._labelComputer?.refreshLabel(); } })); - this._workspaceContextService.onDidChangeWorkspaceFolders(() => this._labelComputer?.refreshLabel()); + this.addDisposable(this._workspaceContextService.onDidChangeWorkspaceFolders(() => this._labelComputer?.refreshLabel())); // Clear out initial data events after 10 seconds, hopefully extension hosts are up and // running at that point. @@ -760,11 +760,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._loadTypeAheadAddon(xterm); - this._configurationService.onDidChangeConfiguration(e => { + this.addDisposable(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TerminalSettingId.LocalEchoEnabled)) { this._loadTypeAheadAddon(xterm); } - }); + })); this._pathService.userHome().then(userHome => { this._userHome = userHome.fsPath; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index d262afd51fb..2b1b063de2d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -458,12 +458,14 @@ class TerminalTabsRenderer implements IListRenderer this._contextMenuVisible = false)); this._hoverDelayer = this._register(new Delayer(this._configurationService.getValue('workbench.hover.delay'))); - this._configurationService.onDidChangeConfiguration(e => { + this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationIcon) || e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationIconSuccess) || e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationIconError)) { @@ -92,8 +92,8 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } this._updateDecorationVisibility(); } - }); - this._themeService.onDidColorThemeChange(() => this._refreshStyles(true)); + })); + this._register(this._themeService.onDidColorThemeChange(() => this._refreshStyles(true))); this._updateDecorationVisibility(); this._register(this._capabilities.onDidAddCapability(c => { if (c === TerminalCapability.CommandDetection) { From 361215a16876075d6fce78f98ba39c903df68b83 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 25 Jul 2022 18:17:23 +0200 Subject: [PATCH 048/179] seperate out devContainer schemas for vscode & codespaces (#156170) * seperateout devContainer schemas for vscode & codespaces * fix for vscode schema --- .../devContainer.codespaces.schema.json | 182 ++++++++++++++++++ .../schemas/devContainer.vscode.schema.json | 33 ++++ 2 files changed, 215 insertions(+) create mode 100644 extensions/configuration-editing/schemas/devContainer.codespaces.schema.json create mode 100644 extensions/configuration-editing/schemas/devContainer.vscode.schema.json diff --git a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json new file mode 100644 index 00000000000..6186ccd86ac --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json @@ -0,0 +1,182 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "customizations": { + "type": "object", + "properties": { + "codespaces": { + "type": "object", + "description": "Customizations specific to GitHub Codespaces", + "properties": { + "repositories": { + "type": "object", + "description": "Configuration relative to the given repositories, following the format 'owner/repo'.\n A wildcard (*) is permitted for the repo name (eg: 'microsoft/*')", + "patternProperties": { + "^[a-zA-Z0-9-_.]+[.]*\/[a-zA-Z0-9-_*]+[.]*$": { + "type": "object", + "additionalProperties": true, + "oneOf": [ + { + "properties": { + "permissions": { + "type": "object", + "description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.", + "additionalProperties": true, + "anyOf": [ + { + "properties": { + "actions": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "checks": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "contents": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "deployments": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "discussions": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "issues": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "packages": { + "type": "string", + "enum": [ + "read" + ] + } + } + }, + { + "properties": { + "pages": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "pull_requests": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "repository_projects": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "statuses": { + "type": "string", + "enum": [ + "read", + "write" + ] + } + } + }, + { + "properties": { + "workflows": { + "type": "string", + "enum": [ + "write" + ] + } + } + } + ] + } + } + }, + { + "properties": { + "permissions": { + "type": "string", + "description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.", + "enum": [ + "read-all", + "write-all" + ] + } + } + } + ] + } + } + } + } + } + } + } + } +} diff --git a/extensions/configuration-editing/schemas/devContainer.vscode.schema.json b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json new file mode 100644 index 00000000000..4eb7a2f62dc --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "customizations": { + "type": "object", + "properties": { + "vscode": { + "type": "object", + "properties": { + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string", + "pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$", + "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." + } + }, + "settings": { + "$ref": "vscode://schemas/settings/machine", + "description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again." + }, + "devPort": { + "type": "integer", + "description": "The port VS Code can use to connect to its backend." + } + } + } + } + } + } +} From 552e6fe4b1af14ebb56d948324c7c8a856aeab69 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 25 Jul 2022 10:53:10 -0700 Subject: [PATCH 049/179] debug: potential fix for unit test flake (#156177) Fixes #155801 --- .../contrib/debug/test/node/streamDebugAdapter.test.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts b/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts index 06ea6440b6c..c0ffe9dd115 100644 --- a/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts +++ b/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts @@ -49,7 +49,13 @@ suite('Debug - StreamDebugAdapter', () => { const pipeName = crypto.randomBytes(10).toString('hex'); const pipePath = platform.isWindows ? join('\\\\.\\pipe\\', pipeName) : join(tmpdir(), pipeName); - const server = net.createServer(serverConnection).listen(pipePath); + const server = await new Promise((resolve, reject) => { + const server = net.createServer(serverConnection); + server.once('listening', () => resolve(server)); + server.once('error', reject); + server.listen(pipePath); + }); + const debugAdapter = new NamedPipeDebugAdapter({ type: 'pipeServer', path: pipePath From 52a71a1843373480e0bb72820bb31e8aae6f75ba Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Mon, 25 Jul 2022 11:00:36 -0700 Subject: [PATCH 050/179] Make some Emmet settings language-overridable (#156184) Fixes #156075 --- extensions/emmet/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index d9deee50fb3..9cbe3bf74a6 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -65,6 +65,7 @@ "emmet.showAbbreviationSuggestions": { "type": "boolean", "default": true, + "scope": "language-overridable", "markdownDescription": "%emmetShowAbbreviationSuggestions%" }, "emmet.includeLanguages": { @@ -125,6 +126,7 @@ "emmet.triggerExpansionOnTab": { "type": "boolean", "default": false, + "scope": "language-overridable", "markdownDescription": "%emmetTriggerExpansionOnTab%" }, "emmet.useInlineCompletions": { From 3e8a8ee109e2ec9d300b74ff401547e9b7652d49 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 25 Jul 2022 20:02:01 +0200 Subject: [PATCH 051/179] Export workspace for web (#156181) --- src/vs/workbench/workbench.web.main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index a71d4de98e3..3176a04cdb2 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -176,7 +176,7 @@ import 'vs/workbench/contrib/offline/browser/offline.contribution'; // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -import { create, commands, env, window, logger } from 'vs/workbench/browser/web.factory'; +import { create, commands, env, window, workspace, logger } from 'vs/workbench/browser/web.factory'; import { IWorkbench, ICommand, ICommonTelemetryPropertiesResolver, IDefaultEditor, IDefaultLayout, IDefaultView, IDevelopmentOptions, IExternalUriResolver, IExternalURLOpener, IHomeIndicator, IInitialColorTheme, IPosition, IProductQualityChangeHandler, IRange, IResourceUriProvider, ISettingsSyncOptions, IShowPortCandidate, ITunnel, ITunnelFactory, ITunnelOptions, ITunnelProvider, IWelcomeBanner, IWelcomeBannerAction, IWindowIndicator, IWorkbenchConstructionOptions, Menu } from 'vs/workbench/browser/web.api'; import { UriComponents, URI } from 'vs/base/common/uri'; import { IWebSocketFactory, IWebSocket } from 'vs/platform/remote/browser/browserSocketFactory'; @@ -281,6 +281,9 @@ export { // Env env, + // Workspace + workspace, + // Development IDevelopmentOptions }; From 458d44cfc4bd2e22a1ba658e8581606a0a3a55f9 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 20:03:42 +0200 Subject: [PATCH 052/179] Fix: incorrect calculation of the depth --- .../stickyScroll/browser/stickyScroll.ts | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 253932714eb..76ec620a310 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -126,30 +126,34 @@ class StickyScrollController implements IEditorContribution { this._ranges = []; for (const outline of outlineModel.children.values()) { if (outline instanceof OutlineElement) { - this._findLineRanges(outline, 1); + const kind: SymbolKind = outline.symbol.kind; + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { + this._findLineRanges(outline, 1); + } else { + this._findLineRanges(outline, 0); + } } - } - this._ranges = this._ranges.sort(function (a, b) { - if (a[0] !== b[0]) { - return a[0] - b[0]; - } else if (a[1] !== b[1]) { - return b[1] - a[1]; - } else { - return a[2] - b[2]; - } - }); - let previous: number[] = []; - for (const [index, arr] of this._ranges.entries()) { - const [start, end, _depth] = arr; - if (previous[0] === start && previous[1] === end) { - this._ranges.splice(index, 1); - } else { - previous = arr; + this._ranges = this._ranges.sort(function (a, b) { + if (a[0] !== b[0]) { + return a[0] - b[0]; + } else if (a[1] !== b[1]) { + return b[1] - a[1]; + } else { + return a[2] - b[2]; + } + }); + let previous: number[] = []; + for (const [index, arr] of this._ranges.entries()) { + const [start, end, _depth] = arr; + if (previous[0] === start && previous[1] === end) { + this._ranges.splice(index, 1); + } else { + previous = arr; + } } } } } - private _renderStickyScroll() { if (!(this._editor.hasModel())) { From 3c873277c9a6e37cf71e86356b04db1822c6f2ee Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 20:24:23 +0200 Subject: [PATCH 053/179] Added try catch block for the case when LineDecorations.filter returns an error --- .../editor/contrib/stickyScroll/browser/stickyScroll.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 76ec620a310..d37817b72aa 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -230,7 +230,13 @@ class StickyScrollCodeLine { const root: HTMLElement = document.createElement('div'); const modifiedLine = this._line.replace(/\s/g, '\xa0'); const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); - const actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); + let actualInlineDecorations: LineDecoration[]; + try { + actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); + } catch (err) { + console.log(err); + actualInlineDecorations = []; + } const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 500, 'none', true, true, null); From 242e0b3602a931e1d2a64415f5d035ef926488d1 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 20:27:46 +0200 Subject: [PATCH 054/179] limiting the number of characters rendered on one line to 100 to avoid overflow on several lines --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index d37817b72aa..8de7e41b395 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -239,7 +239,7 @@ class StickyScrollCodeLine { } const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, - lineRenderingData.startVisibleColumn, 1, 1, 1, 500, 'none', true, true, null); + lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null); const sb = createStringBuilder(2000); renderViewLine(renderLineInput, sb); From d98ae61984ff0652d54d3324afb11bbf68e428cb Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 25 Jul 2022 21:01:27 +0200 Subject: [PATCH 055/179] Fix #155878 (#156197) --- .../configuration/browser/configurationService.ts | 8 +++++++- .../services/keybinding/browser/keybindingService.ts | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 3dc4ea6419e..6dd1c75a6c2 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -717,7 +717,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat if (e.preserveData) { await Promise.all([ this.copyProfileSettings(e.previous.settingsResource, e.profile.settingsResource), - this.fileService.copy(e.previous.tasksResource, e.profile.tasksResource) + this.copyProfileTasks(e.previous.tasksResource, e.profile.tasksResource) ]); } const promises: Promise[] = []; @@ -751,6 +751,12 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat await this.fileService.writeFile(to, VSBuffer.fromString(toContent)); } + private async copyProfileTasks(from: URI, to: URI): Promise { + if (await this.fileService.exists(from)) { + await this.fileService.copy(from, to); + } + } + private onDefaultConfigurationChanged(configurationModel: ConfigurationModel, properties?: string[]): void { if (this.workspace) { const previousData = this._configuration.toData(); diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index fe4650f771f..f75556ad8a3 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -743,7 +743,9 @@ class UserKeybindings extends Disposable { private async whenCurrentProfieChanged(e: DidChangeUserDataProfileEvent): Promise { if (e.preserveData) { - await this.fileService.copy(e.previous.keybindingsResource, e.profile.keybindingsResource); + if (await this.fileService.exists(e.previous.keybindingsResource)) { + await this.fileService.copy(e.previous.keybindingsResource, e.profile.keybindingsResource); + } } this.watch(); this.reloadConfigurationScheduler.schedule(); From 158fa8817107661d00aba542fd8f0fbc879668f9 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Mon, 25 Jul 2022 21:19:53 +0200 Subject: [PATCH 056/179] fixing : incorrect indentation, needed to take into account not only spaces but tabs too --- .../contrib/stickyScroll/browser/stickyScroll.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 8de7e41b395..2e8a9704125 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -224,24 +224,28 @@ class StickyScrollCodeLine { constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, private readonly _zIndex: number, private readonly _position?: number) { } + replaceTabAndSpacesWithNbsp(str: string, tabSize: number = 4): string { + return str.replace('\t', '\xa0'.repeat(tabSize)).replace(' ', '\xa0'); + } getDomNode() { const root: HTMLElement = document.createElement('div'); - const modifiedLine = this._line.replace(/\s/g, '\xa0'); const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); + let actualInlineDecorations: LineDecoration[]; try { actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); } catch (err) { - console.log(err); actualInlineDecorations = []; } + + const modifiedLine = this.replaceTabAndSpacesWithNbsp(this._line, lineRenderingData.tabSize); const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null); - const sb = createStringBuilder(2000); + const sb = createStringBuilder(400); renderViewLine(renderLineInput, sb); let newLine; From 7163116004eb3505c443b212d5c3df8796fe87bf Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 25 Jul 2022 15:27:29 -0400 Subject: [PATCH 057/179] Update label triage-needed (#156202) --- .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 c0a6e4403b3..25b9625ef31 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -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:needs-triage -label:verification-found" + "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" }, { "kind": 1, From 9d422d290172dc3ee3bca2f1b082dfc7b053b9ff Mon Sep 17 00:00:00 2001 From: Evan Spensley <94762716+0evan@users.noreply.github.com> Date: Mon, 25 Jul 2022 15:28:44 -0400 Subject: [PATCH 058/179] Distinguish testing decoration labels (#155433) * Distinguish testing decoration labels * fixup! tweak to avoid prototype issues Co-authored-by: Connor Peet --- .../testing/browser/testingDecorations.ts | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 718807b102e..d42faa01aa9 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -815,11 +815,39 @@ class MultiRunTestDecoration extends RunTestDecoration implements ITestDecoratio allActions.push(new Action('testing.gutter.debugAll', localize('debug all test', 'Debug All Tests'), undefined, undefined, () => this.defaultDebug())); } + const testItems = this.tests.map(testItem => ({ + currentLabel: testItem.test.item.label, + testItem, + parent: testItem.test.parent, + })); + + const getLabelConflicts = (tests: typeof testItems) => { + const labelCount = new Map(); + for (const test of tests) { + labelCount.set(test.currentLabel, (labelCount.get(test.currentLabel) || 0) + 1); + } + + return tests.filter(e => labelCount.get(e.currentLabel)! > 1); + }; + + let conflicts, hasParent = true; + while ((conflicts = getLabelConflicts(testItems)).length && hasParent) { + for (const conflict of conflicts) { + if (conflict.parent) { + const parent = this.testService.collection.getNodeById(conflict.parent); + conflict.currentLabel = parent?.item.label + ' > ' + conflict.currentLabel; + conflict.parent = parent?.parent ? parent.parent : null; + } else { + hasParent = false; + } + } + } + const disposable = new DisposableStore(); - const testSubmenus = this.tests.map(({ test, resultItem }) => { - const actions = this.getTestContextMenuActions(test, resultItem); + const testSubmenus = testItems.map(({ currentLabel, testItem }) => { + const actions = this.getTestContextMenuActions(testItem.test, testItem.resultItem); disposable.add(actions); - return new SubmenuAction(test.item.extId, stripIcons(test.item.label), actions.object); + return new SubmenuAction(testItem.test.item.extId, stripIcons(currentLabel), actions.object); }); return { object: Separator.join(allActions, testSubmenus), dispose: () => disposable.dispose() }; From 1a73ce68ae43d25491724ebef591dcb488bb746e Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Mon, 25 Jul 2022 12:43:14 -0700 Subject: [PATCH 059/179] fix search selection bug (#156205) --- .../contrib/search/browser/searchActions.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index dc0023470ab..4b503feac04 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -456,7 +456,8 @@ class ReplaceActionRunner { async performReplace(element: FolderMatch | FileMatch | Match): Promise { // since multiple elements can be selected, we need to check the type of the FolderMatch/FileMatch/Match before we perform the replace. - const elementsToReplace = getElementsToOperateOnInfo(this.viewer, element, this.configurationService.getValue('search')); + const opInfo = getElementsToOperateOnInfo(this.viewer, element, this.configurationService.getValue('search')); + const elementsToReplace = opInfo.elements; await Promise.all(elementsToReplace.map(async (elem) => { const parent = elem.parent(); @@ -585,11 +586,12 @@ export class RemoveAction extends AbstractSearchAndReplaceAction { } override run(): Promise { - const elementsToRemove = getElementsToOperateOnInfo(this.viewer, this.element, this.configurationService.getValue('search')); + const opInfo = getElementsToOperateOnInfo(this.viewer, this.element, this.configurationService.getValue('search')); + const elementsToRemove = opInfo.elements; const currentBottomFocusElement = elementsToRemove[elementsToRemove.length - 1]; - const nextFocusElement = !currentBottomFocusElement || currentBottomFocusElement instanceof SearchResult || arrayContainsElementOrParent(currentBottomFocusElement, elementsToRemove) ? + const nextFocusElement = opInfo.mustReselect && (!currentBottomFocusElement || currentBottomFocusElement instanceof SearchResult || arrayContainsElementOrParent(currentBottomFocusElement, elementsToRemove)) ? this.getElementToFocusAfterRemoved(this.viewer, currentBottomFocusElement) : null; @@ -823,13 +825,15 @@ export const focusSearchListCommand: ICommandHandler = accessor => { }); }; -function getElementsToOperateOnInfo(viewer: WorkbenchObjectTree, currElement: RenderableMatch, sortConfig: ISearchConfigurationProperties): RenderableMatch[] { +function getElementsToOperateOnInfo(viewer: WorkbenchObjectTree, 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. + // if selection doesn't include multiple elements, just return current focus element. if (!(elements.length > 1 && elements.includes(currElement))) { elements = [currElement]; } - return elements; + return { elements, mustReselect }; } From 0b7a99104df3ae724d48cbf4a6b8b3330b3dcb58 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 25 Jul 2022 22:35:30 +0200 Subject: [PATCH 060/179] theme-seti icon Laravel .blade.php lose php icon when installing blade related extension (#156204) theme-seti icon Laravel .blade.php lose php icon when installing blade related extension. Fixes #153410 --- .../theme-seti/build/update-icon-theme.js | 3 ++- extensions/theme-seti/cgmanifest.json | 2 +- extensions/theme-seti/icons/seti.woff | Bin 37192 -> 37200 bytes .../theme-seti/icons/vs-seti-icon-theme.json | 10 +++++++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index 66e11c16c5e..c55af7ab7fe 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -45,7 +45,8 @@ const nonBuiltInLanguages = { // { fileNames, extensions } const inheritIconFromLanguage = { "jsonc": 'json', "postcss": 'css', - "django-html": 'html' + "django-html": 'html', + "blade": 'php' } const FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json index 983ec9c5157..919b27b7c91 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": "4dd6c27e1f5aed8068c2451dbaf0db3364545937" + "commitHash": "2d10473b7575ec00c47eda751ea9caeec6b0b606" } }, "version": "0.1.0" diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff index 24cde7296648c637c0f140bb90bb1a1f2986ec09..f0e47486995b58f1484c564f76d10182211ecd47 100644 GIT binary patch delta 15074 zcmV<8IvvHxq5{yO0t|OgMn(Vu00000kx-EgXMcDA0K~u>1YiwlWnp9h0E%b;001rk z001^1`hC1;Xk}pl0E(CZ000~S001NhyaiHdZFG150E)B#001oj00M-0Qvd*LZ)0Hq z0E*-Q00Be*00BfE&ro`8VR&!=0E{RA0018V001BYdI}J3VQpmq0E|cg00ABV00HLS zN(vdwaBp*T0050>vHTNCf8?mnL@OdPBQkPdDl@C!axcg>@z04f3Psc0CSk7bh;YM zyDsPz8^E{5=)=}RBR|1)gkdns$PCUNQOM%`x3rDOZTm0!@Z`4U+FFy`-&~`sleaZD zL95$1|Jb8U{r{^+r+>^`YfkP^SH88mHVL;b-r734`Gw)|4E*o)zCBEaWq4r~^R?2q zvMWII85E8bE-hSFe|UbOFm5YxiHqex?ETnfNXJ0xK$Xg$e7M7ggLT>+_SIrzXVwBX z`_chMf(|RV&o^j^AxytsEQV^62j;?ePX#s8v}|cs!&AY0+4mf~9?%b2rdbP4`HiyY zm*<01VbzrOh2N@nvO}G0KK~#ed?D?e7#?}e^Ip51Ufp{4e{ILcb7_6)Eeoes7jGFI zdQNxcbjPY(eC@4=jy!L5`FNR}8$EAn_0)n{KK{(-9XWLCwHH^c&gqrzbFA)mmL1L} zUtZkKy4zjr@MV`CdR62dUwfV#|It-d)7VO@{XHI91io`4^vz2OuSfjfD0eo*HR9pa zDXu#W3hd>ce-kP;D$WJ!9$;6lbGZZ^r_{Db)>a*=0xDFPeoGzhz_D@e{Q*V>@Cejh z^v!lZcTvf4z@lEije8}7JRT!QU3vm0d8H+jRjPG--P1$O(6tzJc}p{akQr!bGF^vB z(mL8IM_iap*SKIlTWHQV-~&iL3!NUCnn}G>3xcxAf9(LLv7Trr&G2P&3!F2HX@UiM zb@CZP<|^ppVH%nf-w#HU1ir%1tb>_Ls*Ww76g$%B$;?`@*h;OnRE(Jvq4b?{Eo`;f zavyyPKtr;5V(GY*fd-moCd^SV9Ujvbmue*om{Mqe*X}uyRXPmwoZvh~oLl_{C*~1n zpibIzf8>g4IYMX#L$`gY*)v_J2zujdVC)K=b`B@7L58y+2iyees{AV|{3`cJ0_Hu- zdN7k1^SG1UR!&2>WeI{3H;86#bLu#c;fct>2brP^MHGYaJ_acs1B2$h8&L58Jshnx zl&)_|snMvS4)BPcy&-(EX{k;Prb_Ma4kI0w{I`b`K_|Oc;-~cFvWduZEr`Z3rskaoV_)dc9HIJiC0pd2(sb|2@wSGFP}lA*v6X0Ww33wZ)ZM zrOxHDRl#X>m4ELPbu`DZQ@b^3FG1w3mfD)bZNa1iC*uUq4RVj(w&asfhOP7f)tb)1 za<)q8;urKTf?0Crl)})bS}H}lb_mgrCgrpdccT% z;fq{;PiOQFQzuIxEVPY<#e*l7yre8>8KsA2T7e6a%WhTTy1>o<7RV?)5txoiqwc$5 z>|RKz<5{hAs?#jf#|v*Oe5mk;If|>=FiK|-bW^sVc9f9W%;2b}hFhA<5G?Sb&R`nzt0=BPrV9%g6NNH_X#}lRFbzTMi}{8| zb=UiKPJspK4EIr)rb{h!3{z6cO>$R5I-F^y6x@_PgMly>Qc8r5$cN0dV94$A+9fA0 zso7ivhPAvf*BD40@#8SIokr3#LBm?#ywtFDME7v5r zh0`joRQY@=#CQQ>K-sK{C!wP+6>tMUs!;(Q+q0`tYYeJ^5}>;a9JlXn;A z=DO7?8QyRMxze_N>}*|r$X;x>7Ul4=pjsV;90 zjvPGOUz+@R`;L_@OY{9kb9tdvum0;|tqA`cXm1Pso5%IQ^pm8X9#0ngXAT`1Y%W*J z)WN0Q$p_qOy|u91Z1}!rZLQq#qMx~SCR4kt2pXh`aV_1U9y_EtY<~0G-y(NSevKZV z{C^=iObM zSoC({v%g^a`v0Q`#Yn%v`Kv(1=bYRcc%*lpnw(q^R7`FH6@z?BTEGJ)cgRG3T1tAW z-k8$MKZnJuuq|h=bc$)&nf^u!B>uO*O+cK-9-DmTi(h=j0}uS^pOSO8+%mZp4)%6; zNqL(r9VWZmj~(9G-rgp|?T5FqC}Zj;gZQm0g%gD{g_~9U^2?L*Q$Ihmz}AYj#?mtv z8?|EKSdQfhlWIY{w)3LrA0Ct(_w zb1p4ObH26aREneZ;qHN|-wtYNx!3EIpRwW_MYxGf9ygk}y4WN7{Wj-S4yBhrg<&BK z*Z^fAxdv(zA)0`QzbPdP!J3X7($IVzE`_Q*0yT|rNyKLI%LEr7IUHfX!;>~yB^!mH zhu&LwH%OaD3y&ARS@>Sz|1JE_!jB6-#glefd;!Lj^I0>0Cv{L+90{bzyoP2Ct7XR) zu4GKQwh8tekKP{1>VbNa_+^jW1~<0|QEbItR4Le}^~mEjaG*61kV@M~*B~-7-s_DBG59%WUVk?bzjbD+b!M+3}=P z0Y>UuMJlw+kEPzN_spUrWZ7_<3r)vxfIbOzdR5J)wJnoDhg2NPa?3>@cOOf=#6A(E zLDvr~@s4Vbv0j}!o(z_KFO(f!P*TofGcaUSjmlnsLx-7H52~>b+|!pOo@CPeTW(dI zw3vp1yRshBHH*(ZDxF&2 z={TVN%4$9}lFI8OF#iWKyFyReG$%-v60 z-U*7rRSDH_QI#rG$6zqrVK9eS+B|S9_l$2%K1zs;ZNroEbEcQXsO89@7+6jE=Ei|m z|&;dPUXr)SY6L|t#z$kk0d38*e`j*3)7876YKLL^TZnZigQG#~-d2>=fkD^07}N$_JqpwLm6fd_h?xoV zMj&9y@OsB@Tq+UQ7*{F5>X`#kC40fH=#i0+ zI>i)o(0E|qpiJ?2o?;+uw=H-d178$&E$Cnhv^MvSZL47J{Ci8qiM3lp6{_#4Et_oE z9iX(&^Us0mKryrm^wic7qGDCsgLb!-DJ(I#Zx6I=2#2!)T!1;r`y+HM$ECs@I_~3! zB@{Z^f5vDFL_)=V&pud8L(l{<4sA44j_jCJIPI%_&7B;F8T7?nxyjS2zr(c3w@C7E({>JWqBdRAL&_mxIOuJwl*sG(lKOP*9v9=W7u3vALDwqC zZJi+az|@HtQx;<;Z%j;@=S0E#(N(5D=s-C_f9=Y&Q6a7qsM0V+PtzVYBEybN_VHh4 z;Ip0C+D|lHF6yN-oCErP#`H*m7cgEmQJmm1djt~1K!s+9p5d+~%&ADjP*lks8#i!pCkK(B7`mil)?UqK7WHMqB*S=n9YZn& ze+H?-|3owPD^!e$D^>TvhR~4NJCD&x6D}O~zZ{ema2!V)! zW+er;F^-jhwTSDgxZ{IK#tp6<>>Px5#k7pXM(=z$$X!dfFs1-5i*zyhH~$dHdDoMs z2VKJvHyjExG|;-#o(7^}nZ(mUIttrae?Q71Tle)Uv!kspCpX_YXye-cuv7 zUz?vB2MvZn(HH|e8#tBEp)55x=n879l#o24NES`yhv*-;QFdS5%S&uD&W{0gT)_oQkp0(^k zp)im<%*5pD%t(1?f;O>8z!oN^4HPDpP%}sJ15UlW%fiuZ6M9%k-*T&qx+CmjXyERLp-aEE8-qxO?sl2&L|oTx2c#5GuikItw0f@| za9zXc4YqBJp1Za#gcG`Pf7!Hz9r?f#V7drUU4&`4y6epuF7~4)Lno4;LOZxKN2o1p z?H*-QUFF*>Ej*`id!DN@-$g>Mx;xW4b}{$WY>RX}HA?1ZNMZgW~+rmgmbd7Phx^f8yrjJEG1PDt2+4 zomoM|J)+`t8(S;&g-yd)m|r{hjE%B%Kxr-8+nPpgXJZk_@Qus!flhs|9b3=^pSRN1 z((1yBt_dw%Zkk15*b=dPs5v)Z_WadkVR^Szg2@9)LUvK36bh~6Foh%CvryMOfWwWO+f1oP{0!6c{()l2DU1l`G$luQcGAy8zEeMt-MzQvrZk{PtbrbX< zhM}O?XeROWf>FxWbUL|ZDUHdiJ1>9FsmovB`jyH{&R+b6J6aw0Boo>*^hl)Cep zhxz8+dEP7g+y2tQdB*2%n>(=+NPF^8kP6X>sM#wmHGwr4F!j@g=5hC`MJr^^>lkx& z!(zY_`0JRhf9XOOCNLH8{?~B}^U%XsLFuo!cHE2Y6RdSI&_yJ@@>ZFbRp z{v8PK;P5htadF?8&fUvyS?9!F$D3||w==Umg7kY}+a!gCTD`ltaHeoxW#C1KF9bM6 zggBuhr-z^vcA7J%WbyP1bVXysCS1^t^EJFo|CtN+5AQvTyr_~rl=Z1`_R(tfo%q)uK1Kh<#w7reSv-o@*8%dPEQM@G^~;I-@Q+Y@p02BkC0Mbe=vHQr7@ai-^<~Xa&tuCq>fZj@Kz3P zJhSlD3F6I61GIQ9PRM`sT+OgeVWN72nt&A2^{k*|xjJpQAUW;GuE(|o9AAo_kVF`| z9T*%;aUmtlFbN8h2(37>rlBmFbQ-Q}K?Q_u5eAo9W)Q?WCzAIRsJFp1)6`ARF!1g+ zf0PKS)}y+lTsqQsxZ(Mx>A7&9We8IPRwm1~35rZfXhe7HM8l%Js&9Cp+1pVr}@Gb+JsSn%TX$hPr2O$xgRCwf0Rc_6y?qh*yrd2g=?*U^j6m^v4E+LI;l^7pJM~|A#1B_i$f~+yF$kI4b&bg#L?f-l z)8H2)*V*NjB3P20mEwWrFtUp0i_MGncmjU@>xaItBC(&d#`Pnwci{(YE? zAPSexNI^~SEfKttySRVZ;p$TVz{1!|NjZM@xY0~IM|+;h*tZSKaZwkSW&~{WPA;Wy zqB17wtnVW>2eRRe$`-mGA+RU#e{<>H+jC$-7m(?8WiIkJ$kcUBNe+yMneM0QGaHFM zF>iU&y=G;j*L%ggP5sE>m;cgD5jW6liKg+5rB=Ke0taQ$V!yo9+&O03Wz4p#b3`_#*>yZGwZf4$VFn$T12 zV>g~D`lc^nzEwA?fr61W|qRjrB@5W3* z4@u>}*(@v<`h~*^BMx_qyV-D;i1BE+LDE@{jrgB@0plA?az?tHalcN+5gDiC(UT|N zcb1Z~lPlrv7i`33x1at_e=d6FW|^k9lQ_HZ&1Y_vNqYO_``NG2N7qI@GB>w+{}!FA zti8{G%WeB5GXKbbkz1~O){V~O1>_xT{j=w9a^c(C*ES0K^6!nHliY%mW8Ysbo-OeX zxk`aETV&~}cz0lOgG>pUU8;`Hlc(j;Mxr0U=ugpR_tl8*AOi!?e+fe~8h1D69pcH* zm7WGRs7%U!wpCuWU5Xl(C{7;omw{D*aEE_j)PfX`tILDX2?HA}7Ur4`42&aOF-aGdT`CAC#0~@f23IjBINM!D}M3CdSZpXux9-gu|=2{x1w)awugYv_rVaAGCN&d z%ywC#TulahD0{={^uefom02do#zr}e>-+r{#t-!|c15MI;mncMYF5u)^^#-V#Ij_& zv)Z0Ne&B(l^M4)0c6oCkd8o1WRwRAyhnW_eq4Yt2Y3__ze}wy=aac?=n;FKOYbJBd zG+7A)>!{{R)1<=N?k_hh?&jfar`2qCTbGYVb0s5|>01t;l$16!y~D^HSes#Bm^R^{ zfBCJ2xTwn(6JT``(8a*!v!ow_?xo>6g9?n)?9HS+Tl@Sk%q!F|uZBwhrraeHrA@j@ zc8x`Uw z-NN}RE0JpjWm9jI?!{lBX9pGa>toT8hH2gt#6nu?>j6zOBOPJhe;vMsmYx0T3nlX^DJTDbE*3n>3VZXq!fGnlBXA}J#>1E<^!^(+gC@E4 z!>jG?xzp>F^z!;qa_8he`uh6iX=Ux?xyAPSEtC89?Um&M=3p9R!>J;Z%<^bW6K4&T z0yMy^e;QeLo~2Wm2?f@oT#$3J&%F<)8dot#YQZ(VD#10%eftns?sE8z{vNoM+MQI} zR4QkEj>N*c1G0*GzO5OW9pUmo0(y~M_wAmOC1ty=RW(jAx1$hco@u^zJfj+>S2Mxh z1I_B#mhkmN0Ze3)F&#K-7`hRdnBwSVgJmW&e|g;wXeOZpDpy(uyKwo?MVq?rR*Oc} zfFgay%T}b*x8e#%q+47Xj!h-eBONT4vNT(gtt1V52{ELE!FkoK8+rouvKg2|MDHG2 zUgnV*n|=s0hTFXp-n=(jXH{F2ZMJd1Ogt0g5>_-Y-wnnMT9w?_eXVyLLq8f5;~}W6 ze^-DAta8Y!+$?Lp&Z`dCYkT|qSFx8pEl+Y9bjQIs=)~zTN{3zY#;<(k``@^*^NsRX zzC!=uuAdg}!WSw0#*bh1;|qWLsvo^-Ul+TcJ_HhP2V?7^cC6wK&|#(DZHs=+)V4{K zAFL5LjT((YXj03)-D$euaT}u<#;JM&f2L(o(-rNCxDP@R?^9{CVLszZ?T=RPT>`yE zY90Qh>@ZC?W!d@BFmwdXG9db}m&O{S9r;AP{&jmXeV4bsA@A@&cRtx;z^iQkW}jtC z=AFK)vx^T%)AMg3k1j5LUbDRucltF6qGj^vwbbLy8)O$8_f*B{K{0rBpvk`gn6P*KsZFHE!Ccn3_y`ClHM(Hrin*6?PvXh{7TPqfb zyrtbHBG(D2F~45#M0UeI0jdpif7aXFnLLmk)Y+jma`WN=G5PK%B1e)NZPT<5oB;-< zB|tj$jRYOdnT2WV;{@xo11_2SC1RQD9)!rsR$DrI3jRC&0;zDwaA;WtZ0D`Q(ZW?=JKqF4&`S$<7v5QTU*S`Q|6KTf;eQaF zw8)4YBhMtyCBIBwOMZ)de}H_FJVqWTUnhT01>K?-)0-7W%3JB%=)342(g*41=zpP) z)34KS(I3+bpe>YGjkQ>pjo4v!l$~Iw*fs1`?9J?L?6=ti>^b%6=$5{&pV80h z=kEG19qyLaIuwxp0fiLmP_-Xzuek1=y{#t%7e}I38e}w-r z{{sKN`1b_^b;lJou_89Wz8s0G#52V&i5H94ieDFR7H<_F6c39(7mtf?i2o)2(Wn?5 zW7#-t95XIAt~PEme{MBiV!XA} z2u)d*9XXaqLD0CI^Kz5KN;r{t*AHj#)y{gA&3_kj+hKjDHf=aWbIwr!@8vCZPDuD<# z=_PpQIJd1-e=TrbIp3oi6_dEvhs(FJF%})eqv!}L4D2TpXep=D=XG0%ttjwDtQ#a~fj^MSBEivErM9K6Z>yfsaXdl;n$f&~+G*h+1rln6lGss-sNZGo1DwG?Dfb zUc}HB3<-$4i1^b5UXVWp%0!UJaXJ`7vvBp-qg|-Se{ig9#u>yeqF8N!9nx0I=c6HF z_|}w~jM%-vUKOhJ5&Vyxt=>_g+}s-DHZeXCo|cXWs5-}qKwK~2t{6MnQrJ3Ez+H6W zMmi~qHUeegJ)?2A7mId(jQS?Ly69*%LenQp2U%Yf5zQgZpgFiRID+zW#4dz2g8Mg* zz|l6(e@5vj-NI8~0gn;P7oQblUXAf!4AqBMf};imjLVEXjWPElRBLP8FA5}Xm7x@F zO52!>V+?$Cj3Ce5t+)*}8A4V1v4EP4>ZA>gz%0zeQ8!W58w|&B8~Qgc#t23LzwvvD zk!U?6J{R4TT6t&VVrFj5!~Ns_2ox@;UO&wQe+r}wp*yn_X|qc3S)iiF<36;pyHym! zLAxKrfI`JaIKi;o?j}gLF$N!CY9-~0oI@vL7%OI_9AzLcpyi^A$uV)76rroyndm}K z55Q8&75jd!?%|}4aRU~&Sy~xK>ghrksg`aHV7ze0SdB)kZj9Sq94AN!!*jqc?K_3afJd@?`B&_ z?`ka_$PS1lRa-|Y<``_q8jc*21#T*-e;_q9n{b(0bpf;qXL2^g(Zry@vBC*aWIDz? zAY+iiI4Gk&&I1fZL-zq7Oy16hDQF>BF5HZBwSAE6`J0wGJC>TNPzU4Rup41Qq3V;lnodk&Q!Z$Y6$ zcr=V!4_Fb$$)Zk9`87}~5X2B&rJ$j}3EBdb=aFd57TVe~MDQbIYdq=~TVoJAKtVBd zblNJSs6wWIObO~fKnWJ-s}}+za^r40!5=WNF|dtsJY~OG7uqybCYkbwe~0@sm17Ot z2u!p)K!~gnqKd1w6|ttk$Jzp!1&lJt-2wWYW*GmPZl?WK9lbK(Tu&f!iXvjsQvABz z#Q;lS3}c>*aOB5IZEkmgG;szAcwP|+Cv79FTo2_d@CqoSJxVxq%K#}AB#x3TdA9)b zfB{bPtOP~uO5hF{K~+Z)f0w0wl!Rje^CJdbL*;)1s}LBlH)hexsD3uZG%thNm!f%%G+NC#qCof5k(&1UFD9hIzV_1W=NL zkW+ApW>G{mXE~xJ#ni(13>5$fH{ynnfuN)yp^+LQ zV=07d+|1VyR4fNALoEE5<_VQ`bRN0|Zl$0wY6uT+5w+=b1@8Y7t_(q$XYgX!9f=Cm zhErya+14erf0#p;VI1}$ybOL=@F08uQ=oX9xtj`ji|CptV7)+3&#DXJfD?jJ(3~V!8#*MZ~xfAxQuye^djDST#+%o{-NH@;ijWeaah4 znkeF5*)b$=l)B zXQmzXC#ufydObt*3`HWU6Bu*h<0zK)d8~VmAeh6Oe?s*VMe1cF?`QPj!C^v33XTQc zPsp3|QD!3*sb?z6hh`mzFGr|y4$)Qhna1^;+`T@05i9HIn_!I#JRH0`Oh2x<< z^yzrw@Is5oSK!VsPfMfZFR(jsV1)?>5TS%@5c<1>yi=1Acu9X>bqN>oKSLr^mBMah z?7f7143Yl{UPu%o^PEsK)=1&I&OIh@dY6X0E0dHE};iVq+Mx0P-c0 zf{ed2Zh>bu+ zsEGe#R1LiHJcH6t&-jU=UQQc2Ss49)w z1U}2SW-=EMBpH7KiA^y-K~|Kb8zJx8!wO{2C(J-{cnda`iZ@_#coZ&%FL9JOuwJ3F zKgaq)e?^2`2l7G3@qd0X$$N-eY!_wUF@OmQAcA)_)zIrEj4$qmGMxEi|!< z5{S~mS*`0f4vnd^8u4K)T^A&az#fcQM13q+ zQ$vVUP9uyyM1fkx_+|oHCFPQFDHMD4Snj*15swjJppeBB9Kr?3ug#SxCUT%fO!DA4 z!03sY_%;v&^nZ!WBB+p7Z(srjKZ)^i8L}Wu%K}dkaf(C$jhD4Rh8|Q3W^{iENK{b* zx9zBiyw{3t>8rV@Nov9~G{p%74Qir+GuSCwF0*kan9K+?FO)E4;gWi#WNSuF?!xh0 zEy7efI9&x5Hno}O2o2e!#(|2EkeO6{V3h9WWq@Y|FFnbL23Px}x=nL!!jSJ*r#Ks&d zSQ`?gZdKDv0b^i>vIAX2=T{B4YhsohX?l|TF4q}`jB5r$xkzd12GWqk0ys%ERKk?F zvp~PlU4NnT5<@}+UCOcjrf&qqH#(W&0mE1pu2_V@!;I;Imw}K>k7LlO3na&Ih6#xo z3NFh!aHowftF)!K8{F)9mx1We)coh5Znn5*LIVvLU-Y7djxXt&1a`uaRGCU$sv$@p zhPCRZ(zMX|nK<)^+V8pMd<%!c#t}lTO*4@h0e@!~KtvwJjcm;lHgHtrCQxY;-LRQy z#8h();R0iZr=p}WP*Q5>!mBv3TVzvNCwK=kLT7h1P zT+Av0G|s))L`u>eAWYjbu=^ZSp>si#imF)#U4RmFiGF<+PAZA{$Wd?AY#4eLGLIu7 zJaz+6slk|CJ2qDL1iqX2vQAZdSs*f6{ZAY%3Xn&4v;Q^Bbc*EC{d;uM-loC7>Tar7b1h{ zBA19Tm~bWV5vKA;Sh~{ZVIJu$udmXbk@yr^Hgt!^Lj~P}1tY<6ZW_QxC0b25 z%Rw2VhDu>&qTIF;549x+$OU1bn12ndUDrI!f1}UM1wb{rGA#tCAR3Xm5$EBohIWIR zMtry!rxY@4fwBg33Nsi^8!@X1%nfvc#)v79MMTYVuI4q&K#;SpFn}t6-3wHjpo+Q* zN>I3VGJ=MuF_sDk;87G4kJ+FVI$W7C=w?N*A;^oUvJxoTMHsxHk|rygP=CiB)D>GN zQHWVO43O4_0?Y#Xgfd+ZxC-_tN=j64F*zFas|~Hoj5tJF!qAFNk z4VH#IuPcZsw4DU%o4RQuWtI#A%~ufHnh6|2b5Vmu{3yJYE2T++VdIeLD((Y`P+5nV z;2hy!QISTOO4Nm**=jZszJIEiNw7P0geFH@w@w;pp&F=>(_CH473G=vF#DOmQEh5r zpn`6hrRha^S|`sCHZ&Ylgy&6jv9mxUV!E=)PBbSY0nZhPK5=nY~G*$+w-|tpnq5}(3hCB1Nb*=#_3?sM}JghC&Kvnw(`fw zQQ7jOj8ku+abLM;^u{Cdy%(Ojjntns1hb!EXb3&TM!;Q%B?aGmhqA=Sz zy0oF4Oyqpf0u}C8CXbMvg9pEE`5*z9!J=wyWusbcH#gm)>6Mbu~%C^)i_qZ8#0hPbv*D~p*o2T}xx#pdB+YWOvW zAzD2ZbL|Q>{jeDz5F~Y0vW-sm%4N5bt(+~}ez>F`>144l7E!D)EXH1}^VLK%L?BGy z+GYpA>s}3ntcTW|&SKY>_O)CG0Tq>9%XJN<_0#iGIHfo>Ep7_0;_2uw33_T^xQQ%A zjxBA>ORl^2pxe}RcjK;;27y|CdFr)Umy%PvN6(zPyOU9JdiUag$1X7T!SnQq(-$8* zbMiF{8Gc^zYYQ29Z1QhD#O^#mwOKj8%j`UtHHq4y+iqH<4Z8CA-#d5m* z6SVjE;(GUBR>i+;qgmA*v-zJ6Y%H4_a`{Trou*$-yWMp1*e}7~L$9dpv>tkBW8)o{ z?)j$d(2o`DLJ>+XkgjOY%EO!tefZYz!W()2?#}L+qpLf+JF7>}67$ukPy09cXFpl0 zm&n1Vo+7{U1pH0zA-^(zx#xx(9(dE6X8xW;#Vh|TMiAyR7sGKHh*(dDT@j=)>%?M> zfN{_r*2#D%y5m&Pe|YMFJ8zuqTzKFmH=ZNx{p69!h4(-Fzysw69{A9^A9#SAyzh?l zOJsHU$nn`1V&4D4XZPSW`ETbwblva6>&|oMu7hgiai>?X9jL*7M&WXprLQd9U-)q0 z(Zb&ro0 z$Dl!`y&!RMJ;gMtS}OvUG1N5YOypNl4FmPbw2Z3WEQby)NzlSr9Pya++Ly1_kk{)= zrNs+>nXlhDGAx0J5!mZu-104d&8i`q%y&g-FN<*}c4_Hi z->K-v5mzPGJPMM?Q1%pP(Zy}wj>tup^|BIQs}>PVE(V(bbs^x|M(ZoJWUUsUH8+~u zEE#A?;Gz_nXFFiB1@$UuzLJ&7My)+}dTZXeyK*w}s+wqku1gHdvof*Xh}}q81pI}m z15({H;b2vN#U?_N+*H)ba*%o!JY8>lmFJ*rrF>Xf3zUi`s6%$!rKE>``9vB*b6McK zQ0j@$E0fE0&0!%Z1-i3r88$G82(%rYC8+#_&ZcoN14bEc*=DR8&+yFRk!+`1LS3>q zw_bxT;MB92brWGbi)9nn_-M#M=3$#6|la4@4FU_W0A()A?XATVV&+nKZQS_ zxT_~0CD#ymqhD+Ph|K+{{WX$oP5z2DCV##0lYRfSHP$U`6<$;L40`Tj90rE6wB0GV z1z#b-Ji?qO3f&#IR(cp+9;7{8iLqiEgcCY3O=FF5^AzK+G48L0xxFw1L`5dRU6_7O zCG^36eWV?>O9r?r)8d`t)-X_@y|ZLP%8hO`4Ge)}|A$kmO5+||bFJ^JfOcuES}W0N z`FP!CcCU;n2J0I#sS^5aMA~Fz^1&)D51}V2k5rZ_xQRu$LSF_eEp%Y8I}FVxOr*u? zn9^QSj1nfa?4yEr^!pEf0!@NXKKSoZM}qHv`R`BUzaJ#@J3x`IzsmFueLw9k<-rnr3=G)Dz9xDD}$N zXr6HB(YZCd6dFc5ur|^Shy72}r==f%ol}3;UVHA`k0$?tP;0|#bePY9gOPFsV_HQk zl{@B!8Am3I;7Ke(2x~OW4A()6r;b55?VIyI`sn0Z(0KhFocxmIgNK^-7vN@G4FW?4 zhm>wRz;d!-1pg9vb+)13&nJ8bv+)o*Tm|j>65LaXZ)DM88>@o3VG=#kFt?3=Mg7J+ zhIun`bU2*+{&0BzaCp~n_>SRlFK*_u^fLvgP(>Vig6gAaBQ!@lBW)E#rKUwsrLx8N zf>AFa8@J!|?AzE?Z1vhh2QFsBxyp<#Kg4~F-gNr`~Xm+^iDgfx$>DjnTB%Vwmz^Y8mZ0BQ!mKPnwSOm##ew zHkvSW%QOx*LMPO8j~Pz_pXIie`Z_m5FxkAuRtj2dt2|$d9Z-nlnqh)C64cTgh?il4 z-DVXX11w|i+;S~*3{aYT)piS{t`%w)8r8ZjT;169HC(4t*`+yXzE8{hdY)B5f2!qi zCM#qVjuBpe>fE2ArwHbM;!J2_I8r+Rl-pTRFfE~@dj`!8Z&8{ZT_JC#pnaOhKwOC4 z^DkMx_U)A=ty!*R+C1v4KulY#1SQ%aF+$LlDoR_+fFtx#XX}nVqCAb;K_t3SDq!9> z$5DQKD8V9zbK{`Bi;Q@euvCy=KAGJ)ip!m~R`2e!&A%@H;+5ZjnSB1rr>?Bse$4p} zXmr2u1@hY;&`#d{xkGT#Qg$r9g+6rsc5{9GtMO&zO_RU8ex2NSsCE7Iy~$J8kFsoZ zJsd1Ohy37V{G7>4ddq*A9h&^*ZVjs*tNPyvGVke{<~~0BHdvO&3YQg57S0x~DO{^? zr3#%{l8dQ-F6jqik?_-!(`&et{K7}L zq%WSlo;*KRo-6Q5mB$C!QeV>PVRAg4JXm~FxKL&${IT*tLg)sB1S?L8YrCoQzX6rT znRa-bV_;-pU;tv{g;lfS`E9;3a5KLEiZI+~nX?3$X1>ha52QF4m_R%LF`EiFvyO_o E2C4xBV*mgE delta 15018 zcmV;bI#tEcq5{aG0t|OgMn(Vu00000kw}pYXMb=20K~wJnlm_PWnp9h0E%D$001rk z001^1wTCEZXk}pl0E&OT;<pcS8M>^8lw+e3yu5)*Aa%nC?hjCdqg3N_utYsBDd|o=p&QcnrmxKa({D;u1?<7 z+yt#|$u{x($x-YQ0+gWxv zn|y6?JL_(Dt;3gHdgyhLcYN(dZv4krRZU|nt@ihLXc73%jnFr*D7+c*f1}*l5Z8!@ zQ>VD@G$^o_e|t`-*r+%csC$52xz6PhbevM#9$8y;s0yf1Vfrm~xC6(=x%USc8Nee@ zchNW7{oF+*#{r9a{Wk8E4Dxu49Chg_nB`D~#%-+&Jw`7CsLXlf?)QY{F|ehoixK&%`I@wET#z- z=+(*R37M;)kB4b!PJBNYO%nJDL$eNME~z@UfKu#8qbD1KMQiRfX%C)f7 zX3Kr_DF6-0=82`_Rt6eqmYFa|!E|^`TU@G@EMQ8Z{XM(qL{{lA%yWYC6mf3#8=RO& zoPj!Nf6tLCs^tiw84TU_rDo4`p(5ywZ-B8YblN$bzy=x4f*f!YsH^g?sPL=YCkdGM zEbGBcV$9=Cc3U|O;g%%`O57ltxy`BLJccJC2OngLE)-D=#`_qgcnl1h4{kuk1N3mT z(onjxUrYUrM`p_e4P2{Kik?MnlTg37P;4~2e`^W%65&_tku6-$cGW@+O(>0qU0{%! zNpVBSr#i4`Yr|p=Pxa`?9I(020Ug!0L8RQ3mq`d@@w_0jz4z~r94xEe=JU7TadfSpuJ{z{u15|4| z2g}(irHfzIy9j2gtMIYHALS^nYQrd^s_0$_YjXapeOFh7W2|J9)wov?+_Jiu`Qj;ZYY#ohc}I zXM*qvV-+0%%zQ-Nu2+(XOA}av$$3p`u`lKu z8r5CzH#r3sq%+({WtuLv&@oI&B{#_%8`9xSGo|3B^cf6WCkQvF$XHo(US(`sSsEtt0Y>rR%k|=b4^PbgmH-e=Hk1ngbQe z4vaIFt&7NTdAZ@)JO{oR|LRI8c&IBw{QA!sT zE-#!`aiz-VQz6C+5Ch6)RXhnDl`+~;r92w8an%U%=V9DBy?NqNCBOG{3xw*US3knU zPvXkLh_9VEA|I89E?Zx}M(mJ$6pxlW`O!xndT8>!pu)X+BLb6^yvR!}y;z;|<|gki z&dqhJRWiKc26Cls{lwY2{E)raZY|2;Wkb2x+COyZLqCX<$59Z9#aa>mH_+Y|`nQhjf$1knJw2W*_RkzTGT2rAG0SrIfy6XROCLp^p#bJ+aWcfL*DIQb2F zeDZ%s%Rh(3tFSF+uXKuO*_r-E3MBq_zC#e4#~+`3{wrU3%>xho*`JYp(sLIZwPN5{j^zoHYC*iV z^RgEo9+VeRY05$v>uerhiDk0F+iQ94cH}cwXTHg%1@zQTTM> zPYPcsJO+~%RcZn9lYvzh0k4yoRb3TF38{wV@T2Y1&tLg0 zXiVg#La)~S!-Gm_f%>%2Oy1}geb2PqJ9qL+!FbItrMLahE~Q$xdBDu-<(;KXgZbzb zzSx!yGac?&(sJ%-F0hA8&ktSdeYe{@D1Y%%Q1V?}U3zC@|5E5KN3COCpg#dVzEL<> zI0f9~7U;Rx7VZHIP5t)^|EBP{JYxIjll51CC{A{y!Zdo}X>=;88>UgavTkD@sJg*_ z?3eMI@9LWVX`b*%x-QqFmy?}XH(_@!ElG2}wdPccqxIqLfvVpQYH7LG>y)3f;u}S{ ziAt-@syqrc zjc`fCX7XzU7a%ztVZY0hHCZJarJ#r2TX;W6o5u=I7QR*Ze&PQv{Exy<3O~b>by<7? z#gp<`Gk<4wP+1%aq{zI6W(})l#}=++OuDuS_8gDi9m(o}dXo5MkGv6-K^Sb?E;rpu zImqJ4$9h#tY1k+`NnB~@3a92E6I5!6TP}GO;n(Gv$>RhAY`9i06=OR!!UksxZ*j_L zu_rO&gcO$}bpIE^6lEZM=i~`q=E8raW&{QXlz(&%Xp{d2Z{pi<+~Fm1FVl}4S){sU zmON3mE!~#c&T-qZ%kfqWv}v>BNv8sg)VGRMXqg{Ny<6{@MMuc8;WQVTj^O}(66*A- znoVn4CW8*CIF{v>i$3l?mU@YOB1nU-A6Vi&)gEKLI(Ix7Ec;$4JG!8xoW*8f$fz2X zy?=%dGp`<0V;{JuFH1bhr1^K;syb;g4Fz{)QIs=&JO~5fZ6y^StZOE8$wB)gL!)Yl zlJm0yd|J_(aI3*k96o9mUwBkHwZ7AFK>eBF8?ZHyZ-}J{Q<$rg5p?PV0W9OxtgB7-R;l8IYkJ?eMx3)#r zddH6aXmxR%?Aa74==XME73Z0|pSHXc6oso2s^Ow4Rj7`^V7S9z4zaX(;8^Y%-Gw27t3}rZWg<9{P6R?CB0Su!pD=ITws6aa;ekRH$v48!}PZh>re(qgVw#R zD60d5u5~e}4Y+y~rt>Q+TSE{t6XuOTz?9+jo_~3%L|kKBr39;I4n&bp4CV~&n!VLn zo?ovv98KA@KvzSyN^T$@AYUi{C;2HRSfoW-qlgz0r~Ms@aql3)LHiN7VHkr>)SqXl z3&ej#l-7APDMEG>;cS)c1-qh0Mn38kQ_Ml*fqjEA#p8L3fw0}S;C&2yQP{PhgDKG3 z+&i|dg1PhWEfpu$ZVgqazNfZqvSD|C(mu~W2dV?b&??YVTSthBRc#O2-BzZs#NfU? z(6S*M&IWJ+<|OZr(6t+U@;9r6T~>Q(NH^g5U#FCt^%ljG4SKF=?I?1@A{!nf{;yLc4lio(R8_}m(Fkw=!Y58BL!Z-c-2I4g3Ig? zNDu>|bIM?`*_hu_NK-2_8!psCOixI0X%S=CG?lEEqC0wqyOuDgA`L@PC3kGxz`>my zM1o@Il8RY-HJe$~mkE;$F zBQqiingQHYeKtivC9rh~BFbWY2>O1qGE@q;*CXKO7Dcj9o{{iN+{}N>5Yw}GCI-%; zH*COgP=RJWwgj3Twz63FS!8(DvI~X6K=LpXlW#I3<)I1M#3BJ(n3y(Dm{>y19LWzj z^^&hi`MnVOQ|0?5)US6ay?+HGMS#dWrbft~{CE7c%sF_oU^w3=EYr6>hNnDhDsO&3 zKT^0k&tVL_0QYTsW5s`OiomyU$9B3(GqqunMYokr*H*kmS$7I2%_CDJwJxR>#Psb7 z&_Lw{?I-;$^5#a&(OcYMz|X_Li@~h1McFS4N4HJrVIh6XtuE@0u#2IAyB~%w{n~B} zA{n~dWwsM>UAG;OQb4_Wzm3!CgL=Sq4W~EQwlR9{+PV-<=*E9#(-L;%151GEB0zN! zrs3+YH)pumkD3gfNP-IO;LaSOwyd>#ludP&@36G+g2L^2uF8BD3AyU-OzYUi+*h+L z((%+NnV%tvA;3kxIXcDgn_0ukB@rZ=x(8jYhSQ_@Lufzjj6=^FE`S-&qpBI%G6@Wd z^G92rFUwfi-qL@Gn~(2^I$x;R#c_6K1rhg%iqmaut<)Db4P#+`?c8%V%F+R)wQO%| z8nvB`MIghsF3$%#^}Tj%K^J_?j`U9sfe~If? zDz7+u@mua_iSSE790nM8|M6A0VB2-cH{4V#`Qc?(NA>z^&R%u;e!t41 zCFloXa=M@qIR~!mm6>^By}eQD&TAg#n|J4Vuk3I8O9$r}pSx}D#7-dX$tOW7L?@zV zue8(z)?mQYPZyfU-K!R@kU4iV=IVyUfG6;~nXP~6LKh}574hM_xrKS?VXUC^yD`kl z3^|CDx89A554z9{1v_&$ZYY}4f=l=IDiGhOSJ=g@3h1|u^M9VEIe={&(co1Wu}5c< zzKb>k=u+cnhv7af-Qzcp8kJK28ZflXSVfz^2TCie_zdw*cFFmuJUYM0&#j%k@$AMr zysdxJM!8ZNJf{b?>am-~OVMT*-RIwf@D2_ygBTb0t?Aso?3Q&->~*~926#I&%Ogm? z54KHGXsFe@iwkE8=T!z?g!n>$Q$&apDsp-VN@1rtb4nJ^zCc$rHf+KL?Koe<%k-bS zVE^#mv&hRT8Kqet-#%`ei;JdBtCO#go@syEZ!Pbgnp|d^n0pP+;x+c<>*~G%aO(~+ zz5*xg3s2hSefPl?-)~iRD$ORmwXTXxd&h?VW+d&`t3&GKRq#_CmvF)BTjgE6ez)A( z-gRUoodjOH&b}>i4|58?H``sAuEXs^xBwSYyuC(}eS8(v4%PO^bQK>ro$?4N)dhc} zXIUDfS@yjgJ}Eax6i(_$1qE;A;KnlxZ=E3C%rroY=i-F?d(YJj+Y~0MH>e3nAzjZ3 zN|vkBh6|F@j_i7DTfp(9=m|-Lq1%DM!4wx#!VHt3Ac@e5BWoJUqDiOWx)xMG*cM@M zsbvO1taBoHPl0+HOfya0^b7;w=l{#dvau`o*p?i_HiWugB3ZuoZ5+^RiR_ znMeF^WreJ&I~IeGxn0+o+(9(bN<0mIF>;+5LTA^xhG{8+jx5FFRaa>K|AbdnqZ$&mT9M zY3FFqGa37iVL2}9;?j(OZQjYH^i5R8B%Sqr#O6RYoKe|A_ag-M1b%-m-FtfuOy~kK z-LA|<{sx)4t|`fZ@i5c(H&%906KqRXh!4i=Db5Z8M@Nbzy_5`+0VAhtF}u~!xF{G!~Qa`DiH4Q4~$xn z;&F9(5ISLCgT=yJ(}96;geyjiM;hoyOl|gN4*Vq9K6~!gUc+)IwT(bGL2K4Tee1|2 z^=r1e8V7BcMo}<%wC3VAguuiKnya@C*;fy)+4O`I7Mg!Ft3ZSt9)86yzg$nO&==OM zzaq8>^Ws+YP0RKW@cBL%qEcq3i;LMVOO&h0U=L+)IGsKiwXZVE%y;ggcmhNgEInFDJx3=GpI9P}^0wGbC|*$k(#}k zlxJ(7|A~2p8s^nd>ED#QWTLc5SIN%NI8#ouX%2tR=F(ZT$!Hp!q-YD}=WLT9QJKYY zJ&9)B^%?bL)7(}_kTr#4h<%-rQ+F?%zp@g!R!}zeM(JMs6?%41QNKPF9ch^6JwYs_ zrM@1}G&9l>=KVL}TWINN(L?MnX@v*t(9(PTpSv{V|IDTI1J{&Tw^P~OEpH8Lz2Ln1 zbBA?xSz6U!GRhPM%wAuirAc zZ{J>7E?^F(K{lK!GRZ8D)--X}P$@tI%&LEpb>~?+g_%%bEy@KsC;Qy{aH???bEFnr z)2k9(qujR-apf+D-{|jwTdCbiwN0gR*5^nptUDm9sOQ_7q1h2G4&IUIayM+ z>snRg6mvTYQRbQEYsWLHVR|(a>^;z|j%^8FPZYpJCK=O#vxcD?fr%-OUN%@}GLwJT z?SN(yI-qi;b+8MU4_&mW>u$AZR1GN7XS{4hI(;Xua74PrrQz6A52h7AXF)m?6 z1M}Tr+@Mv-ecji3*D>^?F)<#3+IoKlh`=g`yvoh8=IgxbfW5Z2zkek=^{hO}Y259I zc#NNQ5_id4pLl}&*>QF@pdq_E^5ar z?f@ND`rWqZ=S*#zMESuQfzznbD1;`p+}oX|3m&&Inqi!(Ctz9@HC@rJi2Hva6!AWl zMjPfcuGIc`_1-1WYoylUPsG1`$&)$8B17t{B7>l^Y8 z4|L~~JqEnW_HXuCwq)MvyE?o0fHXb-7V_BQ;+HhrJ8`F9lOS3qk6lYm-@nWEO?uL_ z&C)GPk1t(4SG@iB@m7awFFSw11k;x~+OW5}O7xr0nXd8jXE2Vr$5s=U5cFlW8Zoyh~)L7jgcS|c|v9uSl7 zeI{}wxzRRF`@k7sP+9_{Q{PC?(VSVBwk}><>6bzp-6oiHp4C2#NIQu;bw3|er$!70 zF-0qws+f;;HrSzR`E00mhFzNH<)sQD3DtrL`Jq=VdXpl&lf^$fK0fbtmO3@x49mcr z9Ya{YSxOA;4x=o&L?x3W9pV89HD8h+LC`lF~|qme1SvDDquTr6^<6J0^9i}(1BiAxU2Bq z!iNfZcn@=bs84^+@CdNI9OVWhm1 zzKgz({tzUei=W_pT}?H zzs%pn@8u8hkMU3NKjB~I{|EnpV4&`}q9#_v2H2M)ag}(k_!aST@h0(`;_c#{;-lgb z@fYGr@wejt5&vjZjE=Ev95#*_mm60bHyO7YuP|O`+--mSj`0EG-x!}Z{?zyn#uLUj zjQ?VM+xWim55|v;i3Fi3%d#WK@`$`#UMZg^Z;`jjJLD_nZ^*aEd*pA+2jm~hhvb*# z*X7^I@5vv^r{yyy%W+}1+CzaZNO8L*wnlwrOJo8=>~c@u+`7PJNrk_R(+RU|t7wYu zaNJcf8u)(`m4@~>0j8J16H^bt=+W^`6#L0Ik7z}`p*KdfbPqwiz;MK5cuKKAjU;RD z(jL|&MQ@8%7ca+q(p-%j;s)+O9ZL~yY^3ZWOeVp_V7l*xzQZ-b^KHO(3(ky`3bQ#J zj73p^afJJVt!yA-Y)db}JIA?grD}oe%K0AEsF;7my*^yNm5s6J7#>AOSYcp4nLtZ9 zoj$MILTp8WH)7p@*<^4O!=KX_LnzuKIExkE9Q3hcgbI92x}zjt%!97Oh(y$4Q^b^= zW>Xzy>Ym}W_n?WipYS4vzF}>Up3gzb37`KV>iSV>^JV4bsP6Xn5 z0e8jN$(F*_nF8*j6F1UHQM3^#3-1|?yS-Sn`(xBM;nhV)s}Y($Svtu2qKIe?X$H-~ zoxu^5mm_u|tP$M5c?6EOc{WN%=@y;>3wVEwV7~aQ81rh32VHWAYfc(`LG}7+CQu+{2;G^bNSl9E zg3kgKJs$U=joq!H7!KO~7zPw7Ho^&p<#sngx{WdT08=X|SL7Tz8N*mHE9EEyc>ygK zT}+ON)1(Mp)y_m0dU^nsQm)wdb9E0Vb&MOZxXseaI8sj+x=6KjYXIYgJH~1>Vs&HO z?&5GM${DM4m0cJOG^+YYS1KSbLyCV)W2B=lbi-H;5!~7p2y?8Od6@K}j1;=Q8xOi_ zps8)*@Vl~stbRhO*oUY zA&w>n1&$R?h$7Q5<^dUl6vjar^>H3xC>pvC0AccWHcUYa!E)hdoU84FWGBbQ-oPif zfbhC0l1Lq45Yi%UtdH{MkGFE)1?-m5Fxep)ff{M!M+={=jjpDH`^Y$z_@4L0ID(2i7=UQ z%4}iko9-rbF0{1^1_m5yDGHBs6Cxd{r(zv5Os0-*nZsT(?&n;u6{iCvFPsN>Q5U^6 z6BtwFi-IOiAD&-Kkp;jIpa{VSVqJ1l*@6i$Kna7`0$VV?9>r11R3CqDK^I^J5Q86> z@EFHH!Jb3q$6HY75FQPq)&o|=ak8kBQ+^GU3Is7kS1D*HaDuh~<#{ApvxTc7{iz+BOLj$Qk&adAWfV>0-jey!b#f*E7wE$3cLc!Xpa&O z-7-K*1&O0%OWrNOJYay+JS#yFyArqqMo`sJ#ARt8CE-}W{D^-+*HHQ2z-ondj$tH< z{ZtHK$Pw-h*=?#gEEEo$rHB`1<8A^iXtfc^ZZyPshpYyXmem7?1899J+Q8$XvB(3) z8S*)mfkAzAQxLzPqxAY53d9d!SCo5p`h6s0g3R9+`AfPK^tT#j2F;{ z+Ofj)=J*U~Os0R-nN(msp_*-=_3<{?RkV+NmG+Ti;D{=k>0`z_-~d3>#k8eJwZEzI zgky?u)GRP9a347*l&Yq1w-2-jY+?(f)|RsTu{kZA6i8RdU^lnWeQ5}kfncdXwn*18 z@AmpwA5iKrz-Ftb(0#>_-bJWkHA2^6xJ>A{hQ@VW%649tG4e4ku`b`i6ZnMzqgBp@6 z$SKJYbxOmC2`~mVTz(@Ch5-_t%QjqL`w0DosoyAN=&Pajp5ZA>9W$uuz=|M=AmkKWqFEFX%~_6UNinrBK0^fn!i~5gWT0urG+M^>1tJ8cv2qnr z$WsiHC8h?HV`!v?$XE*D8aMMb1Qp9c%Mc4crg=hT9i4}6fm9ibFN1#{7CZIBAI_&AECeF^KHBM9d3=ATi$M3H(K z$@>{ScyO2yl7eGF_Y?B=yxB-a>Y0l2p;<`B;mZ-KoI`X~eWtVbQaT$vm3~0&RAP@p zEj~v;0afT3MB#X-4}ChGIK0pz@*m;OuT4v%bs^-Bcw{m zUC8kijiks46_ubb5pU8Q6>&OIh@h_mX0E0dHE};iVq+Mx0P+OMarwv;1ry%>J$i~E ztb>lUN&XkpOijne!L<4GnM`pM)_~#trRnq`3JXFFa+5cC6@Q2F{y>jH#73YZRK))& zss>(poTTb)h6$PLZk#KByn3ylo%%L(3p@K zx^V)%OO=ttjzFql1`$1GwACgS(4j3%`F`}b`z>gRCa5VjJ;nU+f_+}iQ%W2grx>*9 zeu;wOZG<#&Ry+^GA=G^9C`eAStnd?|T1a?s%O+M5>wgZ<(zj5WQOCu;7Mj?_@zMqE zyFyp86^62!>oJ_d7>*XhJj3Wb2}Eh(tk!iKhsM-djrcH@t_zYyU=PMDqCOU^sUbuv zrx8XUqCl-;d@}*9l5)wo6pFoiEcad1h{uR9P{?8m4&j32*XBwT6FJZ#CVB82VD!XH zd>e=X`hP@b5mZR4H!uN%pTzjM3|SDSWr3%NI7K3W#>-kDLk}tiGrGS7B&sNZ+jdk$ z-fP9S^wnI{BsJj~n&Je41~t*Z8SE4-m)STIOlAa{7fP72a7n#VvNa=MGQcx}om^}u11tYi;^aXZ=#szXQVq*>!tPKfL zx2kETfH5#b*?}&i^Q(s2H8D$$G(E|Em+K5e#x(<>T%DU*8=cJXfMF~PS1iKdVa9a9%Roq`$1&*C1(IVp!-T{P1(#(V zxYI_LRoYVA4Q}?l%RqE!YW{OjH(T5@p@9aBFM82J$Cq?X0z2VIs!XLW)exi)!&-Gy zX?AMz&@N8#pR*6R5O_ZrIE;Vyd}@ zaDg$yQ&G|wC@D2`;Z>a2EwZUB@)*oTiU67N^W}p{t02`(HRmq|ST~BSZ-CIfBVh2}grK>1G(D2l9~#7k?v2 z3?k+c<{W1@YIw*ca1ex{38_<4<$WStm7_F1{BM|WFM1?Nmj6_%R3z5NekxN7v zOt=#G2vhl_loV4V!_iH_wiQ>&wQ3w?gQ71#L%;I?e{lqyMn^AYJmB;<9Df*8;qu&$ zpa@Nk3>Hb3HK;J4H>paRgPJoc9LhT%y)7&h1BR0Bz;Q7<06Yjd6loL2 zk`$N-6V*UvdVs1aEM4jIFpqSW*H`JzNPG${8@fZ|p@MF~f|1}jHx1yU60Ihj<)DmF zL#41XQEpp_huV?@WZzCD8wus z21si|0cHVxLYb}yTm^d+B_%4jm>doI)rMAaM7Ps$j@rbq4G&$%2+9m)jixv0S+eiYuymC~fZuyM$A759NesH{UwaE|b= zs7RwsCF(-ZY&Dw*Uw>81B-ougLX)GdTPF>)Pz}_`X|As2it@~SnElM(s5Z4QP(ioM z()6M{t&?X68yb!&!t_<8-j+BYJdOOTlr(;sBC#s z#;Lc^xUXC^dgBrK{!7o?M(R%+g4;&XxHxMqbzZyJIU&vB;YMWmcIC)LQJC!ld~Qr+*7K7k;&H5AMJ1flPU1>fDvXW6V6dc*e(TQ>gLtNXZmBq}P11SQ;V)Jk@HT;^x5Urky zxpsw`e%K5U2$DK0*+wUO?Xp|RR?e1fKU~s}bh6kN3sF`W7Gp2g`D&sWA`m8UZL@>m zb*~3P)c7B_`g@pSZ;1U)q{+(Z^5$Cftc zCD&bh&~0kEyYa@84uM*KedUr!PKs=Hwd| zGW@*aHx@GT_~c)IjNN&FYO`{FkJ))HYZA3Zx81Zz8+7IKzklxJ$#dl9M<2b59D{#9 zA;mYnY4Ry@<%O@&ji1AAlZ8^Dp<;W3X3$p2rddB7RUt-SbV^ zp`R+)g(8$(AYIX(m4`VQ`tYsag*Woy-JRVtM^|@tcUF&{CFbi-pZ0I?&wjR4FOh@K zJVSo%DfpY*Lw;?4a?cGnJn*)+&HO!yidX)5j3CTsE{5YY5V4*PyCO(q)``U$0pp-M ztdsFjbjPWn|Mi&%?!0lbbK!wk+<1<#50ghH7e4&R0}qrRc;I92f8YUf^1eIHFOk*Z zqsM1oheZmcF)df8pbW#|nQ} zcm{npr|y?CDB3>G(RCuGkT&R#g&TS^A1b}oR^XCCdAs*>yc#5_EN#tVJurjS4#h}N z%od_{7~(yQ+nYOM%Z#!%CoGm&3KH4M}z(=w`hvm83KBtZ*fal~WNYhS)zLtd{hl@>32 zHDAATWLN@yQL=JPw*BCWW8@k4h6I!bBe2)SxaC`anpHzIneU0vUKZm{?9$T3zEjbS zBd$uWc@!j(q3kKpqKn(U9g&MH>s2MbRxKi!Tnsh=>O#P^jn;pxC2O?+t+~BD4W3Utm7L4O zj95dZ21`a>%2r=vmoer}>0RccY4;rFup61LGKkzV)DxW*mp02FSfeu$DyQc+nA1x) zP?hGdCuFjH0NPfgq}oDoQ+P_Fs^XEWnfko}bU4FUTVu7tX5mEPKH!hxrO+_ifwhrtIP8CzJ}v!!_?-H?_S$pjemwbigjyR`qr-d-9E_AB7}F|RsoXI) z%s4Vx1W#fSLRh0|X1ESoJar7hY2Tdx(Z?p&g2wCb;N+JqA3W5wzYI6yY7iJYIHYvj z0hW^uBlwrVtFsOLem>zln2m?f;VNj~m*AdCd?Sk%+gKIM4U_1RhPiEjEb2GrG0dBh zqr>6k4~E10hr>4xhwm8<_u^*0KtEq_3RT3RC#XJ(HbQf>GtyQ;RBBrER4QAHFBtU_ zvT^%O&%cdb#a6F9bl_q}oU6>}@PMaG|`Y=5-e(=RdUv_<(R3{(p z9Xx7*U^ugT&82CxQ7Scmn|twM|44sScqM38xvw;8rl^s_WQLEC%40hXZt2e4%vFda z=5fc*TwTpUf<^AZj@olFOTd9~Vag9uN!{ExELVtoBl2rTzT+h-DR*Gt0^K%J3f5ob zCol$q!lls=LR{20z#er?%*`q>9vFRO>@p;4{d!qtskU&D1em0g;H=KHL?ujg46^ru=LXR<;@ z;TYldr_TK;dWv9wF3yA|h9k8DK)Ib21=A8bx@XYr@D`=n(G~J`3fiZ648(=#z4(&l zYu{a2(wgO3rp=?y3dFRHK=5+ej%siL&C3^+m`b++!)~MO z1>}b(;}=X`(Odp%c4+d|-5ORsR`tITWZtti&3%0MZLlnl6)r2BESxP|Q@B>)N)PVRAg4JXm~NxKL&${IT*tLg)sB1S?L8YrCoQ{{l8Wn0|Pi zV_;-pU;tvj{|9s8`E9;3a5KLEiZI-Jq!@)vGhb%z2T~jiOduWrQb7v(vzCgw24M>8 Aod5s; diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index 0914afe46c1..abf5c8a0a7e 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -1694,6 +1694,7 @@ "tf": "_terraform", "tf.json": "_terraform", "tfvars": "_terraform", + "tfvars.json": "_terraform", "dtx": "_tex_2", "ins": "_tex_3", "toml": "_config", @@ -1942,7 +1943,8 @@ "vala": "_vala", "vue": "_vue", "postcss": "_css", - "django-html": "_html_3" + "django-html": "_html_3", + "blade": "_php" }, "light": { "file": "_default_light", @@ -2093,6 +2095,7 @@ "tf": "_terraform_light", "tf.json": "_terraform_light", "tfvars": "_terraform_light", + "tfvars.json": "_terraform_light", "dtx": "_tex_2_light", "ins": "_tex_3_light", "toml": "_config_light", @@ -2258,7 +2261,8 @@ "vala": "_vala_light", "vue": "_vue_light", "postcss": "_css_light", - "django-html": "_html_3_light" + "django-html": "_html_3_light", + "blade": "_php_light" }, "fileNames": { "mix": "_hex_light", @@ -2340,5 +2344,5 @@ "npm-debug.log": "_npm_ignored_light" } }, - "version": "https://github.com/jesseweed/seti-ui/commit/4dd6c27e1f5aed8068c2451dbaf0db3364545937" + "version": "https://github.com/jesseweed/seti-ui/commit/2d10473b7575ec00c47eda751ea9caeec6b0b606" } \ No newline at end of file From c7a138df0e775ea73f9b23d0c10afa2f030026b9 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 25 Jul 2022 13:39:13 -0700 Subject: [PATCH 061/179] Add a view and actions for managing edit sessions (#156199) * Add basic view for managing edit sessions * Allow to resume/delete edit sessions from view * Allow opening individual working changes from view * Make edit session actions visible by default * Update tests --- .../browser/editSessions.contribution.ts | 36 +++- .../browser/editSessionsContentProvider.ts | 34 ++++ .../editSessions/browser/editSessionsViews.ts | 187 ++++++++++++++++++ .../browser/editSessionsWorkbenchService.ts | 17 +- .../editSessions/common/editSessions.ts | 11 ++ .../test/browser/editSessions.test.ts | 17 ++ 6 files changed, 297 insertions(+), 5 deletions(-) create mode 100644 src/vs/workbench/contrib/editSessions/browser/editSessionsContentProvider.ts create mode 100644 src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 9be6a5124f7..68efea1cca6 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 { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion, IEditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME } 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 } from 'vs/platform/workspace/common/workspace'; @@ -39,6 +39,13 @@ 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 } from 'vs/workbench/common/views'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { EditSessionsContentProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsContentProvider'; registerSingleton(IEditSessionsLogService, EditSessionsLogService); registerSingleton(IEditSessionsWorkbenchService, EditSessionsWorkbenchService); @@ -74,9 +81,11 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo @IDialogService private readonly dialogService: IDialogService, @IEditSessionsLogService private readonly logService: IEditSessionsLogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @IProductService private readonly productService: IProductService, @IConfigurationService private configurationService: IConfigurationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @ITextModelService textModelResolverService: ITextModelService, @IQuickInputService private readonly quickInputService: IQuickInputService, @ICommandService private commandService: ICommandService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @@ -101,6 +110,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo }); this.registerActions(); + this.registerViews(); continueEditSessionExtPoint.setHandler(extensions => { const continueEditSessionOptions: ContinueEditSessionItem[] = []; @@ -128,6 +138,24 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } this.continueEditSessionOptions = continueEditSessionOptions; }); + + textModelResolverService.registerTextModelContentProvider(EDIT_SESSIONS_SCHEME, instantiationService.createInstance(EditSessionsContentProvider)); + } + + private registerViews() { + const container = Registry.as(ViewExtensions.ViewContainersRegistry).registerViewContainer( + { + id: EDIT_SESSIONS_CONTAINER_ID, + title: EDIT_SESSIONS_TITLE, + ctorDescriptor: new SyncDescriptor( + ViewPaneContainer, + [EDIT_SESSIONS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true }] + ), + icon: EDIT_SESSIONS_VIEW_ICON, + hideIfEmpty: true + }, ViewContainerLocation.Sidebar + ); + this._register(this.instantiationService.createInstance(EditSessionsDataViews, container)); } private registerActions() { @@ -195,7 +223,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo }); } - async run(accessor: ServicesAccessor): Promise { + async run(accessor: ServicesAccessor, editSessionId?: string): Promise { await that.progressService.withProgress({ location: ProgressLocation.Notification, title: localize('resuming edit session', 'Resuming edit session...') @@ -206,7 +234,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo }; that.telemetryService.publicLog2('editSessions.resume'); - await that.resumeEditSession(); + await that.resumeEditSession(editSessionId); }); } })); @@ -536,7 +564,7 @@ Registry.as(Extensions.Configuration).registerConfigurat 'workbench.experimental.editSessions.enabled': { 'type': 'boolean', 'tags': ['experimental', 'usesOnlineServices'], - 'default': false, + '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."), }, } diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsContentProvider.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsContentProvider.ts new file mode 100644 index 00000000000..30d56a6c398 --- /dev/null +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsContentProvider.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { ITextModel } from 'vs/editor/common/model'; +import { IModelService } from 'vs/editor/common/services/model'; +import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; +import { EDIT_SESSIONS_SCHEME, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions'; + +export class EditSessionsContentProvider implements ITextModelContentProvider { + + constructor( + @IEditSessionsWorkbenchService private editSessionsWorkbenchService: IEditSessionsWorkbenchService, + @IModelService private readonly modelService: IModelService, + ) { } + + async provideTextContent(uri: URI): Promise { + let model: ITextModel | null = null; + if (uri.scheme === EDIT_SESSIONS_SCHEME) { + const match = /(?[^/]+)\/(?[^/]+)\/(?.*)/.exec(uri.path.substring(1)); + if (match?.groups) { + const { ref, folderName, filePath } = match.groups; + const data = await this.editSessionsWorkbenchService.read(ref); + const content = data?.editSession.folders.find((f) => f.name === folderName)?.workingChanges.find((change) => change.relativeFilePath === filePath)?.contents; + if (content) { + model = this.modelService.createModel(content, null, uri); + } + } + } + return model; + } +} diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts new file mode 100644 index 00000000000..cacef9b047b --- /dev/null +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +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_SCHEME, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } 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'; +import { API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; +import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; + +export class EditSessionsDataViews extends Disposable { + constructor( + container: ViewContainer, + @IInstantiationService private readonly instantiationService: IInstantiationService, + ) { + super(); + this.registerViews(container); + } + + private registerViews(container: ViewContainer): void { + const viewId = 'workbench.views.editSessions.data'; + const name = localize('edit sessions data', 'All Sessions'); + const treeView = this.instantiationService.createInstance(TreeView, viewId, name); + treeView.showCollapseAllAction = true; + treeView.showRefreshAction = true; + const disposable = treeView.onDidChangeVisibility(visible => { + if (visible && !treeView.dataProvider) { + disposable.dispose(); + treeView.dataProvider = this.instantiationService.createInstance(EditSessionDataViewDataProvider); + } + }); + Registry.as(Extensions.ViewsRegistry).registerViews([{ + id: viewId, + name, + ctorDescriptor: new SyncDescriptor(TreeViewPane), + canToggleVisibility: true, + canMoveView: false, + treeView, + collapsed: false, + order: 100, + hideByDefault: true, + }], container); + + registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.editSessions.actions.resume', + title: localize('workbench.editSessions.actions.resume', "Resume Edit Session"), + icon: Codicon.repoPull, + menu: { + id: MenuId.ViewItemContext, + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', viewId), ContextKeyExpr.regex('viewItem', /edit-session/i)), + group: 'inline' + } + }); + } + + 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 treeView.refresh(); + } + }); + + registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.editSessions.actions.delete', + title: localize('workbench.editSessions.actions.delete', "Delete Edit Session"), + icon: Codicon.trash, + menu: { + id: MenuId.ViewItemContext, + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', viewId), ContextKeyExpr.regex('viewItem', /edit-session/i)), + group: 'inline' + } + }); + } + + async run(accessor: ServicesAccessor, handle: TreeViewItemHandleArg): Promise { + const editSessionId = URI.parse(handle.$treeItemHandle).path.substring(1); + const dialogService = accessor.get(IDialogService); + const editSessionWorkbenchService = accessor.get(IEditSessionsWorkbenchService); + const result = await dialogService.confirm({ + message: localize('confirm delete', 'Are you sure you want to permanently delete the edit session with ref {0}? You cannot undo this action.', editSessionId), + type: 'warning', + title: EDIT_SESSIONS_TITLE + }); + if (result.confirmed) { + await editSessionWorkbenchService.delete(editSessionId); + await treeView.refresh(); + } + } + }); + } +} + +class EditSessionDataViewDataProvider implements ITreeViewDataProvider { + constructor( + @IEditSessionsWorkbenchService private readonly editSessionsWorkbenchService: IEditSessionsWorkbenchService + ) { } + + async getChildren(element?: ITreeItem): Promise { + if (!element) { + return this.getAllEditSessions(); + } + + const [ref, folderName, filePath] = URI.parse(element.handle).path.substring(1).split('/'); + + if (ref && !folderName) { + return this.getEditSession(ref); + } else if (ref && folderName && !filePath) { + return this.getEditSessionFolderContents(ref, folderName); + } + + return []; + } + + private async getAllEditSessions(): Promise { + const allEditSessions = await this.editSessionsWorkbenchService.list(); + return allEditSessions.map((session) => { + const resource = URI.from({ scheme: EDIT_SESSIONS_SCHEME, authority: 'remote-session-content', path: `/${session.ref}` }); + return { + handle: resource.toString(), + collapsibleState: TreeItemCollapsibleState.Collapsed, + label: { label: session.ref }, + description: fromNow(session.created, true), + themeIcon: Codicon.repo, + contextValue: `edit-session` + }; + }); + } + + private async getEditSession(ref: string): Promise { + const data = await this.editSessionsWorkbenchService.read(ref); + + if (!data) { + return []; + } + + return data.editSession.folders.map((folder) => { + const resource = URI.from({ scheme: EDIT_SESSIONS_SCHEME, authority: 'remote-session-content', path: `/${data.ref}/${folder.name}` }); + return { + handle: resource.toString(), + collapsibleState: TreeItemCollapsibleState.Collapsed, + label: { label: folder.name }, + themeIcon: Codicon.folder + }; + }); + } + + private async getEditSessionFolderContents(ref: string, folderName: string): Promise { + const data = await this.editSessionsWorkbenchService.read(ref); + + if (!data) { + return []; + } + + return (data.editSession.folders.find((folder) => folder.name === folderName)?.workingChanges ?? []).map((change) => { + const resource = URI.from({ scheme: EDIT_SESSIONS_SCHEME, authority: 'remote-session-content', path: `/${data.ref}/${folderName}/${change.relativeFilePath}` }); + return { + handle: resource.toString(), + resourceUri: resource, + collapsibleState: TreeItemCollapsibleState.None, + label: { label: change.relativeFilePath }, + themeIcon: Codicon.file, + command: { + id: API_OPEN_EDITOR_COMMAND_ID, + title: localize('open file', 'Open File'), + arguments: [resource, undefined, undefined] + } + }; + }); + } +} diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts index b63b550ab35..d8dbac59900 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts @@ -14,7 +14,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IRequestService } from 'vs/platform/request/common/request'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { createSyncHeaders, IAuthenticationProvider } from 'vs/platform/userDataSync/common/userDataSync'; +import { createSyncHeaders, IAuthenticationProvider, IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -122,6 +122,21 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes } } + async list(): Promise { + await this.initialize(); + if (!this.initialized) { + throw new Error(`Unable to list edit sessions.`); + } + + try { + return this.storeClient?.getAllRefs('editSessions') ?? []; + } catch (ex) { + this.logService.error(ex); + } + + return []; + } + private async initialize() { if (this.initialized) { return; diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index 789976a50e5..60b3ab6ca40 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -3,11 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Codicon } from 'vs/base/common/codicons'; import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; 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'; export const EDIT_SESSION_SYNC_CATEGORY: ILocalizedString = { original: 'Edit Sessions', @@ -21,6 +24,7 @@ export interface IEditSessionsWorkbenchService { read(ref: string | undefined): Promise<{ ref: string; editSession: EditSession } | undefined>; write(editSession: EditSession): Promise; delete(ref: string): Promise; + list(): Promise; } export const IEditSessionsLogService = createDecorator('IEditSessionsLogService'); @@ -65,3 +69,10 @@ export interface EditSession { export const EDIT_SESSIONS_SIGNED_IN_KEY = 'editSessionsSignedIn'; export const EDIT_SESSIONS_SIGNED_IN = new RawContextKey(EDIT_SESSIONS_SIGNED_IN_KEY, false); + +export const EDIT_SESSIONS_CONTAINER_ID = 'workbench.view.editSessions'; +export const EDIT_SESSIONS_TITLE = localize('edit sessions', 'Edit Sessions'); + +export const EDIT_SESSIONS_VIEW_ICON = registerIcon('edit-sessions-view-icon', Codicon.cloudDownload, localize('editSessionViewIcon', 'View icon of the edit sessions view.')); + +export const EDIT_SESSIONS_SCHEME = 'vscode-edit-sessions'; 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 07917f285e5..138436bc52f 100644 --- a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -28,6 +28,12 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { Event } from 'vs/base/common/event'; +import { IViewDescriptorService } from 'vs/workbench/common/views'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; const folderName = 'test-folder'; const folderUri = URI.file(`/${folderName}`); @@ -76,6 +82,17 @@ suite('Edit session sync', () => { // Stub repositories instantiationService.stub(ISCMService, '_repositories', new Map()); + instantiationService.stub(IContextKeyService, new MockContextKeyService()); + instantiationService.stub(IThemeService, new class extends mock() { + override onDidColorThemeChange = Event.None; + override onDidFileIconThemeChange = Event.None; + }); + instantiationService.stub(IViewDescriptorService, { + onDidChangeLocation: Event.None + }); + instantiationService.stub(ITextModelService, new class extends mock() { + override registerTextModelContentProvider = () => ({ dispose: () => { } }); + }); editSessionsContribution = instantiationService.createInstance(EditSessionsContribution); }); From 1a8d4bf61da751ccaa99178e7705082b26dac9de Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 25 Jul 2022 13:44:47 -0700 Subject: [PATCH 062/179] Restore waitOnExit, type, hideFromUser, reconnectionOwner terminal properties on reconnect (#155346) --- src/vs/platform/terminal/common/terminal.ts | 16 ++- .../terminal/common/terminalProcess.ts | 6 +- src/vs/platform/terminal/node/ptyService.ts | 6 +- .../tasks/browser/terminalTaskSystem.ts | 100 ++++++++++-------- .../contrib/terminal/browser/terminal.ts | 13 ++- .../browser/terminalEditorSerializer.ts | 6 +- .../terminal/browser/terminalInstance.ts | 40 +++++-- .../browser/terminalProcessManager.ts | 1 - 8 files changed, 124 insertions(+), 64 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 4c3c72a1f30..3f56c931175 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -169,8 +169,14 @@ export interface IPtyHostAttachTarget { environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined; reconnectionOwner?: string; task?: { label: string; id: string; lastTask: string; group?: string }; + waitOnExit?: WaitOnExitValue; + hideFromUser?: boolean; + isFeatureTerminal?: boolean; + type?: TerminalType; } +export type TerminalType = 'Task' | 'Local' | undefined; + export enum TitleEventSource { /** From the API or the rename command that overrides any other type */ Api, @@ -446,7 +452,7 @@ export interface IShellLaunchConfig { reconnectionOwner?: string; /** Whether to wait for a key press before closing the terminal. */ - waitOnExit?: boolean | string | ((exitCode: number) => string); + waitOnExit?: WaitOnExitValue; /** * A string including ANSI escape sequences that will be written to the terminal emulator @@ -469,7 +475,9 @@ export interface IShellLaunchConfig { /** * This is a terminal that attaches to an already running terminal. */ - attachPersistentProcess?: { id: number; findRevivedId?: boolean; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections; reconnectionOwner?: string; task?: { label: string; id: string; lastTask: string; group?: string } }; + attachPersistentProcess?: { + id: number; findRevivedId?: boolean; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections; reconnectionOwner?: string; task?: { label: string; id: string; lastTask: string; group?: string }; type?: TerminalType; waitOnExit?: WaitOnExitValue; hideFromUser?: boolean; isFeatureTerminal?: boolean; + }; /** * Whether the terminal process environment should be exactly as provided in @@ -544,9 +552,11 @@ export interface IShellLaunchConfig { /** * The task associated with this terminal */ - task?: { lastTask: string; group?: string; label: string; id: string }; + task?: { label: string; id: string; lastTask: string; group?: string }; } +export type WaitOnExitValue = boolean | string | ((exitCode: number) => string); + export interface ICreateContributedTerminalProfileOptions { icon?: URI | string | { light: URI; dark: URI }; color?: string; diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index 4329c9e0635..dc360427a6b 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -5,7 +5,7 @@ import { UriComponents } from 'vs/base/common/uri'; import { ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable'; -import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal'; export interface ISingleTerminalConfiguration { userValue: T | undefined; @@ -62,6 +62,10 @@ export interface IProcessDetails { environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined; reconnectionOwner?: string; task?: { label: string; id: string; lastTask: string; group?: string }; + waitOnExit?: WaitOnExitValue; + hideFromUser?: boolean; + isFeatureTerminal?: boolean; + type?: TerminalType; } export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo; diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 2b7ad270732..5e1feff3086 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -411,7 +411,11 @@ export class PtyService extends Disposable implements IPtyService { fixedDimensions: persistentProcess.fixedDimensions, environmentVariableCollections: persistentProcess.processLaunchOptions.options.environmentVariableCollections, reconnectionOwner: persistentProcess.shellLaunchConfig.reconnectionOwner, - task: persistentProcess.shellLaunchConfig.task + task: persistentProcess.shellLaunchConfig.task, + waitOnExit: persistentProcess.shellLaunchConfig.waitOnExit, + hideFromUser: persistentProcess.shellLaunchConfig.hideFromUser, + isFeatureTerminal: persistentProcess.shellLaunchConfig.isFeatureTerminal, + type: persistentProcess.shellLaunchConfig.type }; } diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 22c53792466..abcde9212e7 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -30,14 +30,14 @@ import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IShellLaunchConfig, TerminalLocation, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { IShellLaunchConfig, TerminalLocation, TerminalSettingId, WaitOnExitValue } from 'vs/platform/terminal/common/terminal'; import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; import { TaskTerminalStatus } from 'vs/workbench/contrib/tasks/browser/taskTerminalStatus'; import { ProblemCollectorEventKind, ProblemHandlingStrategy, StartStopProblemCollector, WatchingProblemCollector } from 'vs/workbench/contrib/tasks/common/problemCollectors'; import { GroupKind } from 'vs/workbench/contrib/tasks/common/taskConfiguration'; -import { CommandOptions, CommandString, ContributedTask, CustomTask, DependsOrder, ICommandConfiguration, IExtensionTaskSource, InMemoryTask, IShellConfiguration, IShellQuotingOptions, ITaskEvent, PanelKind, RevealKind, RevealProblemKind, RuntimeType, ShellQuoting, Task, TaskEvent, TaskEventKind, TaskScope, TaskSettingId, TaskSourceKind } from 'vs/workbench/contrib/tasks/common/tasks'; +import { CommandOptions, CommandString, ContributedTask, CustomTask, DependsOrder, ICommandConfiguration, IConfigurationProperties, IExtensionTaskSource, InMemoryTask, IPresentationOptions, IShellConfiguration, IShellQuotingOptions, ITaskEvent, PanelKind, RevealKind, RevealProblemKind, RuntimeType, ShellQuoting, Task, TaskEvent, TaskEventKind, TaskScope, TaskSettingId, TaskSourceKind } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; import { IResolvedVariables, IResolveSet, ITaskExecuteResult, ITaskResolver, ITaskSummary, ITaskSystem, ITaskSystemInfo, ITaskSystemInfoResolver, ITaskTerminateResponse, TaskError, TaskErrors, TaskExecuteKind, Triggers } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { ITerminalGroupService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; @@ -284,6 +284,11 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } if (this._tasksToReconnect.includes(task._id)) { this._terminalForTask = terminals.find(t => t.shellLaunchConfig.attachPersistentProcess?.task?.id === task._id); + // Restore the waitOnExit value of the terminal because it may have been a function + // that cannot be persisted in the pty host + if ('command' in task && task.command.presentation && this._terminalForTask) { + this._terminalForTask.waitOnExit = getWaitOnExitValue(task.command.presentation, task.configurationProperties); + } this.run(task, resolver, trigger); } return undefined; @@ -541,35 +546,38 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { alreadyResolved = alreadyResolved ?? new Map(); const promises: Promise[] = []; if (task.configurationProperties.dependsOn) { - for (const dependency of task.configurationProperties.dependsOn) { - const dependencyTask = await resolver.resolve(dependency.uri, dependency.task!); - if (dependencyTask) { - this._adoptConfigurationForDependencyTask(dependencyTask, task); - const key = dependencyTask.getMapKey(); - let promise = this._activeTasks[key] ? this._getDependencyPromise(this._activeTasks[key]) : undefined; - if (!promise) { - this._fireTaskEvent(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); - encounteredDependencies.add(task.getCommonTaskId()); - promise = this._executeDependencyTask(dependencyTask, resolver, trigger, encounteredDependencies, alreadyResolved); - } - promises.push(promise); - if (task.configurationProperties.dependsOrder === DependsOrder.sequence) { - const promiseResult = await promise; - if (promiseResult.exitCode === 0) { - promise = Promise.resolve(promiseResult); - } else { - promise = Promise.reject(promiseResult); - break; + if (!this._terminalForTask) { + // we already handle dependent tasks when reconnecting, don't create extras + for (const dependency of task.configurationProperties.dependsOn) { + const dependencyTask = await resolver.resolve(dependency.uri, dependency.task!); + if (dependencyTask) { + this._adoptConfigurationForDependencyTask(dependencyTask, task); + const key = dependencyTask.getMapKey(); + let promise = this._activeTasks[key] ? this._getDependencyPromise(this._activeTasks[key]) : undefined; + if (!promise) { + this._fireTaskEvent(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); + encounteredDependencies.add(task.getCommonTaskId()); + promise = this._executeDependencyTask(dependencyTask, resolver, trigger, encounteredDependencies, alreadyResolved); } + promises.push(promise); + if (task.configurationProperties.dependsOrder === DependsOrder.sequence) { + const promiseResult = await promise; + if (promiseResult.exitCode === 0) { + promise = Promise.resolve(promiseResult); + } else { + promise = Promise.reject(promiseResult); + break; + } + } + promises.push(promise); + } else { + this._log(nls.localize('dependencyFailed', + 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', + Types.isString(dependency.task) ? dependency.task : JSON.stringify(dependency.task, undefined, 0), + dependency.uri.toString() + )); + this._showOutput(); } - promises.push(promise); - } else { - this._log(nls.localize('dependencyFailed', - 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', - Types.isString(dependency.task) ? dependency.task : JSON.stringify(dependency.task, undefined, 0), - dependency.uri.toString() - )); - this._showOutput(); } } } @@ -1065,7 +1073,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return needsFolderQualification ? task.getQualifiedLabel() : (task.configurationProperties.name || ''); } - private async _createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string | ((exitCode: number) => string)): Promise { + private async _createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: WaitOnExitValue): Promise { let shellLaunchConfig: IShellLaunchConfig; const isShellCommand = task.command.runtime === RuntimeType.Shell; const needsFolderQualification = this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; @@ -1338,24 +1346,10 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { const options = await this._resolveOptions(resolver, task.command.options); const presentationOptions = task.command.presentation; - let waitOnExit: boolean | string | ((exitCode: number) => string) = false; if (!presentationOptions) { throw new Error('Task presentation options should not be undefined here.'); } - - if ((presentationOptions.close === undefined) || (presentationOptions.close === false)) { - if ((presentationOptions.reveal !== RevealKind.Never) || !task.configurationProperties.isBackground || (presentationOptions.close === false)) { - if (presentationOptions.panel === PanelKind.New) { - waitOnExit = taskShellIntegrationWaitOnExitSequence(nls.localize('closeTerminal', 'Press any key to close the terminal.')); - } else if (presentationOptions.showReuseMessage) { - waitOnExit = taskShellIntegrationWaitOnExitSequence(nls.localize('reuseTerminal', 'Terminal will be reused by tasks, press any key to close it.')); - } else { - waitOnExit = true; - } - } - } else { - waitOnExit = !presentationOptions.close; - } + const waitOnExit = getWaitOnExitValue(presentationOptions, task.configurationProperties); let command: CommandString | undefined; let args: CommandString[] | undefined; @@ -1384,7 +1378,6 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return [undefined, new TaskError(Severity.Error, nls.localize('TerminalTaskSystem', 'Can\'t execute a shell command on an UNC drive using cmd.exe.'), TaskErrors.UnknownError)]; } } - const prefersSameTerminal = presentationOptions.panel === PanelKind.Dedicated; const allowsSharedTerminal = presentationOptions.panel === PanelKind.Shared; const group = presentationOptions.group; @@ -1787,6 +1780,21 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } +function getWaitOnExitValue(presentationOptions: IPresentationOptions, configurationProperties: IConfigurationProperties) { + if ((presentationOptions.close === undefined) || (presentationOptions.close === false)) { + if ((presentationOptions.reveal !== RevealKind.Never) || !configurationProperties.isBackground || (presentationOptions.close === false)) { + if (presentationOptions.panel === PanelKind.New) { + return taskShellIntegrationWaitOnExitSequence(nls.localize('closeTerminal', 'Press any key to close the terminal.')); + } else if (presentationOptions.showReuseMessage) { + return taskShellIntegrationWaitOnExitSequence(nls.localize('reuseTerminal', 'Terminal will be reused by tasks, press any key to close it.')); + } else { + return true; + } + } + } + return !presentationOptions.close; +} + function taskShellIntegrationWaitOnExitSequence(message: string): (exitCode: number) => string { return (exitCode) => { return `${VSCodeSequence(VSCodeOscPt.CommandFinished, exitCode.toString())}${message}`; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 45871689f60..ed6ba54d0eb 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -11,7 +11,7 @@ import { FindReplaceState } from 'vs/editor/contrib/find/browser/findState'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IKeyMods } from 'vs/platform/quickinput/common/quickInput'; import { ITerminalCapabilityStore, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; -import { IExtensionTerminalProfile, IProcessPropertyMap, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, ProcessPropertyType, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IExtensionTerminalProfile, IProcessPropertyMap, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, ProcessPropertyType, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal'; import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProcess'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; @@ -257,6 +257,11 @@ interface ITerminalEditorInputObject { readonly icon: TerminalIcon | undefined; readonly color: string | undefined; readonly hasChildProcesses?: boolean; + readonly task?: { label: string; id: string; lastTask: string; group?: string; waitOnExit?: WaitOnExitValue }; + readonly type?: TerminalType; + readonly isFeatureTerminal?: boolean; + readonly hideFromUser?: boolean; + readonly reconnectionOwner?: string; } export interface ISerializedTerminalEditorInput extends ITerminalEditorInputObject { @@ -513,6 +518,12 @@ export interface ITerminalInstance { */ readonly hasFocus: boolean; + /** + * Get or set the behavior of the terminal when it closes. This was indented only to be called + * after reconnecting to a terminal. + */ + waitOnExit: WaitOnExitValue | undefined; + /** * An event that fires when the terminal instance's title changes. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorSerializer.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorSerializer.ts index 2a8abde35cb..853b4eb98e7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorSerializer.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorSerializer.ts @@ -43,7 +43,11 @@ export class TerminalInputSerializer implements IEditorSerializer { icon: instance.icon, color: instance.color, resource: instance.resource.toString(), - hasChildProcesses: instance.hasChildProcesses + hasChildProcesses: instance.hasChildProcesses, + task: instance.shellLaunchConfig.task, + type: instance.shellLaunchConfig.type, + isFeatureTerminal: instance.shellLaunchConfig.isFeatureTerminal, + hideFromUser: instance.shellLaunchConfig.hideFromUser, }; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a2993cbc0fa..f4c2df2b842 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -226,6 +226,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { xterm?: XtermTerminal; disableLayout: boolean = false; + get waitOnExit(): ITerminalInstance['waitOnExit'] { return this._shellLaunchConfig.attachPersistentProcess?.waitOnExit || this._shellLaunchConfig.waitOnExit; } + set waitOnExit(value: ITerminalInstance['waitOnExit']) { + this._shellLaunchConfig.waitOnExit = value; + } + get target(): TerminalLocation | undefined { return this._target; } set target(value: TerminalLocation | undefined) { if (this.xterm) { @@ -303,12 +308,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { get description(): string | undefined { if (this._description) { return this._description; - } else if (this._shellLaunchConfig.type) { - if (this._shellLaunchConfig.type === 'Task') { + } + const type = this.shellLaunchConfig.attachPersistentProcess?.type || this.shellLaunchConfig.type; + if (type) { + if (type === 'Task') { return nls.localize('terminalTypeTask', "Task"); - } else { - return nls.localize('terminalTypeLocal', "Local"); } + return nls.localize('terminalTypeLocal', "Local"); } return undefined; } @@ -407,6 +413,18 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // the resource is already set when it's been moved from another window this._resource = resource || getTerminalUri(this._workspaceContextService.getWorkspace().id, this.instanceId, this.title); + if (this._shellLaunchConfig.attachPersistentProcess?.hideFromUser) { + this._shellLaunchConfig.hideFromUser = this._shellLaunchConfig.attachPersistentProcess.hideFromUser; + } + + if (this._shellLaunchConfig.attachPersistentProcess?.isFeatureTerminal) { + this._shellLaunchConfig.isFeatureTerminal = this._shellLaunchConfig.attachPersistentProcess.isFeatureTerminal; + } + + if (this._shellLaunchConfig.attachPersistentProcess?.type) { + this._shellLaunchConfig.type = this._shellLaunchConfig.attachPersistentProcess.type; + } + if (this.shellLaunchConfig.cwd) { const cwdUri = typeof this._shellLaunchConfig.cwd === 'string' ? URI.from({ scheme: Schemas.file, @@ -1764,18 +1782,19 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Only trigger wait on exit when the exit was *not* triggered by the // user (via the `workbench.action.terminal.kill` command). - if (this._shellLaunchConfig.waitOnExit && this._processManager.processState !== ProcessState.KilledByUser) { + const waitOnExit = this.waitOnExit; + if (waitOnExit && this._processManager.processState !== ProcessState.KilledByUser) { this._xtermReadyPromise.then(xterm => { if (exitMessage) { xterm.raw.write(formatMessageForTerminal(exitMessage)); } - switch (typeof this._shellLaunchConfig.waitOnExit) { + switch (typeof waitOnExit) { case 'string': - xterm.raw.write(formatMessageForTerminal(this._shellLaunchConfig.waitOnExit, { excludeLeadingNewLine: true })); + xterm.raw.write(formatMessageForTerminal(waitOnExit, { excludeLeadingNewLine: true })); break; case 'function': if (this.exitCode !== undefined) { - xterm.raw.write(formatMessageForTerminal(this._shellLaunchConfig.waitOnExit(this.exitCode), { excludeLeadingNewLine: true })); + xterm.raw.write(formatMessageForTerminal(waitOnExit(this.exitCode), { excludeLeadingNewLine: true })); } break; } @@ -2732,14 +2751,15 @@ export class TerminalLabelComputer extends Disposable { labelType: TerminalLabelType, reset?: boolean ) { + const type = this._instance.shellLaunchConfig.attachPersistentProcess?.type || this._instance.shellLaunchConfig.type; const templateProperties: ITerminalLabelTemplateProperties = { cwd: this._instance.cwd || this._instance.initialCwd || '', cwdFolder: '', workspaceFolder: this._instance.workspaceFolder ? path.basename(this._instance.workspaceFolder.uri.fsPath) : undefined, - local: this._instance.shellLaunchConfig.type === 'Local' ? this._instance.shellLaunchConfig.type : undefined, + local: type === 'Local' ? type : undefined, process: this._instance.processName, sequence: this._instance.sequence, - task: this._instance.shellLaunchConfig.type === 'Task' ? this._instance.shellLaunchConfig.type : undefined, + task: type === 'Task' ? type : undefined, fixedDimensions: this._instance.fixedCols ? (this._instance.fixedRows ? `\u2194${this._instance.fixedCols} \u2195${this._instance.fixedRows}` : `\u2194${this._instance.fixedCols}`) : (this._instance.fixedRows ? `\u2195${this._instance.fixedRows}` : ''), diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 901505cb26a..a869232b29f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -441,7 +441,6 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce remoteAuthority: undefined, os: OS }); - const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); const initialCwd = await terminalEnvironment.getCwd( From fbdc848c29c8d70faeba67b298cc245f1fac2c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E8=89=AF?= <1204183885@qq.com> Date: Tue, 26 Jul 2022 06:41:30 +0800 Subject: [PATCH 063/179] fix: typos (#155310) * fix: typos * chore: revert formatting changes * fix: Remove redundant blank lines --- extensions/git/src/commands.ts | 2 +- src/vs/editor/common/services/getIconClasses.ts | 1 - src/vs/workbench/browser/web.main.ts | 4 ++-- .../services/configuration/browser/configurationService.ts | 6 +++--- .../browser/webExtensionsScannerService.ts | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 560734f6316..ac763f00c53 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1770,7 +1770,7 @@ export class CommandCenter { const shouldPrompt = config.get('confirmEmptyCommits') === true; if (shouldPrompt) { - const message = localize('confirm emtpy commit', "Are you sure you want to create an empty commit?"); + const message = localize('confirm empty commit', "Are you sure you want to create an empty commit?"); const yes = localize('yes', "Yes"); const neverAgain = localize('yes never again', "Yes, Don't Show Again"); const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain); diff --git a/src/vs/editor/common/services/getIconClasses.ts b/src/vs/editor/common/services/getIconClasses.ts index 57a63980ce7..38f13bf83c7 100644 --- a/src/vs/editor/common/services/getIconClasses.ts +++ b/src/vs/editor/common/services/getIconClasses.ts @@ -71,7 +71,6 @@ export function getIconClasses(modelService: IModelService, languageService: ILa return classes; } - export function getIconClassesForLanguageId(languageId: string): string[] { return ['file-icon', `${cssEscape(languageId)}-lang-file-icon`]; } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 0cdc6ba01d3..a307a64ec7e 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -137,7 +137,7 @@ export class BrowserMain extends Disposable { const openerService = accessor.get(IOpenerService); const productService = accessor.get(IProductService); const telemetryService = accessor.get(ITelemetryService); - const progessService = accessor.get(IProgressService); + const progressService = accessor.get(IProgressService); const environmentService = accessor.get(IBrowserWorkbenchEnvironmentService); const instantiationService = accessor.get(IInstantiationService); const remoteExplorerService = accessor.get(IRemoteExplorerService); @@ -169,7 +169,7 @@ export class BrowserMain extends Disposable { } }, window: { - withProgress: (options, task) => progessService.withProgress(options, task) + withProgress: (options, task) => progressService.withProgress(options, task) }, workspace: { openTunnel: async (tunnelOptions) => { diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 6dd1c75a6c2..a1245856684 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -912,12 +912,12 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat private async onWorkspaceFolderConfigurationChanged(folder: IWorkspaceFolder): Promise { const [folderConfiguration] = await this.loadFolderConfigurations([folder]); const previous = { data: this._configuration.toData(), workspace: this.workspace }; - const folderConfiguraitonChange = this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration); + const folderConfigurationChange = this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration); if (this.getWorkbenchState() === WorkbenchState.FOLDER) { const workspaceConfigurationChange = this._configuration.compareAndUpdateWorkspaceConfiguration(folderConfiguration); - this.triggerConfigurationChange(mergeChanges(folderConfiguraitonChange, workspaceConfigurationChange), previous, ConfigurationTarget.WORKSPACE); + this.triggerConfigurationChange(mergeChanges(folderConfigurationChange, workspaceConfigurationChange), previous, ConfigurationTarget.WORKSPACE); } else { - this.triggerConfigurationChange(folderConfiguraitonChange, previous, ConfigurationTarget.WORKSPACE_FOLDER); + this.triggerConfigurationChange(folderConfigurationChange, previous, ConfigurationTarget.WORKSPACE_FOLDER); } this.updateRestrictedSettings(); } diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index bc5e140d42a..61275010652 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -331,7 +331,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten 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 foud.', missingExtensions); + this.logService.info('Skipping the additional builtin extensions because their compatible versions are not found.', missingExtensions); } const webExtensions: IWebExtension[] = []; From 05b8f739bd40b044fa445827f58a11654ba9b511 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Mon, 25 Jul 2022 15:53:46 -0700 Subject: [PATCH 064/179] minor fix on PR, pushing js/ts accidental to later PR --- .../editor/contrib/codeAction/browser/codeActionCommands.ts | 4 ++-- src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index f1c96816b3b..62647863cf5 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -536,7 +536,7 @@ registerEditorCommand(new CodeActionContribution({ kbOpts: { weight: weight + 100000, primary: KeyCode.UpArrow, - secondary: [KeyMod.CtrlCmd | KeyCode.KeyK], + secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow], } })); @@ -549,7 +549,7 @@ registerEditorCommand(new CodeActionContribution({ kbOpts: { weight: weight + 100000, primary: KeyCode.DownArrow, - secondary: [KeyMod.CtrlCmd | KeyCode.KeyJ], + secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow], } })); diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index 9b73033541f..b68b62a20a9 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -279,7 +279,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.codeActionList.value?.layout(height, maxWidth); // List selection - if (this.viewItems.length <= 1 && this.viewItems[0].title === 'Learn more about JS/TS refactorings') { + if (this.viewItems.length < 1) { this.currSelectedItem = 0; } else { this.focusedEnabledItem = 0; @@ -306,7 +306,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusPrevious() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems[0].index; - } else if (this.viewItems.length <= 1 && this.viewItems[0].title !== 'Learn more about JS/TS refactorings') { + } else if (this.viewItems.length < 1) { return false; } @@ -329,7 +329,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusNext() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems.length - 1; - } else if (this.viewItems.length <= 1 && this.viewItems[0].title !== 'Learn more about JS/TS refactorings') { + } else if (this.viewItems.length < 1) { return false; } From 2d48d411f6990ef6fcbff2ab51a144f159e8b3d3 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Mon, 25 Jul 2022 15:55:07 -0700 Subject: [PATCH 065/179] fix on disposable blocking div --- src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index b68b62a20a9..ce67cfa821c 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -217,7 +217,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.block.style.zIndex = '-1'; // TODO@Steven: this is never getting disposed - dom.addDisposableListener(this.block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation()); + renderDisposables.add(dom.addDisposableListener(this.block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation())); renderMenu.id = 'codeActionMenuWidget'; renderMenu.classList.add('codeActionMenuWidget'); From bbe0dbe9258ca18f80a9454f3a0ca53339194c9f Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Mon, 25 Jul 2022 16:05:02 -0700 Subject: [PATCH 066/179] code clean up on pr --- src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index ce67cfa821c..f9b5b7b8547 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -146,7 +146,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { private focusedEnabledItem: number | undefined; private currSelectedItem: number = 0; private hasSeperator: boolean = false; - private block: HTMLElement | null = null; + private block?: HTMLElement; public static readonly ID: string = 'editor.contrib.codeActionMenu'; @@ -216,7 +216,6 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.block.style.height = '100%'; this.block.style.zIndex = '-1'; - // TODO@Steven: this is never getting disposed renderDisposables.add(dom.addDisposableListener(this.block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation())); renderMenu.id = 'codeActionMenuWidget'; @@ -290,8 +289,6 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { // List Focus this.codeActionList.value.domFocus(); const focusTracker = dom.trackFocus(element); - - element.focus(); const blurListener = focusTracker.onDidBlur(() => { this.hideCodeActionWidget(); // this._contextViewService.hideContextView({ source: this }); From 364247dc78b69dc59800528bf4ef26289ff0aac9 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 25 Jul 2022 16:24:14 -0700 Subject: [PATCH 067/179] disable task reconnection by default (#156217) --- .../workbench/contrib/tasks/browser/abstractTaskService.ts | 2 +- .../workbench/contrib/tasks/browser/task.contribution.ts | 6 ++++++ .../workbench/contrib/tasks/browser/terminalTaskSystem.ts | 1 - src/vs/workbench/contrib/tasks/common/tasks.ts | 3 ++- .../workbench/contrib/terminal/browser/terminalInstance.ts | 7 ++++--- .../contrib/terminal/browser/terminalProcessManager.ts | 7 +++---- .../workbench/contrib/terminal/browser/terminalService.ts | 1 - 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index dbe5a62e3be..9df0e983136 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -340,7 +340,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer processContext.set(process && !isVirtual); } this._onDidRegisterSupportedExecutions.fire(); - if (this._jsonTasksSupported && !this._tasksReconnected) { + if (this._configurationService.getValue(TaskSettingId.Reconnection) === true && this._jsonTasksSupported && !this._tasksReconnected) { this._reconnectTasks(); } } diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 658d86f53b2..9e62a8604dc 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -513,6 +513,12 @@ configurationRegistry.registerConfiguration({ description: nls.localize('task.showDecorations', "Shows decorations at points of interest in the terminal buffer such as the first problem found via a watch task. Note that this will only take effect for future tasks."), default: true }, + [TaskSettingId.Reconnection]: { + type: 'boolean', + description: nls.localize('task.experimental.reconnection', "On window reload, reconnect to running watch/background tasks. Note that this is experimental, so you could encounter issues."), + default: false, + tags: ['experimental'] + }, [TaskSettingId.SaveBeforeRun]: { markdownDescription: nls.localize( 'task.saveBeforeRun', diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index abcde9212e7..ff02f515527 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -959,7 +959,6 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); processStartedSignaled = true; } - this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode ?? undefined)); for (let i = 0; i < eventCounter; i++) { diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 2033ec632d9..cfa357558d2 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -1201,7 +1201,8 @@ export const enum TaskSettingId { QuickOpenDetail = 'task.quickOpen.detail', QuickOpenSkip = 'task.quickOpen.skip', QuickOpenShowAll = 'task.quickOpen.showAll', - AllowAutomaticTasks = 'task.allowAutomaticTasks' + AllowAutomaticTasks = 'task.allowAutomaticTasks', + Reconnection = 'task.experimental.reconnection' } export const enum TasksSchemaProperties { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index f4c2df2b842..fde509c864f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -87,6 +87,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProcess'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; +import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; const enum Constants { /** @@ -695,7 +696,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._shutdownPersistentProcessId = shutdownPersistentProcessId; } get persistentProcessId(): number | undefined { return this._processManager.persistentProcessId ?? this._shutdownPersistentProcessId; } - get shouldPersist(): boolean { return (this._processManager.shouldPersist || this._shutdownPersistentProcessId !== undefined) && !this.shellLaunchConfig.isTransient; } + get shouldPersist(): boolean { return (this._processManager.shouldPersist || this._shutdownPersistentProcessId !== undefined) && !this.shellLaunchConfig.isTransient && (!this.reconnectionOwner || this._configurationService.getValue(TaskSettingId.Reconnection) === true); } /** * Create xterm.js instance and attach data listeners. @@ -2386,12 +2387,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } // Recreate the process if the terminal has not yet been interacted with and it's not a - // special terminal (eg. task, extension terminal) + // special terminal (eg. extension terminal) if ( info.requiresAction && this._configHelper.config.environmentChangesRelaunch && !this._processManager.hasWrittenData && - (this.reconnectionOwner || !this._shellLaunchConfig.isFeatureTerminal) && + (!this._shellLaunchConfig.isFeatureTerminal || (this.reconnectionOwner && this._configurationService.getValue(TaskSettingId.Reconnection) === true)) && !this._shellLaunchConfig.customPtyImplementation && !this._shellLaunchConfig.isExtensionOwnedTerminal && !this._shellLaunchConfig.attachPersistentProcess diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index a869232b29f..a82ae60c449 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -36,6 +36,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; @@ -245,8 +246,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce // this is a copy of what the merged environment collection is on the remote side const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig); - - const shouldPersist = (!!shellLaunchConfig.reconnectionOwner || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient; + const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionOwner) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient; if (shellLaunchConfig.attachPersistentProcess) { const result = await backend.attachToProcess(shellLaunchConfig.attachPersistentProcess.id); if (result) { @@ -318,7 +318,6 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce } this._process = newProcess; - this._setProcessState(ProcessState.Launching); // Add any capabilities inherit to the backend @@ -461,7 +460,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce windowsEnableConpty: this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled, environmentVariableCollections: this._extEnvironmentVariableCollection ? serializeEnvironmentVariableCollections(this._extEnvironmentVariableCollection.collections) : undefined }; - const shouldPersist = this._configHelper.config.enablePersistentSessions && (!!this.reconnectionOwner || !shellLaunchConfig.isFeatureTerminal); + const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionOwner) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient; return await backend.createProcess(shellLaunchConfig, initialCwd, cols, rows, this._configHelper.config.unicodeVersion, env, options, shouldPersist); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f315f11cd30..1d504f3334c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -175,7 +175,6 @@ export class TerminalService implements ITerminalService { // we update detected profiles when an instance is created so that, // for example, we detect if you've installed a pwsh this.onDidCreateInstance(() => this._terminalProfileService.refreshAvailableProfiles()); - this._forwardInstanceHostEvents(this._terminalGroupService); this._forwardInstanceHostEvents(this._terminalEditorService); this._terminalGroupService.onDidChangeActiveGroup(this._onDidChangeActiveGroup.fire, this._onDidChangeActiveGroup); From cf145a83ac05de793b04b018c7105c81aada2477 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 25 Jul 2022 16:32:10 -0700 Subject: [PATCH 068/179] Enable safe inline svg tags in trusted html (#156216) Enable safe svg tags in trusted html From https://github.com/cure53/DOMPurify/blob/cce00ac40d33c2aae6422eaa59e6a8aad5c73901/src/tags.js#L124 --- .../notebook/index.ts | 149 ++++++++++++------ 1 file changed, 100 insertions(+), 49 deletions(-) diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index a036374fed1..70dcfd6984b 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -8,57 +8,108 @@ import MarkdownIt from 'markdown-it'; import type * as MarkdownItToken from 'markdown-it/lib/token'; import type { ActivationFunction } from 'vscode-notebook-renderer'; +const allowedHtmlTags = Object.freeze([ + 'a', + 'b', + 'blockquote', + 'br', + 'button', + 'caption', + 'center', + 'code', + 'col', + 'colgroup', + 'details', + 'div', + 'em', + 'font', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'hr', + 'i', + 'img', + 'input', + 'kbd', + 'label', + 'li', + 'ol', + 'p', + 'pre', + 'select', + 'small', + 'span', + 'strong', + 'sub', + 'summary', + 'sup', + 'table', + 'tbody', + 'td', + 'textarea', + 'tfoot', + 'th', + 'thead', + 'tr', + 'tt', + 'u', + 'ul', + 'video', +]); + +const allowedSvgTags = Object.freeze([ + 'svg', + 'a', + 'altglyph', + 'altglyphdef', + 'altglyphitem', + 'animatecolor', + 'animatemotion', + 'animatetransform', + 'circle', + 'clippath', + 'defs', + 'desc', + 'ellipse', + 'filter', + 'font', + 'g', + 'glyph', + 'glyphref', + 'hkern', + 'image', + 'line', + 'lineargradient', + 'marker', + 'mask', + 'metadata', + 'mpath', + 'path', + 'pattern', + 'polygon', + 'polyline', + 'radialgradient', + 'rect', + 'stop', + 'style', + 'switch', + 'symbol', + 'text', + 'textpath', + 'title', + 'tref', + 'tspan', + 'view', + 'vkern', +]); + const sanitizerOptions: DOMPurify.Config = { ALLOWED_TAGS: [ - 'a', - 'b', - 'blockquote', - 'br', - 'button', - 'caption', - 'center', - 'code', - 'col', - 'colgroup', - 'details', - 'div', - 'em', - 'font', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'hr', - 'i', - 'img', - 'input', - 'kbd', - 'label', - 'li', - 'ol', - 'p', - 'pre', - 'select', - 'small', - 'span', - 'strong', - 'sub', - 'summary', - 'sup', - 'table', - 'tbody', - 'td', - 'textarea', - 'tfoot', - 'th', - 'thead', - 'tr', - 'tt', - 'u', - 'ul', - 'video', + ...allowedHtmlTags, + ...allowedSvgTags, ], }; From 8f10b21033161e235e9c14767c21efb550319848 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 25 Jul 2022 16:32:23 -0700 Subject: [PATCH 069/179] Temporarily comment out tuple type annotations (#156213) These seem to be breaking out api generation for the website. Commenting them out for now --- src/vscode-dts/vscode.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 8ddc0b0377f..ba9aa39c643 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -6019,7 +6019,7 @@ declare module 'vscode' { * To get an instance of a `DiagnosticCollection` use * {@link languages.createDiagnosticCollection createDiagnosticCollection}. */ - export interface DiagnosticCollection extends Iterable<[uri: Uri, diagnostics: readonly Diagnostic[]]> { + export interface DiagnosticCollection extends Iterable<[/*uri:*/ Uri, /*diagnostics:*/ readonly Diagnostic[]]> { /** * The name of this diagnostic collection, for instance `typescript`. Every diagnostic @@ -10159,7 +10159,7 @@ declare module 'vscode' { * data transfer. These additional mime types will only be included in the `handleDrop` when the the drag was initiated from * an element in the same drag and drop controller. */ - export class DataTransfer implements Iterable<[mimeType: string, item: DataTransferItem]> { + export class DataTransfer implements Iterable<[/*mimeType:*/ string, /*item:*/ DataTransferItem]> { /** * Retrieves the data transfer item for a given mime type. * @@ -10189,7 +10189,7 @@ declare module 'vscode' { /** * Get a new iterator with the `[mime, item]` pairs for each element in this data transfer. */ - [Symbol.iterator](): IterableIterator<[mimeType: string, item: DataTransferItem]>; + [Symbol.iterator](): IterableIterator<[/*mimeType:*/ string, /*item:*/ DataTransferItem]>; } /** @@ -10858,7 +10858,7 @@ declare module 'vscode' { /** * A collection of mutations that an extension can apply to a process environment. */ - export interface EnvironmentVariableCollection extends Iterable<[variable: string, mutator: EnvironmentVariableMutator]> { + export interface EnvironmentVariableCollection extends Iterable<[/*variable:*/ string, /*mutator:*/ EnvironmentVariableMutator]> { /** * Whether the collection should be cached for the workspace and applied to the terminal * across window reloads. When true the collection will be active immediately such when the @@ -15737,7 +15737,7 @@ declare module 'vscode' { * Collection of test items, found in {@link TestItem.children} and * {@link TestController.items}. */ - export interface TestItemCollection extends Iterable<[id: string, testItem: TestItem]> { + export interface TestItemCollection extends Iterable<[/*id:*/ string, /*testItem:*/ TestItem]> { /** * Gets the number of items in the collection. */ From cc098faebd320a2eea3da6ae154b7e2e1347a4b9 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Mon, 25 Jul 2022 21:01:27 -0400 Subject: [PATCH 070/179] Allow msftInternal to be setting toggled (#156198) --- .../sharedProcess/sharedProcessMain.ts | 7 ++++--- src/vs/code/electron-main/app.ts | 5 +++-- src/vs/code/node/cliProcessMain.ts | 7 ++++--- src/vs/platform/telemetry/browser/1dsAppender.ts | 5 ++--- src/vs/platform/telemetry/common/1dsAppender.ts | 6 ++---- .../platform/telemetry/common/commonProperties.ts | 7 +++---- src/vs/platform/telemetry/common/telemetryUtils.ts | 13 +++++++++++++ src/vs/platform/telemetry/node/1dsAppender.ts | 5 ++--- .../telemetry/test/browser/1dsAppender.test.ts | 4 ++-- src/vs/server/node/serverServices.ts | 7 ++++--- src/vs/workbench/contrib/debug/node/telemetryApp.ts | 2 +- .../services/telemetry/browser/telemetryService.ts | 7 ++++--- .../telemetry/browser/workbenchCommonProperties.ts | 10 ++++++++-- .../telemetry/electron-sandbox/telemetryService.ts | 5 +++-- .../electron-sandbox/workbenchCommonProperties.ts | 4 ++-- .../telemetry/test/browser/commonProperties.test.ts | 6 +++--- .../test/electron-browser/commonProperties.test.ts | 8 ++++---- 17 files changed, 64 insertions(+), 44 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 7f2a4965b81..d959a938e93 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -62,7 +62,7 @@ import { ICustomEndpointTelemetryService, ITelemetryService } from 'vs/platform/ import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; +import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService'; import { LocalReconnectConstants, TerminalIpcChannels, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; @@ -277,19 +277,20 @@ class SharedProcessMain extends Disposable { // Telemetry let telemetryService: ITelemetryService; const appenders: ITelemetryAppender[] = []; + const internalTelemetry = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { const logAppender = new TelemetryLogAppender(loggerService, environmentService); appenders.push(logAppender); const { installSourcePath } = environmentService; if (productService.aiConfig?.ariaKey) { - const collectorAppender = new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey); + const collectorAppender = new OneDataSystemWebAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data appenders.push(collectorAppender); } telemetryService = new TelemetryService({ appenders, - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, productService.msftInternalDomains, installSourcePath), + commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry, installSourcePath), sendErrorTelemetry: true, piiPaths: getPiiPathsFromEnvironment(environmentService), }, configurationService, productService); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 670685ffd9d..b13a6098ddd 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -75,7 +75,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProp import { ITelemetryService, machineIdKey, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { getPiiPathsFromEnvironment, getTelemetryLevel, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { getPiiPathsFromEnvironment, getTelemetryLevel, isInternalTelemetry, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IUpdateService } from 'vs/platform/update/common/update'; import { UpdateChannel } from 'vs/platform/update/common/updateIpc'; import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateService.darwin'; @@ -680,9 +680,10 @@ export class CodeApplication extends Disposable { // Telemetry if (supportsTelemetry(this.productService, this.environmentMainService)) { + const isInternal = isInternalTelemetry(this.productService, this.configurationService); const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, this.productService.msftInternalDomains, this.environmentMainService.installSourcePath); + const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal, this.environmentMainService.installSourcePath); const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService); const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true }; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 79c5b02e686..eda61ad1689 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -52,7 +52,7 @@ import { StateService } from 'vs/platform/state/node/stateService'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; +import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; @@ -187,9 +187,10 @@ class CliMain extends Disposable { // Telemetry const appenders: OneDataSystemAppender[] = []; + const isInternal = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { if (productService.aiConfig && productService.aiConfig.ariaKey) { - appenders.push(new OneDataSystemAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey)); + appenders.push(new OneDataSystemAppender(isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey)); } const { installSourcePath } = environmentService; @@ -208,7 +209,7 @@ class CliMain extends Disposable { } } - return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, productService.msftInternalDomains, installSourcePath); + return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal, installSourcePath); })(), piiPaths: getPiiPathsFromEnvironment(environmentService) }; diff --git a/src/vs/platform/telemetry/browser/1dsAppender.ts b/src/vs/platform/telemetry/browser/1dsAppender.ts index 5075fdfc7df..1481d2ffecd 100644 --- a/src/vs/platform/telemetry/browser/1dsAppender.ts +++ b/src/vs/platform/telemetry/browser/1dsAppender.ts @@ -4,18 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import type { AppInsightsCore } from '@microsoft/1ds-core-js'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsAppender'; export class OneDataSystemWebAppender extends AbstractOneDataSystemAppender { constructor( - configurationService: IConfigurationService | undefined, + isInternalTelemetry: boolean, eventPrefix: string, defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing ) { - super(configurationService, eventPrefix, defaultData, iKeyOrClientFactory); + super(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory); // If we cannot fetch the endpoint it means it is down and we should not send any telemetry. // This is most likely due to ad blockers diff --git a/src/vs/platform/telemetry/common/1dsAppender.ts b/src/vs/platform/telemetry/common/1dsAppender.ts index 5dd4975c9e1..11c49cba163 100644 --- a/src/vs/platform/telemetry/common/1dsAppender.ts +++ b/src/vs/platform/telemetry/common/1dsAppender.ts @@ -7,7 +7,6 @@ import type { AppInsightsCore, IExtendedConfiguration } from '@microsoft/1ds-cor import type { IChannelConfiguration, IXHROverride, PostChannel } from '@microsoft/1ds-post-js'; import { onUnexpectedError } from 'vs/base/common/errors'; import { mixin } from 'vs/base/common/objects'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; const endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0'; @@ -63,7 +62,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende protected readonly endPointUrl = endpointUrl; constructor( - private readonly _configurationService: IConfigurationService | undefined, + private readonly _isInternalTelemetry: boolean, private _eventPrefix: string, private _defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing @@ -92,8 +91,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende } if (!this._asyncAiCore) { - const isInternal = this._configurationService?.getValue('telemetry.internalTesting'); - this._asyncAiCore = getClient(this._aiCoreOrKey, isInternal, this._xhrOverride); + this._asyncAiCore = getClient(this._aiCoreOrKey, this._isInternalTelemetry, this._xhrOverride); } this._asyncAiCore.then( diff --git a/src/vs/platform/telemetry/common/commonProperties.ts b/src/vs/platform/telemetry/common/commonProperties.ts index 06bd318a5eb..1b1df77de55 100644 --- a/src/vs/platform/telemetry/common/commonProperties.ts +++ b/src/vs/platform/telemetry/common/commonProperties.ts @@ -25,7 +25,7 @@ export async function resolveCommonProperties( commit: string | undefined, version: string | undefined, machineId: string | undefined, - msftInternalDomains: string[] | undefined, + isInternalTelemetry: boolean, installSourcePath: string, product?: string ): Promise<{ [name: string]: string | boolean | undefined }> { @@ -50,10 +50,9 @@ export async function resolveCommonProperties( // __GDPR__COMMON__ "common.product" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } result['common.product'] = product || 'desktop'; - const msftInternal = verifyMicrosoftInternalDomain(msftInternalDomains || []); - if (msftInternal) { + if (isInternalTelemetry) { // __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - result['common.msftInternal'] = msftInternal; + result['common.msftInternal'] = isInternalTelemetry; } // dynamic properties which value differs on each call diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index e8c5e417f2e..ded0380e412 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -11,6 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { ConfigurationTarget, ConfigurationTargetToString, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IProductService } from 'vs/platform/product/common/productService'; +import { verifyMicrosoftInternalDomain } from 'vs/platform/telemetry/common/commonProperties'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; @@ -252,6 +253,18 @@ function flatKeys(result: string[], prefix: string, value: { [key: string]: any } } +/** + * Whether or not this is an internal user + * @param productService The product service + * @param configService The config servivce + * @returns true if internal, false otherwise + */ +export function isInternalTelemetry(productService: IProductService, configService: IConfigurationService) { + const msftInternalDomains = productService.msftInternalDomains || []; + const internalTesting = configService.getValue('telemetry.internalTesting'); + return verifyMicrosoftInternalDomain(msftInternalDomains) || internalTesting; +} + interface IPathEnvironment { appRoot: string; extensionsPath: string; diff --git a/src/vs/platform/telemetry/node/1dsAppender.ts b/src/vs/platform/telemetry/node/1dsAppender.ts index c7b6442cf7a..b8825f6e8a9 100644 --- a/src/vs/platform/telemetry/node/1dsAppender.ts +++ b/src/vs/platform/telemetry/node/1dsAppender.ts @@ -6,14 +6,13 @@ import type { AppInsightsCore } from '@microsoft/1ds-core-js'; import type { IPayloadData, IXHROverride } from '@microsoft/1ds-post-js'; import * as https from 'https'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsAppender'; export class OneDataSystemAppender extends AbstractOneDataSystemAppender { constructor( - configurationService: IConfigurationService | undefined, + isInternalTelemetry: boolean, eventPrefix: string, defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing @@ -48,6 +47,6 @@ export class OneDataSystemAppender extends AbstractOneDataSystemAppender { } }; - super(configurationService, eventPrefix, defaultData, iKeyOrClientFactory, customHttpXHROverride); + super(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory, customHttpXHROverride); } } diff --git a/src/vs/platform/telemetry/test/browser/1dsAppender.test.ts b/src/vs/platform/telemetry/test/browser/1dsAppender.test.ts index 0c0378845ab..c59461414d1 100644 --- a/src/vs/platform/telemetry/test/browser/1dsAppender.test.ts +++ b/src/vs/platform/telemetry/test/browser/1dsAppender.test.ts @@ -33,7 +33,7 @@ suite('AIAdapter', () => { setup(() => { appInsightsMock = new AppInsightsCoreMock(); - adapter = new OneDataSystemWebAppender(undefined, prefix, undefined!, () => appInsightsMock); + adapter = new OneDataSystemWebAppender(false, prefix, undefined!, () => appInsightsMock); }); teardown(() => { @@ -48,7 +48,7 @@ suite('AIAdapter', () => { }); test('addional data', () => { - adapter = new OneDataSystemWebAppender(undefined, prefix, { first: '1st', second: 2, third: true }, () => appInsightsMock); + adapter = new OneDataSystemWebAppender(false, prefix, { first: '1st', second: 2, third: true }, () => appInsightsMock); adapter.log('testEvent'); assert.strictEqual(appInsightsMock.events.length, 1); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index ab5f5cb7d57..bc2d71f8f03 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -49,7 +49,7 @@ import { RequestService } from 'vs/platform/request/node/requestService'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; -import { getPiiPathsFromEnvironment, ITelemetryAppender, NullAppender, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { getPiiPathsFromEnvironment, isInternalTelemetry, ITelemetryAppender, NullAppender, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import ErrorTelemetry from 'vs/platform/telemetry/node/errorTelemetry'; import { IPtyService, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; @@ -131,15 +131,16 @@ export async function setupServerServices(connectionToken: ServerConnectionToken let oneDsAppender: ITelemetryAppender = NullAppender; const machineId = await getMachineId(); + const isInternal = isInternalTelemetry(productService, configurationService); if (supportsTelemetry(productService, environmentService)) { if (productService.aiConfig && productService.aiConfig.ariaKey) { - oneDsAppender = new OneDataSystemAppender(configurationService, eventPrefix, null, productService.aiConfig.ariaKey); + oneDsAppender = new OneDataSystemAppender(isInternal, eventPrefix, null, productService.aiConfig.ariaKey); disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } const config: ITelemetryServiceConfig = { appenders: [oneDsAppender], - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, productService.msftInternalDomains, environmentService.installSourcePath, 'remoteAgent'), + commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, isInternal, environmentService.installSourcePath, 'remoteAgent'), piiPaths: getPiiPathsFromEnvironment(environmentService) }; const initialTelemetryLevelArg = environmentService.args['telemetry-level']; diff --git a/src/vs/workbench/contrib/debug/node/telemetryApp.ts b/src/vs/workbench/contrib/debug/node/telemetryApp.ts index 601ff4f9b1e..6296aeb862e 100644 --- a/src/vs/workbench/contrib/debug/node/telemetryApp.ts +++ b/src/vs/workbench/contrib/debug/node/telemetryApp.ts @@ -7,7 +7,7 @@ import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; -const appender = new OneDataSystemAppender(undefined, process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); +const appender = new OneDataSystemAppender(false, process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); process.once('exit', () => appender.flush()); const channel = new TelemetryAppenderChannel([appender]); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 3ad179570b6..f181154fe05 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -15,7 +15,7 @@ import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/pla import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { ITelemetryServiceConfig, TelemetryService as BaseTelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { ITelemetryAppender, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { isInternalTelemetry, ITelemetryAppender, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { resolveWorkbenchCommonProperties } from 'vs/workbench/services/telemetry/browser/workbenchCommonProperties'; @@ -40,12 +40,13 @@ export class TelemetryService extends Disposable implements ITelemetryService { if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.ariaKey) { // If remote server is present send telemetry through that, else use the client side appender const appenders = []; - const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig?.ariaKey); + const isInternal = isInternalTelemetry(productService, configurationService); + const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(isInternal, 'monacoworkbench', null, productService.aiConfig?.ariaKey); appenders.push(telemetryProvider); appenders.push(new TelemetryLogAppender(loggerService, environmentService)); const config: ITelemetryServiceConfig = { appenders, - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.remoteAuthority, productService.embedderIdentifier, productService.removeTelemetryMachineId, environmentService.options && environmentService.options.resolveCommonTelemetryProperties), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, isInternal, environmentService.remoteAuthority, productService.embedderIdentifier, productService.removeTelemetryMachineId, environmentService.options && environmentService.options.resolveCommonTelemetryProperties), sendErrorTelemetry: this.sendErrorTelemetry, }; diff --git a/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts b/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts index 16bce794a23..81c10410b03 100644 --- a/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts +++ b/src/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts @@ -24,12 +24,13 @@ export async function resolveWorkbenchCommonProperties( storageService: IStorageService, commit: string | undefined, version: string | undefined, + isInternalTelemetry: boolean, remoteAuthority?: string, productIdentifier?: string, removeMachineId?: boolean, resolveAdditionalProperties?: () => { [key: string]: any } -): Promise<{ [name: string]: string | undefined }> { - const result: { [name: string]: string | undefined } = Object.create(null); +): Promise<{ [name: string]: string | boolean | undefined }> { + const result: { [name: string]: string | boolean | undefined } = Object.create(null); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.APPLICATION)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.APPLICATION)!; @@ -75,6 +76,11 @@ export async function resolveWorkbenchCommonProperties( // __GDPR__COMMON__ "common.isTouchDevice" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.isTouchDevice'] = String(Gesture.isTouchDevice()); + if (isInternalTelemetry) { + // __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + result['common.msftInternal'] = isInternalTelemetry; + } + // dynamic properties which value differs on each call let seq = 0; const startTime = Date.now(); diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts index a91c4a23be9..0645973a7bb 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITelemetryService, ITelemetryInfo, ITelemetryData, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; -import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; +import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; @@ -37,10 +37,11 @@ export class TelemetryService extends Disposable implements ITelemetryService { super(); if (supportsTelemetry(productService, environmentService)) { + const isInternal = isInternalTelemetry(productService, configurationService); const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appenders: [new TelemetryAppenderClient(channel)], - commonProperties: resolveWorkbenchCommonProperties(storageService, fileService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, fileService, environmentService.os.release, environmentService.os.hostname, productService.commit, productService.version, environmentService.machineId, isInternal, environmentService.installSourcePath, environmentService.remoteAuthority), piiPaths: getPiiPathsFromEnvironment(environmentService), sendErrorTelemetry: true }; diff --git a/src/vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties.ts b/src/vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties.ts index 9d5b4282308..83f9b2c2a7b 100644 --- a/src/vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties.ts +++ b/src/vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties.ts @@ -18,11 +18,11 @@ export async function resolveWorkbenchCommonProperties( commit: string | undefined, version: string | undefined, machineId: string, - msftInternalDomains: string[] | undefined, + isInternalTelemetry: boolean, installSourcePath: string, remoteAuthority?: string ): Promise<{ [name: string]: string | boolean | undefined }> { - const result = await resolveCommonProperties(fileService, release, hostname, process.arch, commit, version, machineId, msftInternalDomains, installSourcePath); + const result = await resolveCommonProperties(fileService, release, hostname, process.arch, commit, version, machineId, isInternalTelemetry, installSourcePath); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.APPLICATION)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.APPLICATION)!; diff --git a/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts b/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts index c3f2b77b696..42640f42bc7 100644 --- a/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts +++ b/src/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts @@ -23,7 +23,7 @@ suite('Browser Telemetry - common properties', function () { }; }; - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, undefined, false, resolveCommonTelemetryProperties); + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.ok('commitHash' in props); assert.ok('sessionID' in props); @@ -53,10 +53,10 @@ suite('Browser Telemetry - common properties', function () { }); }; - const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, undefined, false, resolveCommonTelemetryProperties); + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.strictEqual(props['userId'], 1); - const props2 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, undefined, false, resolveCommonTelemetryProperties); + const props2 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, false, undefined, undefined, false, resolveCommonTelemetryProperties); assert.strictEqual(props2['userId'], 2); }); }); diff --git a/src/vs/workbench/services/telemetry/test/electron-browser/commonProperties.test.ts b/src/vs/workbench/services/telemetry/test/electron-browser/commonProperties.test.ts index 8ae51addd3e..a4813d2485a 100644 --- a/src/vs/workbench/services/telemetry/test/electron-browser/commonProperties.test.ts +++ b/src/vs/workbench/services/telemetry/test/electron-browser/commonProperties.test.ts @@ -46,7 +46,7 @@ suite('Telemetry - common properties', function () { test('default', async function () { await Promises.mkdir(parentDir, { recursive: true }); fs.writeFileSync(installSource, 'my.install.source'); - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', undefined, installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource); assert.ok('commitHash' in props); assert.ok('sessionID' in props); assert.ok('timestamp' in props); @@ -66,7 +66,7 @@ suite('Telemetry - common properties', function () { // machine id et al assert.ok('common.machineId' in props, 'machineId'); fs.unlinkSync(installSource); - const props_1 = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', undefined, installSource); + const props_1 = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource); assert.ok(!('common.source' in props_1)); }); @@ -74,14 +74,14 @@ suite('Telemetry - common properties', function () { testStorageService.store('telemetry.lastSessionDate', new Date().toUTCString(), StorageScope.APPLICATION, StorageTarget.MACHINE); - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', undefined, installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource); assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); assert.strictEqual(props['common.isNewSession'], '0'); }); test('values chance on ask', async function () { - const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', undefined, installSource); + const props = await resolveWorkbenchCommonProperties(testStorageService, testFileService, release(), hostname(), commit, version, 'someMachineId', false, installSource); let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq'); From 0e38fdea94b638136fefcb62884dcaad54994e22 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 26 Jul 2022 07:57:53 +0200 Subject: [PATCH 071/179] Fix #107657 (#156233) Fox #107657 --- .../extensionRecommendationsService.test.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts index 6040e37a790..03adbe3a5f0 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts @@ -447,7 +447,7 @@ suite('ExtensionRecommendationsService Test', () => { }); }); - test.skip('ExtensionRecommendationsService: Able to retrieve collection of all ignored recommendations', async () => { + test('ExtensionRecommendationsService: Able to retrieve collection of all ignored recommendations', async () => { const storageService = instantiationService.get(IStorageService); const workspaceIgnoredRecommendations = ['ms-dotnettools.csharp']; // ignore a stored recommendation and a workspace recommendation. @@ -462,9 +462,7 @@ suite('ExtensionRecommendationsService Test', () => { await testObject.activationPromise; const recommendations = testObject.getAllRecommendationsWithReason(); - assert.ok(recommendations['ms-python.python'], 'ms-python.python extension shall exist'); - assert.ok(!recommendations['mockpublisher2.mockextension2'], 'mockpublisher2.mockextension2 extension shall not exist'); - assert.ok(!recommendations['ms-dotnettools.csharp'], 'ms-dotnettools.csharp extension shall not exist'); + assert.deepStrictEqual(Object.keys(recommendations), ['ms-python.python', 'mockpublisher1.mockextension1']); }); test('ExtensionRecommendationsService: Able to dynamically ignore/unignore global recommendations', async () => { From d2a8be73559a3cdc86260973994f5cc42ca9044a Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 26 Jul 2022 00:20:33 -0700 Subject: [PATCH 072/179] Hide edit sessions view until explicitly shown (#156238) --- .../browser/editSessions.contribution.ts | 33 +++++++++++++++++-- .../editSessions/browser/editSessionsViews.ts | 3 +- .../editSessions/common/editSessions.ts | 2 ++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 68efea1cca6..0602d52a480 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 { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN } 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 } from 'vs/platform/workspace/common/workspace'; @@ -32,14 +32,14 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio import { Extensions, 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, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +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 } from 'vs/workbench/common/views'; +import { IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -70,6 +70,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo private registered = false; private continueEditSessionOptions: ContinueEditSessionItem[] = []; + private readonly shouldShowViewsContext: IContextKey; + constructor( @IEditSessionsWorkbenchService private readonly editSessionsWorkbenchService: IEditSessionsWorkbenchService, @IFileService private readonly fileService: IFileService, @@ -139,6 +141,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.continueEditSessionOptions = continueEditSessionOptions; }); + this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService); + textModelResolverService.registerTextModelContentProvider(EDIT_SESSIONS_SCHEME, instantiationService.createInstance(EditSessionsContentProvider)); } @@ -171,9 +175,32 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo this.registerContinueInLocalFolderAction(); + this.registerShowEditSessionViewAction(); + this.registered = true; } + private registerShowEditSessionViewAction() { + const that = this; + this._register(registerAction2(class ShowEditSessionView extends Action2 { + constructor() { + super({ + 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 + }); + } + + async run(accessor: ServicesAccessor) { + that.shouldShowViewsContext.set(true); + const viewsService = accessor.get(IViewsService); + await viewsService.openViewContainer(EDIT_SESSIONS_CONTAINER_ID); + } + })); + } + private registerContinueEditSessionAction() { const that = this; this._register(registerAction2(class ContinueEditSessionAction extends Action2 { diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index cacef9b047b..36b0c497939 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_SCHEME, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } 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'; @@ -49,6 +49,7 @@ export class EditSessionsDataViews extends Disposable { canMoveView: false, treeView, collapsed: false, + when: ContextKeyExpr.and(EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_SHOW_VIEW), order: 100, hideByDefault: true, }], container); diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index 60b3ab6ca40..da791afa9df 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -75,4 +75,6 @@ export const EDIT_SESSIONS_TITLE = localize('edit sessions', 'Edit Sessions'); export const EDIT_SESSIONS_VIEW_ICON = registerIcon('edit-sessions-view-icon', Codicon.cloudDownload, localize('editSessionViewIcon', 'View icon of the edit sessions view.')); +export const EDIT_SESSIONS_SHOW_VIEW = new RawContextKey('editSessionsShowView', false); + export const EDIT_SESSIONS_SCHEME = 'vscode-edit-sessions'; From 42f2178106b708a85c12d356450fc2c729f9f8a4 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 17:08:02 +0200 Subject: [PATCH 073/179] Fixing the line jumps in the sticky scroll by allowing overflow and setting whitespace=nowrap. --- .../stickyScroll/browser/stickyScroll.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 2e8a9704125..e6ee3656c8d 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -16,6 +16,7 @@ import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; +import 'vs/css!./media/style'; const enum ScrollDirection { Down = 0, @@ -224,10 +225,6 @@ class StickyScrollCodeLine { constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, private readonly _zIndex: number, private readonly _position?: number) { } - replaceTabAndSpacesWithNbsp(str: string, tabSize: number = 4): string { - return str.replace('\t', '\xa0'.repeat(tabSize)).replace(' ', '\xa0'); - } - getDomNode() { const root: HTMLElement = document.createElement('div'); @@ -240,8 +237,7 @@ class StickyScrollCodeLine { actualInlineDecorations = []; } - const modifiedLine = this.replaceTabAndSpacesWithNbsp(this._line, lineRenderingData.tabSize); - const renderLineInput: RenderLineInput = new RenderLineInput(true, true, modifiedLine, lineRenderingData.continuesWithWrappedLine, + const renderLineInput: RenderLineInput = new RenderLineInput(true, true, this._line, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null); @@ -256,16 +252,17 @@ class StickyScrollCodeLine { } const lineHTMLNode = document.createElement('div'); - lineHTMLNode.style.paddingLeft = this._editor.getLayoutInfo().contentLeft - this._editor.getLayoutInfo().lineNumbersLeft - this._editor.getLayoutInfo().lineNumbersWidth + 'px'; - lineHTMLNode.style.float = 'left'; - lineHTMLNode.style.width = this._editor.getLayoutInfo().width - this._editor.getLayoutInfo().contentLeft + 'px'; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + lineHTMLNode.style.overflow = 'hidden'; + lineHTMLNode.style.whiteSpace = 'nowrap'; + lineHTMLNode.style.display = 'inline-block'; lineHTMLNode.innerHTML = newLine as string; const lineNumberHTMLNode = document.createElement('div'); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; + lineNumberHTMLNode.style.display = 'inline-block'; const innerLineNumberHTML = document.createElement('div'); innerLineNumberHTML.innerText = this._lineNumber.toString(); @@ -300,6 +297,8 @@ class StickyScrollCodeLine { root.style.zIndex = this._zIndex.toString(); root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + root.style.overflow = 'hidden'; + root.style.whiteSpace = 'nowrap'; // Special case for last line of sticky scroll if (this._position) { From f37293c6c0e739bf0837a9ed7b3405c6d14add0d Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 17:15:29 +0200 Subject: [PATCH 074/179] Removing an import that caused an error --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index e6ee3656c8d..ca723e08050 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -16,7 +16,6 @@ import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; -import 'vs/css!./media/style'; const enum ScrollDirection { Down = 0, From 9f331b70b668621f90ba9517b6fe335d8f6b4ef0 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 17:35:46 +0200 Subject: [PATCH 075/179] Not sticking outlines which span only one line --- .../stickyScroll/browser/stickyScroll.ts | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index ca723e08050..8e76db3d0a4 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -183,29 +183,31 @@ class StickyScrollController implements IEditorContribution { for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; - topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; - bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; - bottomOfBeginningLine = start * lineHeight; - topOfEndLine = (end - 1) * lineHeight; - bottomOfEndLine = end * lineHeight; + if (end - start > 0) { + topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; + bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; + bottomOfBeginningLine = start * lineHeight; + topOfEndLine = (end - 1) * lineHeight; + bottomOfEndLine = end * lineHeight; - if (!beginningLinesConsidered.has(start)) { - if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + bottomOfEndLine - bottomOfElementAtDepth)); - break; - } - else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + if (!beginningLinesConsidered.has(start)) { + if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + bottomOfEndLine - bottomOfElementAtDepth)); + break; + } + else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || - scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || + scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { + beginningLinesConsidered.add(start); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + } + } else { + this._ranges.splice(index, 1); } - } else { - this._ranges.splice(index, 1); } } From 6bb3909461539c26e609b6cacac37d6b0e138bfc Mon Sep 17 00:00:00 2001 From: "Jui Hanamshet (SHE/HER)" Date: Tue, 26 Jul 2022 09:10:57 -0700 Subject: [PATCH 076/179] If the brackets are removed, reduce the range. If the brackets are added, increase the range --- .../inlineCompletions/browser/inlineCompletionsModel.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index b60a6dec142..4050b76b17b 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -699,7 +699,7 @@ export async function provideInlineCompletions( } for (const item of completions.items) { - const range = item.range ? Range.lift(item.range) : defaultReplaceRange; + let range = item.range ? Range.lift(item.range) : defaultReplaceRange; if (range.startLineNumber !== range.endLineNumber) { // Ignore invalid ranges. @@ -726,6 +726,12 @@ export async function provideInlineCompletions( ); } + // Modify range depending on if brackets are added or removed + if (insertText.length != item.insertText.length) { + const diff = insertText.length - item.insertText.length; + range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff); + } + snippetInfo = undefined; } else if ('snippet' in item.insertText) { const snippet = new SnippetParser().parse(item.insertText.snippet); From ce10de94db823cfda32a9103ee4d59e2cb38d218 Mon Sep 17 00:00:00 2001 From: "Jui Hanamshet (SHE/HER)" Date: Tue, 26 Jul 2022 09:31:24 -0700 Subject: [PATCH 077/179] fixing != to be !== --- .../contrib/inlineCompletions/browser/inlineCompletionsModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index 4050b76b17b..bb49228f345 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -727,7 +727,7 @@ export async function provideInlineCompletions( } // Modify range depending on if brackets are added or removed - if (insertText.length != item.insertText.length) { + if (insertText.length !== item.insertText.length) { const diff = insertText.length - item.insertText.length; range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff); } From 189950f732aad4ab864e6b68efce5d25bfc9a8d9 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 26 Jul 2022 18:54:54 +0200 Subject: [PATCH 078/179] Git Comments: Edit Doesn't Work Always (#156318) Fixes #156260 --- .../contrib/comments/browser/commentThreadZoneWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts index 99c4aae1ca9..c057977818c 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts @@ -456,6 +456,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget override show(rangeOrPos: IRange | IPosition, heightInLines: number): void { this._isExpanded = true; super.show(rangeOrPos, heightInLines); + this._commentThread.collapsibleState = languages.CommentThreadCollapsibleState.Expanded; this._refresh(this._commentThreadWidget.getDimensions()); } From db1d08b7fdc7761002509d0b3e2f93df9f32f484 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 19:04:38 +0200 Subject: [PATCH 079/179] Force the line height to be correct, before was slightly larger than the line height inside of the editor --- .../contrib/stickyScroll/browser/stickyScroll.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 8e76db3d0a4..7a21322f4e1 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -183,7 +183,7 @@ class StickyScrollController implements IEditorContribution { for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; - if (end - start > 0) { + if (end - start > 0 && model.getLineContent(start) !== '') { topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; bottomOfBeginningLine = start * lineHeight; @@ -252,26 +252,29 @@ class StickyScrollCodeLine { newLine = sb.build(); } - const lineHTMLNode = document.createElement('div'); + const lineHTMLNode = document.createElement('span'); lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineHTMLNode.style.overflow = 'hidden'; lineHTMLNode.style.whiteSpace = 'nowrap'; lineHTMLNode.style.display = 'inline-block'; + lineHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; lineHTMLNode.innerHTML = newLine as string; - const lineNumberHTMLNode = document.createElement('div'); + const lineNumberHTMLNode = document.createElement('span'); lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px'; lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)'; lineNumberHTMLNode.style.display = 'inline-block'; + lineNumberHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; - const innerLineNumberHTML = document.createElement('div'); + const innerLineNumberHTML = document.createElement('span'); innerLineNumberHTML.innerText = this._lineNumber.toString(); innerLineNumberHTML.style.paddingLeft = this._editor.getLayoutInfo().lineNumbersLeft.toString() + 'px'; innerLineNumberHTML.style.width = this._editor.getLayoutInfo().lineNumbersWidth.toString() + 'px'; innerLineNumberHTML.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; innerLineNumberHTML.style.textAlign = 'right'; innerLineNumberHTML.style.float = 'left'; + innerLineNumberHTML.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; lineNumberHTMLNode.appendChild(innerLineNumberHTML); lineHTMLNode.onclick = e => { @@ -300,6 +303,8 @@ class StickyScrollCodeLine { root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; root.style.overflow = 'hidden'; root.style.whiteSpace = 'nowrap'; + root.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; + root.style.height = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; // Special case for last line of sticky scroll if (this._position) { From f3ce5b3a508610f73527e481a76ab011560db5b9 Mon Sep 17 00:00:00 2001 From: SamirAk <44325916+SamirPS@users.noreply.github.com> Date: Tue, 26 Jul 2022 19:49:28 +0200 Subject: [PATCH 080/179] Code scanning: deprecation of CodeQL Action v1 (#156271) Update codeql.yml --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6c5d2999898..f64aa7df15c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,14 +24,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: javascript # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -45,4 +45,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From 2cc280494ed8fd2429afff8b5ad2ec18ab1d1dc7 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 20:31:03 +0200 Subject: [PATCH 081/179] Fixing the issue with model not appearing on undo (control+z) --- .../contrib/stickyScroll/browser/stickyScroll.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 7a21322f4e1..098fee4b172 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -61,10 +61,10 @@ class StickyScrollController implements IEditorContribution { return; } else { this._editor.addOverlayWidget(this.stickyScrollWidget); - this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); + this._sessionStore.add(this._editor.onDidChangeModel(() => setTimeout(() => this._update(true), 1000))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); - this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._update(true))); - this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); + this._sessionStore.add(this._editor.onDidChangeModelContent(() => setTimeout(() => this._update(true), 1000))); + this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => setTimeout(() => this._update(true), 1000))); this._update(true); } } @@ -154,15 +154,13 @@ class StickyScrollController implements IEditorContribution { } } } - private _renderStickyScroll() { + private _renderStickyScroll() { if (!(this._editor.hasModel())) { return; } - const lineHeight: number = this._editor.getOption(EditorOption.lineHeight); const model = this._editor.getModel(); - const scrollTop = this._editor.getScrollTop(); let scrollDirection: ScrollDirection; if (this._lastScrollPosition < scrollTop) { From 2077ae51201c39bdcdec981447338fa1db5633b4 Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Tue, 26 Jul 2022 12:19:27 -0700 Subject: [PATCH 082/179] fix package.json/esbuild.js for files in publish --- extensions/ipynb/esbuild.js | 2 +- extensions/ipynb/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ipynb/esbuild.js b/extensions/ipynb/esbuild.js index 444ec268030..973d26faf26 100644 --- a/extensions/ipynb/esbuild.js +++ b/extensions/ipynb/esbuild.js @@ -19,7 +19,7 @@ if (outputRootIndex >= 0) { } const srcDir = path.join(__dirname, 'src'); -const outDir = path.join(outputRoot, 'out'); +const outDir = path.join(outputRoot, 'notebook-out'); async function build() { await esbuild.build({ diff --git a/extensions/ipynb/package.json b/extensions/ipynb/package.json index 7e057f605b7..b7250aee1f4 100644 --- a/extensions/ipynb/package.json +++ b/extensions/ipynb/package.json @@ -57,7 +57,7 @@ "displayName": "Markdown it ipynb Cell Attachment renderer", "entrypoint": { "extends": "vscode.markdown-it-renderer", - "path": "./out/cellAttachmentRenderer.js" + "path": "./notebook-out/cellAttachmentRenderer.js" } } ], From 53c3028c471200cc4402d493d713e58a3980323d Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Tue, 26 Jul 2022 12:29:23 -0700 Subject: [PATCH 083/179] add notebook-out to .gitignore --- extensions/ipynb/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ipynb/.gitignore b/extensions/ipynb/.gitignore index 170d890802b..8c0ca40ca20 100644 --- a/extensions/ipynb/.gitignore +++ b/extensions/ipynb/.gitignore @@ -2,3 +2,4 @@ out dist node_modules *.vsix +notebook-out From 7e3e4bcb88926d90b68845e34f83e2618dc3dd71 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 26 Jul 2022 21:42:02 +0200 Subject: [PATCH 084/179] Remove Manual Folding Range doesn't work (#156278) Remove Manual Folding Range doesn't work. Fixes #156277 --- src/vs/editor/contrib/folding/browser/foldingModel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/foldingModel.ts b/src/vs/editor/contrib/folding/browser/foldingModel.ts index f5b7a59f173..f3bc09b1ce3 100644 --- a/src/vs/editor/contrib/folding/browser/foldingModel.ts +++ b/src/vs/editor/contrib/folding/browser/foldingModel.ts @@ -94,9 +94,9 @@ export class FoldingModel { public removeManualRanges(ranges: ILineRange[]) { const newFoldingRanges: FoldRange[] = new Array(); - const containedBy = (foldRange: FoldRange) => { + const intersects = (foldRange: FoldRange) => { for (const range of ranges) { - if (range.startLineNumber <= foldRange.startLineNumber && range.endLineNumber >= foldRange.endLineNumber) { + if (!(range.startLineNumber > foldRange.endLineNumber || foldRange.startLineNumber > range.endLineNumber)) { return true; } } @@ -104,7 +104,7 @@ export class FoldingModel { }; for (let i = 0; i < this._regions.length; i++) { const foldRange = this._regions.toFoldRange(i); - if (!foldRange.isUserDefined && !foldRange.isRecovered || !containedBy(foldRange)) { + if (!foldRange.isUserDefined && !foldRange.isRecovered || !intersects(foldRange)) { newFoldingRanges.push(foldRange); } } From 8f25356ff191f125332b00c64dd169d7273d1cec Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 26 Jul 2022 13:42:01 -0700 Subject: [PATCH 085/179] remove show X paradigm (#156359) fixes #156308 --- .../contrib/contextmenu/browser/contextmenu.ts | 2 +- src/vs/workbench/browser/actions/layoutActions.ts | 12 ++++++------ .../parts/auxiliarybar/auxiliaryBarActions.ts | 4 ++-- .../browser/parts/editor/breadcrumbsControl.ts | 2 +- src/vs/workbench/browser/parts/panel/panelActions.ts | 4 ++-- .../workbench/browser/parts/titlebar/titlebarPart.ts | 4 ++-- .../contrib/codeEditor/browser/toggleMinimap.ts | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts index 0cd4c1e73b0..650488e797f 100644 --- a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts @@ -311,7 +311,7 @@ export class ContextMenuController implements IEditorContribution { const actions: IAction[] = []; actions.push(createAction({ - label: nls.localize('context.minimap.showMinimap', "Show Minimap"), + label: nls.localize('context.minimap.minimap', "Minimap"), checked: minimapOptions.enabled, run: () => { this._configurationService.updateValue(`editor.minimap.enabled`, !minimapOptions.enabled); diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 150c192a1b8..519e716b8c7 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -81,7 +81,7 @@ export class ToggleActivityBarVisibilityAction extends Action2 { id: ToggleActivityBarVisibilityAction.ID, title: { value: localize('toggleActivityBar', "Toggle Activity Bar Visibility"), - mnemonicTitle: localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), + mnemonicTitle: localize({ key: 'miActivityBar', comment: ['&& denotes a mnemonic'] }, "&&Activity Bar"), original: 'Toggle Activity Bar Visibility' }, category: CATEGORIES.View, @@ -406,7 +406,7 @@ MenuRegistry.appendMenuItems([ group: '2_workbench_layout', command: { id: ToggleSidebarVisibilityAction.ID, - title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Primary Side Bar"), + title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "&&Primary Side Bar"), toggled: SideBarVisibleContext }, order: 1 @@ -417,7 +417,7 @@ MenuRegistry.appendMenuItems([ group: '0_workbench_layout', command: { id: ToggleSidebarVisibilityAction.ID, - title: localize('miShowSidebarNoMnnemonic', "Show Primary Side Bar"), + title: localize('miSidebarNoMnnemonic', "Primary Side Bar"), toggled: SideBarVisibleContext }, order: 0 @@ -464,7 +464,7 @@ export class ToggleStatusbarVisibilityAction extends Action2 { id: ToggleStatusbarVisibilityAction.ID, title: { value: localize('toggleStatusbar', "Toggle Status Bar Visibility"), - mnemonicTitle: localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), + mnemonicTitle: localize({ key: 'miStatusbar', comment: ['&& denotes a mnemonic'] }, "S&&tatus Bar"), original: 'Toggle Status Bar Visibility' }, category: CATEGORIES.View, @@ -573,7 +573,7 @@ if (isWindows || isLinux || isWeb) { id: 'workbench.action.toggleMenuBar', title: { value: localize('toggleMenuBar', "Toggle Menu Bar"), - mnemonicTitle: localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), + mnemonicTitle: localize({ key: 'miMenuBar', comment: ['&& denotes a mnemonic'] }, "Menu &&Bar"), original: 'Toggle Menu Bar' }, category: CATEGORIES.View, @@ -596,7 +596,7 @@ if (isWindows || isLinux || isWeb) { MenuRegistry.appendMenuItem(MenuId.TitleBarContext, { command: { id: 'workbench.action.toggleMenuBar', - title: localize('miShowMenuBarNoMnemonic', "Show Menu Bar"), + title: localize('miMenuBarNoMnemonic', "Menu Bar"), toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')) }, order: 0 diff --git a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts index 2b0b723d0e3..cf521c32e16 100644 --- a/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts +++ b/src/vs/workbench/browser/parts/auxiliarybar/auxiliaryBarActions.ts @@ -76,7 +76,7 @@ MenuRegistry.appendMenuItems([ group: '0_workbench_layout', command: { id: ToggleAuxiliaryBarAction.ID, - title: localize('miShowAuxiliaryBarNoMnemonic', "Show Secondary Side Bar"), + title: localize('miAuxiliaryBarNoMnemonic', "Secondary Side Bar"), toggled: AuxiliaryBarVisibleContext }, order: 2 @@ -116,7 +116,7 @@ MenuRegistry.appendMenuItems([ group: '2_workbench_layout', command: { id: ToggleAuxiliaryBarAction.ID, - title: localize({ key: 'miShowAuxiliaryBar', comment: ['&& denotes a mnemonic'] }, "Show Secondary Si&&de Bar"), + title: localize({ key: 'miAuxiliaryBar', comment: ['&& denotes a mnemonic'] }, "Secondary Si&&de Bar"), toggled: AuxiliaryBarVisibleContext }, order: 2 diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 51879dbf0ba..0ef796ae3fa 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -504,7 +504,7 @@ registerAction2(class ToggleBreadcrumb extends Action2 { id: 'breadcrumbs.toggle', title: { value: localize('cmd.toggle', "Toggle Breadcrumbs"), - mnemonicTitle: localize('miShowBreadcrumbs', "Show &&Breadcrumbs"), + mnemonicTitle: localize('miBreadcrumbs', "&&Breadcrumbs"), original: 'Toggle Breadcrumbs', }, category: CATEGORIES.View, diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index e64439239c5..b23e8bd6fa3 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -422,7 +422,7 @@ MenuRegistry.appendMenuItems([ group: '2_workbench_layout', command: { id: TogglePanelAction.ID, - title: localize({ key: 'miShowPanel', comment: ['&& denotes a mnemonic'] }, "Show &&Panel"), + title: localize({ key: 'miPanel', comment: ['&& denotes a mnemonic'] }, "&&Panel"), toggled: PanelVisibleContext }, order: 5 @@ -433,7 +433,7 @@ MenuRegistry.appendMenuItems([ group: '0_workbench_layout', command: { id: TogglePanelAction.ID, - title: localize('miShowPanelNoMnemonic', "Show Panel"), + title: localize('miPanelNoMnemonic', "Panel"), toggled: PanelVisibleContext }, order: 4 diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 7c4cef14f90..31f4d9b6e27 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -524,12 +524,12 @@ class ToogleConfigAction extends Action2 { registerAction2(class ToogleCommandCenter extends ToogleConfigAction { constructor() { - super('window.commandCenter', localize('toggle.commandCenter', 'Show Command Center'), 1); + super('window.commandCenter', localize('toggle.commandCenter', 'Command Center'), 1); } }); registerAction2(class ToogleLayoutControl extends ToogleConfigAction { constructor() { - super('workbench.layoutControl.enabled', localize('toggle.layout', 'Show Layout Controls'), 2); + super('workbench.layoutControl.enabled', localize('toggle.layout', 'Layout Controls'), 2); } }); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts index 54fc34de741..f0ea2a89e33 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -20,7 +20,7 @@ export class ToggleMinimapAction extends Action2 { title: { value: localize('toggleMinimap', "Toggle Minimap"), original: 'Toggle Minimap', - mnemonicTitle: localize({ key: 'miShowMinimap', comment: ['&& denotes a mnemonic'] }, "Show &&Minimap") + mnemonicTitle: localize({ key: 'miMinimap', comment: ['&& denotes a mnemonic'] }, "&&Minimap") }, category: CATEGORIES.View, f1: true, From 69d1f955d1ea0cc56f63a06c3b3bbab037971475 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 23:11:25 +0200 Subject: [PATCH 086/179] Changed the settings text to make the functionality of the sticky scroll clearer. --- src/vs/editor/common/config/editorOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 826aa1a6a72..f6f71c68076 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2537,7 +2537,7 @@ class EditorStickyScroll extends BaseEditorOption Date: Tue, 26 Jul 2022 23:30:07 +0200 Subject: [PATCH 087/179] Set timetout to 500 milliseconds on model change in order to let the coloring be done before rendering sticky scroll (this timeout is also necessary for rendering upon control+z). --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 098fee4b172..27c578e8026 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -61,10 +61,10 @@ class StickyScrollController implements IEditorContribution { return; } else { this._editor.addOverlayWidget(this.stickyScrollWidget); - this._sessionStore.add(this._editor.onDidChangeModel(() => setTimeout(() => this._update(true), 1000))); + this._sessionStore.add(this._editor.onDidChangeModel(() => setTimeout(() => this._update(true), 500))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); - this._sessionStore.add(this._editor.onDidChangeModelContent(() => setTimeout(() => this._update(true), 1000))); - this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => setTimeout(() => this._update(true), 1000))); + this._sessionStore.add(this._editor.onDidChangeModelContent(() => setTimeout(() => this._update(true), 500))); + this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => setTimeout(() => this._update(true), 500))); this._update(true); } } From 001843b0a87017ab3a96583bc87a4d79ffc113e9 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Tue, 26 Jul 2022 14:42:06 -0700 Subject: [PATCH 088/179] fix accidental hits on js/ts, added hovers, added keybdinings for refactor w/preview, fixed domFocus and important tags --- .../codeAction/browser/codeActionCommands.ts | 16 ++++++ .../codeAction/browser/codeActionMenu.ts | 50 ++++++++++++++++--- .../codeAction/browser/codeActionUi.ts | 13 ++++- .../codeAction/browser/media/action.css | 8 +-- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 62647863cf5..6c6f5fb306f 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -151,6 +151,10 @@ export class QuickFixController extends Disposable implements IEditorContributio } } + public selectedOptionWithPreview() { + this._ui.getValue().onPreviewEnter(); + } + public showCodeActions(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) { return this._ui.getValue().showCodeActionList(trigger, actions, at, { includeDisabledActions: false, fromLightbulb: false }); } @@ -566,4 +570,16 @@ registerEditorCommand(new CodeActionContribution({ } })); +registerEditorCommand(new CodeActionContribution({ + id: 'onEnterSelectCodeActionWithPreview', + precondition: Context.Visible, + handler(x) { + x.selectedOptionWithPreview(); + }, + kbOpts: { + weight: weight + 100000, + primary: KeyMod.CtrlCmd | KeyCode.Enter, + } +})); + diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index f9b5b7b8547..0cc02fbc935 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -5,7 +5,7 @@ import * as dom from 'vs/base/browser/dom'; import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; -import { IListEvent, IListRenderer } from 'vs/base/browser/ui/list/list'; +import { IListEvent, IListMouseEvent, IListRenderer } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { canceled } from 'vs/base/common/errors'; @@ -69,6 +69,7 @@ export interface ICodeActionMenuItem { decoratorRight?: string; isSeparator?: boolean; isEnabled: boolean; + isDocumentation: boolean; index: number; disposables?: IDisposable[]; } @@ -93,6 +94,13 @@ const TEMPLATE_ID = 'codeActionWidget'; const codeActionLineHeight = 26; class CodeMenuRenderer implements IListRenderer { + + constructor( + @IKeybindingService private readonly keybindingService: IKeybindingService, + ) { + + } + get templateId(): string { return TEMPLATE_ID; } renderTemplate(container: HTMLElement): ICodeActionMenuTemplateData { @@ -114,6 +122,7 @@ class CodeMenuRenderer implements IListRenderer { + const [accept, preview] = [`onEnterSelectCodeAction`, `onEnterSelectCodeActionWithPreview`]; + data.root.title = this.keybindingService.lookupKeybinding(accept)?.getLabel() + ' to Refactor, ' + this.keybindingService.lookupKeybinding(preview)?.getLabel() + ' to Preview'; + }; + updateLabel(); + } + } disposeTemplate(templateData: ICodeActionMenuTemplateData): void { templateData.disposables = dispose(templateData.disposables); @@ -155,7 +172,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { } private readonly _keybindingResolver: CodeActionKeybindingResolver; - private listRenderer: CodeMenuRenderer = new CodeMenuRenderer(); + private listRenderer: CodeMenuRenderer; constructor( private readonly _editor: ICodeEditor, @@ -176,6 +193,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { }); this._ctxMenuWidgetVisible = Context.Visible.bindTo(this._contextKeyService); + this.listRenderer = new CodeMenuRenderer(keybindingService); } get isVisible(): boolean { @@ -200,6 +218,18 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { } + private _onListHover(e: IListMouseEvent): void { + if (!e.element) { + this.codeActionList.value?.setFocus([]); + } else { + if (e.element?.isEnabled) { + this.codeActionList.value?.setFocus([e.element.index]); + this.focusedEnabledItem = this.viewItems.indexOf(e.element); + this.currSelectedItem = e.element.index; + } + } + } + private renderCodeActionMenuList(element: HTMLElement, inputArray: IAction[]): IDisposable { const renderDisposables = new DisposableStore(); const renderMenu = document.createElement('div'); @@ -236,6 +266,8 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { }, [this.listRenderer], { keyboardSupport: false } ); + renderDisposables.add(this.codeActionList.value.onMouseOver(e => this._onListHover(e))); + renderDisposables.add(this.codeActionList.value.onDidChangeFocus(e => this.codeActionList.value?.domFocus())); renderDisposables.add(this.codeActionList.value.onDidChangeSelection(e => this._onListSelection(e))); renderDisposables.add(this._editor.onDidLayoutChange(e => this.hideCodeActionWidget())); @@ -243,11 +275,16 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { // Populating the list widget and tracking enabled options. inputArray.forEach((item, index) => { const currIsSeparator = item.class === 'separator'; + let isDocumentation = false; + if (item instanceof CodeActionAction) { + isDocumentation = item.action.kind === '_documentation'; + } + if (currIsSeparator) { // set to true forever this.hasSeperator = true; } - const menuItem = { title: item.label, detail: item.tooltip, action: inputArray[index], isEnabled: item.enabled, isSeparator: currIsSeparator, index }; + const menuItem = { title: item.label, detail: item.tooltip, action: inputArray[index], isEnabled: item.enabled, isSeparator: currIsSeparator, index, isDocumentation }; if (item.enabled) { this.viewItems.push(menuItem); } @@ -278,7 +315,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.codeActionList.value?.layout(height, maxWidth); // List selection - if (this.viewItems.length < 1) { + if (this.viewItems.length < 1 || (this.viewItems.length === 1 && this.viewItems[0].isDocumentation)) { this.currSelectedItem = 0; } else { this.focusedEnabledItem = 0; @@ -303,7 +340,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusPrevious() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems[0].index; - } else if (this.viewItems.length < 1) { + } else if (this.viewItems.length < 1 || (this.viewItems.length === 1 && !this.viewItems[0].isDocumentation)) { return false; } @@ -326,7 +363,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusNext() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems.length - 1; - } else if (this.viewItems.length < 1) { + } else if (this.viewItems.length < 1 || (this.viewItems.length === 1 && !this.viewItems[0].isDocumentation)) { return false; } @@ -474,6 +511,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { result.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction(new CodeActionItem({ title: command.title, command: command, + kind: '_documentation' }, undefined)))); } diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index e42d043ab5e..f8ac0210a73 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -23,6 +23,7 @@ export class CodeActionUi extends Disposable { private readonly _codeActionWidget: Lazy; private readonly _lightBulbWidget: Lazy; private readonly _activeCodeActions = this._register(new MutableDisposable()); + private previewOn: boolean = false; #disposed = false; @@ -40,7 +41,12 @@ export class CodeActionUi extends Disposable { this._codeActionWidget = new Lazy(() => { return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { onSelectCodeAction: async (action, trigger) => { - this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(trigger.preview)); + if (this.previewOn) { + this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(this.previewOn)); + } else { + this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(trigger.preview)); + } + this.previewOn = false; } })); }); @@ -70,6 +76,11 @@ export class CodeActionUi extends Disposable { } } + public onPreviewEnter() { + this.previewOn = true; + this.onEnter(); + } + public navigateList(navUp: Boolean) { if (this._codeActionWidget.hasValue()) { if (navUp) { diff --git a/src/vs/editor/contrib/codeAction/browser/media/action.css b/src/vs/editor/contrib/codeAction/browser/media/action.css index a32d77522f4..52faf076802 100644 --- a/src/vs/editor/contrib/codeAction/browser/media/action.css +++ b/src/vs/editor/contrib/codeAction/browser/media/action.css @@ -30,10 +30,10 @@ z-index: 5; /* make sure we are on top of the tree items */ content: ""; pointer-events: none; /* enable click through */ - outline: 0px solid; /* we still need to handle the empty tree or no focus item case */ - outline-width: 0px; - outline-style: none; - outline-offset: 0px; + outline: 0px solid !important; /* we still need to handle the empty tree or no focus item case */ + outline-width: 0px !important; + outline-style: none !important; + outline-offset: 0px !important; } .codeActionMenuWidget .monaco-list { From 15229f184a1bbc62d8c31a392a5d4793e0d910b9 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Tue, 26 Jul 2022 23:45:05 +0200 Subject: [PATCH 089/179] OnModelChange need to empty the stickyScrollWidget before rendering after a delay of 500 ms --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 27c578e8026..3a742f81246 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -61,7 +61,7 @@ class StickyScrollController implements IEditorContribution { return; } else { this._editor.addOverlayWidget(this.stickyScrollWidget); - this._sessionStore.add(this._editor.onDidChangeModel(() => setTimeout(() => this._update(true), 500))); + this._sessionStore.add(this._editor.onDidChangeModel(() => this.onModelChange())); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); this._sessionStore.add(this._editor.onDidChangeModelContent(() => setTimeout(() => this._update(true), 500))); this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => setTimeout(() => this._update(true), 500))); @@ -69,6 +69,11 @@ class StickyScrollController implements IEditorContribution { } } + private onModelChange() { + this.stickyScrollWidget.emptyRootNode(); + setTimeout(() => this._update(true), 500); + } + private async _update(updateOutline: boolean = false): Promise { if (updateOutline) { this._cts?.dispose(true); From 02dd789283f7c89d1cb15e654d52007d877920c8 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 27 Jul 2022 00:19:18 +0200 Subject: [PATCH 090/179] Changing the color of the sticky scroll so it is of the same background as editor and on hover it has the list hover color from the registry --- .../contrib/stickyScroll/browser/stickyScroll.ts | 13 ++++++++++--- src/vs/platform/theme/common/colorRegistry.ts | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 3a742f81246..4048a5fc9ec 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -125,6 +125,7 @@ class StickyScrollController implements IEditorContribution { if (this._editor.hasModel()) { const model = this._editor.getModel(); const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token); + console.log('outline model is : ', outlineModel); if (token.isCancellationRequested) { return; } @@ -280,20 +281,26 @@ class StickyScrollCodeLine { innerLineNumberHTML.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; lineNumberHTMLNode.appendChild(innerLineNumberHTML); - lineHTMLNode.onclick = e => { + root.onclick = e => { e.stopPropagation(); e.preventDefault(); this._editor.revealLine(this._lineNumber); }; - lineHTMLNode.onmouseover = e => { + root.onmouseover = e => { innerLineNumberHTML.style.background = `var(--vscode-editorStickyScrollHover-background)`; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; + root.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; innerLineNumberHTML.style.cursor = `pointer`; lineHTMLNode.style.cursor = `pointer`; + root.style.cursor = `pointer`; + lineNumberHTMLNode.style.cursor = `pointer`; }; - lineHTMLNode.onmouseleave = e => { + root.onmouseleave = e => { innerLineNumberHTML.style.background = `var(--vscode-editorStickyScroll-background)`; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; + root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; }; this._editor.applyFontInfo(lineHTMLNode); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 129959b9e23..c1f226c3601 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -315,8 +315,8 @@ export const editorForeground = registerColor('editor.foreground', { light: '#33 /** * Sticky scroll */ -export const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: darken(editorBackground, 0.2), dark: lighten(editorBackground, 0.2), hcDark: lighten(editorBackground, 0.2), hcLight: darken(editorBackground, 0.2) }, nls.localize('editorStickyScrollBackground', "Sticky scroll background color for the editor")); -export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { light: darken(editorBackground, 0.4), dark: lighten(editorBackground, 0.4), hcDark: lighten(editorBackground, 0.4), hcLight: darken(editorBackground, 0.4) }, nls.localize('editorStickyScrollHoverBackground', "Sticky scroll on hover background color for the editor")); +export const editorStickyScrollBackground = registerColor('editorStickyScroll.background', { light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground }, nls.localize('editorStickyScrollBackground', "Sticky scroll background color for the editor")); +export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background', { dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) }, nls.localize('editorStickyScrollHoverBackground', "Sticky scroll on hover background color for the editor")); /** * Editor widgets From d31f53b5dc057aff1fe9513f62d283bd608e6100 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Tue, 26 Jul 2022 15:27:52 -0700 Subject: [PATCH 091/179] code clean up and fix on documentation type check --- .../codeAction/browser/codeActionCommands.ts | 5 ++++- .../codeAction/browser/codeActionMenu.ts | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 6c6f5fb306f..7f106ceba40 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -152,7 +152,10 @@ export class QuickFixController extends Disposable implements IEditorContributio } public selectedOptionWithPreview() { - this._ui.getValue().onPreviewEnter(); + if (this._ui.hasValue()) { + this._ui.getValue().onPreviewEnter(); + } + } public showCodeActions(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) { diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index 0cc02fbc935..8ce748081a0 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -96,10 +96,9 @@ const codeActionLineHeight = 26; class CodeMenuRenderer implements IListRenderer { constructor( + private readonly acceptKeybindings: [string, string], @IKeybindingService private readonly keybindingService: IKeybindingService, - ) { - - } + ) { } get templateId(): string { return TEMPLATE_ID; } @@ -141,8 +140,9 @@ class CodeMenuRenderer implements IListRenderer { - const [accept, preview] = [`onEnterSelectCodeAction`, `onEnterSelectCodeActionWithPreview`]; - data.root.title = this.keybindingService.lookupKeybinding(accept)?.getLabel() + ' to Refactor, ' + this.keybindingService.lookupKeybinding(preview)?.getLabel() + ' to Preview'; + const [accept, preview] = this.acceptKeybindings; + data.root.title = localize({ key: 'label', comment: ['placeholders are keybindings, e.g "F2 to Refactor, Shift+F2 to Preview"'] }, "{0} to Rename, {1} to Preview", this.keybindingService.lookupKeybinding(accept)?.getLabel(), this.keybindingService.lookupKeybinding(preview)?.getLabel()); + // data.root.title = this.keybindingService.lookupKeybinding(accept)?.getLabel() + ' to Refactor, ' + this.keybindingService.lookupKeybinding(preview)?.getLabel() + ' to Preview'; }; updateLabel(); } @@ -193,7 +193,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { }); this._ctxMenuWidgetVisible = Context.Visible.bindTo(this._contextKeyService); - this.listRenderer = new CodeMenuRenderer(keybindingService); + this.listRenderer = new CodeMenuRenderer([`onEnterSelectCodeAction`, `onEnterSelectCodeActionWithPreview`], keybindingService); } get isVisible(): boolean { @@ -315,7 +315,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.codeActionList.value?.layout(height, maxWidth); // List selection - if (this.viewItems.length < 1 || (this.viewItems.length === 1 && this.viewItems[0].isDocumentation)) { + if (this.viewItems.length < 1 || this.viewItems.every(item => item.isDocumentation)) { this.currSelectedItem = 0; } else { this.focusedEnabledItem = 0; @@ -340,7 +340,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusPrevious() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems[0].index; - } else if (this.viewItems.length < 1 || (this.viewItems.length === 1 && !this.viewItems[0].isDocumentation)) { + } else if (this.viewItems.length < 1) { return false; } @@ -363,7 +363,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { protected focusNext() { if (typeof this.focusedEnabledItem === 'undefined') { this.focusedEnabledItem = this.viewItems.length - 1; - } else if (this.viewItems.length < 1 || (this.viewItems.length === 1 && !this.viewItems[0].isDocumentation)) { + } else if (this.viewItems.length < 1) { return false; } From 181df9e79298a6da0b955967295ba840de2fdaf2 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Tue, 26 Jul 2022 16:25:13 -0700 Subject: [PATCH 092/179] added global ID for documentation --- src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index 8ce748081a0..dc1a9a5031b 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -165,6 +165,8 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { private hasSeperator: boolean = false; private block?: HTMLElement; + public static readonly documentationID: string = '_documentation'; + public static readonly ID: string = 'editor.contrib.codeActionMenu'; public static get(editor: ICodeEditor): CodeActionMenu | null { @@ -277,7 +279,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { const currIsSeparator = item.class === 'separator'; let isDocumentation = false; if (item instanceof CodeActionAction) { - isDocumentation = item.action.kind === '_documentation'; + isDocumentation = item.action.kind === CodeActionMenu.documentationID; } if (currIsSeparator) { @@ -511,7 +513,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { result.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction(new CodeActionItem({ title: command.title, command: command, - kind: '_documentation' + kind: CodeActionMenu.documentationID }, undefined)))); } From 9cf2fabdd600c7d8e3230803acb246405321e8dd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 26 Jul 2022 21:44:44 -0700 Subject: [PATCH 093/179] Rename editor.dropIntoEditor.enabled setting (#156381) Fixes #156344 --- .../package.nls.json | 2 +- .../editor/browser/widget/codeEditorWidget.ts | 4 +- .../editor/browser/widget/diffEditorWidget.ts | 2 +- src/vs/editor/common/config/editorOptions.ts | 59 ++++++++++++++++--- .../common/standalone/standaloneEnums.ts | 2 +- .../browser/dropIntoEditorContribution.ts | 17 ------ src/vs/monaco.d.ts | 21 +++++-- .../browser/parts/editor/editorDropTarget.ts | 2 +- .../browser/parts/editor/textDiffEditor.ts | 4 +- .../browser/parts/editor/textEditor.ts | 4 +- .../browser/workbench.contribution.ts | 5 -- .../browser/view/cellParts/markdownCell.ts | 2 +- .../browser/view/renderers/cellRenderer.ts | 2 +- .../contrib/scm/browser/scmViewPane.ts | 2 +- src/vscode-dts/vscode.d.ts | 2 +- 15 files changed, 82 insertions(+), 48 deletions(-) diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 062c6ac899f..1c32e447e05 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -29,7 +29,7 @@ "configuration.markdown.links.openLocation.currentGroup": "Open links in the active editor group.", "configuration.markdown.links.openLocation.beside": "Open links beside the active editor.", "configuration.markdown.suggest.paths.enabled.description": "Enable/disable path suggestions for markdown links", - "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbench.editor.dropIntoEditor.enabled#`.", + "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#editor.dropIntoEditor.enabled#`.", "configuration.markdown.editor.pasteLinks.enabled": "Enable/disable pasting files into a Markdown editor inserts Markdown links. Requires enabling `#editor.experimental.pasteActions.enabled#`.", "configuration.markdown.experimental.validate.enabled.description": "Enable/disable all error reporting in Markdown files.", "configuration.markdown.experimental.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.", diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 0cc2cfa02af..bed9912d2d3 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -371,7 +371,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._register(new dom.DragAndDropObserver(this._domElement, { onDragEnter: () => undefined, onDragOver: e => { - if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) { + if (!this._configuration.options.get(EditorOption.dropIntoEditor).enabled) { return; } @@ -381,7 +381,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } }, onDrop: async e => { - if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) { + if (!this._configuration.options.get(EditorOption.dropIntoEditor).enabled) { return; } diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index ee1a5a107b9..ef1aa278e53 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -1189,7 +1189,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE result.ariaLabel = options.originalAriaLabel; } result.readOnly = !this._options.originalEditable; - result.enableDropIntoEditor = !result.readOnly; + result.dropIntoEditor = { enabled: !result.readOnly }; result.extraEditorClassName = 'original-in-monaco-diff-editor'; return { ...result, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 826aa1a6a72..066080e9ae3 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -665,11 +665,11 @@ export interface IEditorOptions { bracketPairColorization?: IBracketPairColorizationOptions; /** - * Enables dropping into the editor from an external source. + * Controls dropping into the editor from an external source. * - * This shows a preview of the drop location and triggers an `onDropIntoEditor` event. + * When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event. */ - enableDropIntoEditor?: boolean; + dropIntoEditor?: IDropIntoEditorOptions; } /** @@ -4439,6 +4439,53 @@ class EditorWrappingInfoComputer extends ComputedEditorOption>; + +class EditorDropIntoEditor extends BaseEditorOption { + + constructor() { + const defaults: EditorDropIntoEditorOptions = { enabled: true }; + super( + EditorOption.dropIntoEditor, 'dropIntoEditor', defaults, + { + 'editor.dropIntoEditor.enabled': { + type: 'boolean', + default: defaults.enabled, + markdownDescription: nls.localize('dropIntoEditor.enabled', "Controls whether you can drag and drop a file into a text editor by holding down `shift` (instead of opening the file in an editor)."), + }, + } + ); + } + + public validate(_input: any): EditorDropIntoEditorOptions { + if (!_input || typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IDropIntoEditorOptions; + return { + enabled: boolean(input.enabled, this.defaultValue.enabled) + }; + } +} + +//#endregion + const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace'; const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace'; const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace'; @@ -4501,7 +4548,7 @@ export const enum EditorOption { disableMonospaceOptimizations, domReadOnly, dragAndDrop, - enableDropIntoEditor, + dropIntoEditor, emptySelectionClipboard, extraEditorClassName, fastScrollSensitivity, @@ -4811,9 +4858,7 @@ export const EditorOptions = { { description: nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") } )), emptySelectionClipboard: register(new EditorEmptySelectionClipboard()), - enableDropIntoEditor: register(new EditorBooleanOption( - EditorOption.enableDropIntoEditor, 'enableDropIntoEditor', true - )), + dropIntoEditor: register(new EditorDropIntoEditor()), extraEditorClassName: register(new EditorStringOption( EditorOption.extraEditorClassName, 'extraEditorClassName', '', )), diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 6e9446f55db..c62e7fc404f 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -204,7 +204,7 @@ export enum EditorOption { disableMonospaceOptimizations = 29, domReadOnly = 30, dragAndDrop = 31, - enableDropIntoEditor = 32, + dropIntoEditor = 32, emptySelectionClipboard = 33, extraEditorClassName = 34, fastScrollSensitivity = 35, diff --git a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts index 10ed525fc05..83f8ad1e314 100644 --- a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts +++ b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts @@ -25,7 +25,6 @@ import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/edit import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; import { localize } from 'vs/nls'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -37,7 +36,6 @@ export class DropIntoEditorController extends Disposable implements IEditorContr constructor( editor: ICodeEditor, @IBulkEditService private readonly _bulkEditService: IBulkEditService, - @IConfigurationService private readonly _configurationService: IConfigurationService, @ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService, @IProgressService private readonly _progressService: IProgressService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @@ -46,22 +44,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr this._register(editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event))); - this._languageFeaturesService.documentOnDropEditProvider.register('*', new DefaultOnDropProvider(workspaceContextService)); - - this._register(this._configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('workbench.editor.dropIntoEditor.enabled')) { - this.updateEditorOptions(editor); - } - })); - - this.updateEditorOptions(editor); - } - - private updateEditorOptions(editor: ICodeEditor) { - editor.updateOptions({ - enableDropIntoEditor: this._configurationService.getValue('workbench.editor.dropIntoEditor.enabled') - }); } private async onDropIntoEditor(editor: ICodeEditor, position: IPosition, dragEvent: DragEvent) { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index ac468aa007f..db39c17f9c6 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3439,11 +3439,11 @@ declare namespace monaco.editor { */ bracketPairColorization?: IBracketPairColorizationOptions; /** - * Enables dropping into the editor from an external source. + * Controls dropping into the editor from an external source. * - * This shows a preview of the drop location and triggers an `onDropIntoEditor` event. + * When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event. */ - enableDropIntoEditor?: boolean; + dropIntoEditor?: IDropIntoEditorOptions; } export interface IDiffEditorBaseOptions { @@ -4330,6 +4330,17 @@ declare namespace monaco.editor { readonly wrappingColumn: number; } + /** + * Configuration options for editor drop into behavior + */ + export interface IDropIntoEditorOptions { + /** + * Enable the dropping into editor. + * Defaults to true. + */ + enabled?: boolean; + } + export enum EditorOption { acceptSuggestionOnCommitCharacter = 0, acceptSuggestionOnEnter = 1, @@ -4363,7 +4374,7 @@ declare namespace monaco.editor { disableMonospaceOptimizations = 29, domReadOnly = 30, dragAndDrop = 31, - enableDropIntoEditor = 32, + dropIntoEditor = 32, emptySelectionClipboard = 33, extraEditorClassName = 34, fastScrollSensitivity = 35, @@ -4503,7 +4514,7 @@ declare namespace monaco.editor { domReadOnly: IEditorOption; dragAndDrop: IEditorOption; emptySelectionClipboard: IEditorOption; - enableDropIntoEditor: IEditorOption; + dropIntoEditor: IEditorOption>>; extraEditorClassName: IEditorOption; fastScrollSensitivity: IEditorOption; find: IEditorOption>>; diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index e9686439360..947f4475f3b 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -32,7 +32,7 @@ interface IDropOperation { } function isDropIntoEditorEnabledGlobally(configurationService: IConfigurationService) { - return configurationService.getValue('workbench.editor.dropIntoEditor.enabled'); + return configurationService.getValue('editor.dropIntoEditor.enabled'); } function isDragIntoEditorEvent(e: DragEvent): boolean { diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 2aa1285f9a1..2dcf135be7c 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -240,7 +240,7 @@ export class TextDiffEditor extends AbstractTextEditor imp return { ...super.getConfigurationOverrides(), readOnly, - enableDropIntoEditor: !readOnly, + dropIntoEditor: { enabled: !readOnly }, originalEditable: this.input instanceof DiffEditorInput && !this.input.original.hasCapability(EditorInputCapabilities.Readonly), lineDecorationsWidth: '2ch' }; @@ -251,7 +251,7 @@ export class TextDiffEditor extends AbstractTextEditor imp this.diffEditorControl?.updateOptions({ readOnly: input.hasCapability(EditorInputCapabilities.Readonly), originalEditable: !input.original.hasCapability(EditorInputCapabilities.Readonly), - enableDropIntoEditor: !input.hasCapability(EditorInputCapabilities.Readonly) + dropIntoEditor: { enabled: !input.hasCapability(EditorInputCapabilities.Readonly) } }); } else { super.updateReadonly(input); diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index c803409ef74..b43dd3baa8d 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -138,7 +138,7 @@ export abstract class AbstractTextEditor extends Abs this.updateEditorControlOptions({ readOnly, - enableDropIntoEditor: !readOnly + dropIntoEditor: { enabled: !readOnly }, }); } @@ -150,7 +150,7 @@ export abstract class AbstractTextEditor extends Abs lineNumbersMinChars: 3, fixedOverflowWidgets: true, readOnly, - enableDropIntoEditor: !readOnly, + dropIntoEditor: { enabled: !readOnly }, renderValidationDecorations: 'on' // render problems even in readonly editors (https://github.com/microsoft/vscode/issues/89057) }; } diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index b042c202d98..c8728506774 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -466,11 +466,6 @@ const registry = Registry.as(ConfigurationExtensions.Con 'default': 'both', 'description': localize('layoutControlType', "Controls whether the layout control in the custom title bar is displayed as a single menu button or with multiple UI toggles."), }, - 'workbench.editor.dropIntoEditor.enabled': { - 'type': 'boolean', - 'default': true, - 'markdownDescription': localize('dropIntoEditor', "Controls whether you can drag and drop a file into a text editor by holding down `shift` (instead of opening the file in an editor)."), - }, 'workbench.experimental.layoutControl.enabled': { 'type': 'boolean', 'tags': ['experimental'], diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts index 870d4b2d719..813a6ef4354 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts @@ -329,7 +329,7 @@ export class StatefulMarkdownCell extends Disposable { width: width, height: editorHeight }, - enableDropIntoEditor: true, + dropIntoEditor: { enabled: true }, // overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 949c8dd25b5..fff16d43316 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -275,7 +275,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende width: 0, height: 0 }, - enableDropIntoEditor: true, + dropIntoEditor: { enabled: true }, }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions }); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index f479781fba7..32a0d626d66 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -1963,7 +1963,7 @@ class SCMInputWidget { scrollbar: { alwaysConsumeMouseWheel: false }, overflowWidgetsDomNode, renderWhitespace: 'none', - enableDropIntoEditor: true, + dropIntoEditor: { enabled: true }, accessibilitySupport }; diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index ba9aa39c643..d0c64ae91ae 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -5430,7 +5430,7 @@ declare module 'vscode' { /** * Provider which handles dropping of resources into a text editor. * - * The user can drop into a text editor by holding down `shift` while dragging. Requires `workbench.editor.dropIntoEditor.enabled` to be on. + * The user can drop into a text editor by holding down `shift` while dragging. Requires `editor.dropIntoEditor.enabled` to be on. */ export interface DocumentDropEditProvider { /** From 19ac36abb68c9a00c3ef546427c3dbd7c9ed80b9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 27 Jul 2022 07:28:56 +0200 Subject: [PATCH 094/179] Electron Sandbox Workspace Setting (fix #156263) (#156404) --- src/vs/workbench/electron-sandbox/desktop.contribution.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 1dd0c84873b..6559a5f52b7 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -242,6 +242,7 @@ import { ModifierKeyEmitter } from 'vs/base/browser/dom'; type: 'boolean', description: localize('experimentalUseSandbox', "Experimental: When enabled, the window will have sandbox mode enabled via Electron API."), default: false, + 'scope': ConfigurationScope.APPLICATION, ignoreSync: true }, } From e210bbfea4a2ccf7dc3334df162084f379a9ac48 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 27 Jul 2022 11:03:47 +0200 Subject: [PATCH 095/179] Git - fix edge case during rebase (#156410) Fix blocking issue while resolving conflicts during rebase --- extensions/git/src/actionButton.ts | 19 ++++++++++++------- extensions/git/src/commands.ts | 2 ++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index 527b5b1476c..ba11df7a2aa 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -95,21 +95,26 @@ export class ActionButtonCommand { return { command: this.getCommitActionButtonPrimaryCommand(), secondaryCommands: this.getCommitActionButtonSecondaryCommands(), - enabled: this.state.repositoryHasChangesToCommit && !this.state.isCommitInProgress && !this.state.isMergeInProgress + enabled: (this.state.repositoryHasChangesToCommit || this.state.isRebaseInProgress) && !this.state.isCommitInProgress && !this.state.isMergeInProgress }; } private getCommitActionButtonPrimaryCommand(): Command { + // Rebase Continue + if (this.state.isRebaseInProgress) { + return { + command: 'git.commit', + title: localize('scm button continue title', "{0} Continue", '$(check)'), + tooltip: this.state.isCommitInProgress ? localize('scm button continuing tooltip', "Continuing Rebase...") : localize('scm button continue tooltip', "Continue Rebase"), + arguments: [this.repository.sourceControl, ''] + }; + } + + // Commit let commandArg = ''; let title = localize('scm button commit title', "{0} Commit", '$(check)'); let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes"); - // Rebase Continue - if (this.state.isRebaseInProgress) { - return { command: 'git.commit', title, tooltip, arguments: [this.repository.sourceControl, commandArg] }; - } - - // Commit const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); const postCommitCommand = config.get('postCommitCommand'); diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index ac763f00c53..66032dc217c 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1558,6 +1558,8 @@ export class CommandCenter { // amend allows changing only the commit message && !opts.amend && !opts.empty + // rebase not in progress + && repository.rebaseCommit === undefined ) { const commitAnyway = localize('commit anyway', "Create Empty Commit"); const answer = await window.showInformationMessage(localize('no changes', "There are no changes to commit."), commitAnyway); From f1458c0b4cbec35a219a237f031c1a1ad1e711c1 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 27 Jul 2022 13:07:56 +0200 Subject: [PATCH 096/179] Adds color contrast and shadow Fixes #156257 Fixes #156329 --- .../stickyScroll/browser/stickyScroll.ts | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 4048a5fc9ec..7d9cbf358ed 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; @@ -16,6 +16,7 @@ import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; +import { RunOnceScheduler } from 'vs/base/common/async'; const enum ScrollDirection { Down = 0, @@ -23,32 +24,34 @@ const enum ScrollDirection { None = 2 } -class StickyScrollController implements IEditorContribution { +class StickyScrollController extends Disposable implements IEditorContribution { static readonly ID = 'store.contrib.stickyScrollController'; private readonly _editor: ICodeEditor; private readonly stickyScrollWidget: StickyScrollWidget; private readonly _languageFeaturesService: ILanguageFeaturesService; - - private readonly _store: DisposableStore = new DisposableStore(); private readonly _sessionStore: DisposableStore = new DisposableStore(); private _ranges: [number, number, number][] = []; + private _rangesVersionId: number = 0; private _cts: CancellationTokenSource | undefined; private _lastScrollPosition: number = -1; + private readonly _updateSoon: RunOnceScheduler; constructor( editor: ICodeEditor, @ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService, ) { + super(); this._editor = editor; this._languageFeaturesService = _languageFeaturesService; this.stickyScrollWidget = new StickyScrollWidget(this._editor); - this._store.add(this._editor.onDidChangeConfiguration(e => { + this._register(this._editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.stickyScroll)) { this.onConfigurationChange(); } })); + this._updateSoon = this._register(new RunOnceScheduler(() => this._update(true), 50)); this.onConfigurationChange(); } @@ -61,19 +64,14 @@ class StickyScrollController implements IEditorContribution { return; } else { this._editor.addOverlayWidget(this.stickyScrollWidget); - this._sessionStore.add(this._editor.onDidChangeModel(() => this.onModelChange())); + this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); - this._sessionStore.add(this._editor.onDidChangeModelContent(() => setTimeout(() => this._update(true), 500))); - this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => setTimeout(() => this._update(true), 500))); + this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule())); + this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); this._update(true); } } - private onModelChange() { - this.stickyScrollWidget.emptyRootNode(); - setTimeout(() => this._update(true), 500); - } - private async _update(updateOutline: boolean = false): Promise { if (updateOutline) { this._cts?.dispose(true); @@ -124,12 +122,13 @@ class StickyScrollController implements IEditorContribution { private async _updateOutlineModel(token: CancellationToken) { if (this._editor.hasModel()) { const model = this._editor.getModel(); + const modelVersionId = model.getVersionId(); const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token); - console.log('outline model is : ', outlineModel); if (token.isCancellationRequested) { return; } this._ranges = []; + this._rangesVersionId = modelVersionId; for (const outline of outlineModel.children.values()) { if (outline instanceof OutlineElement) { const kind: SymbolKind = outline.symbol.kind; @@ -167,6 +166,10 @@ class StickyScrollController implements IEditorContribution { } const lineHeight: number = this._editor.getOption(EditorOption.lineHeight); const model = this._editor.getModel(); + if (this._rangesVersionId !== model.getVersionId()) { + // Old _ranges not updated yet + return; + } const scrollTop = this._editor.getScrollTop(); let scrollDirection: ScrollDirection; if (this._lastScrollPosition < scrollTop) { @@ -193,33 +196,30 @@ class StickyScrollController implements IEditorContribution { bottomOfBeginningLine = start * lineHeight; topOfEndLine = (end - 1) * lineHeight; bottomOfEndLine = end * lineHeight; - if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, (depth - 1) * lineHeight + bottomOfEndLine - bottomOfElementAtDepth)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); - + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } } else { this._ranges.splice(index, 1); } } } - this.stickyScrollWidget.updateRootNode(); } - dispose(): void { - this._store.dispose(); + override dispose(): void { + super.dispose(); this._sessionStore.dispose(); } } @@ -227,8 +227,13 @@ class StickyScrollController implements IEditorContribution { const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { createHTML: value => value }); class StickyScrollCodeLine { + + public readonly effectiveLineHeight: number = 0; + constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, - private readonly _zIndex: number, private readonly _position?: number) { } + private readonly _zIndex: number, private readonly _relativePosition: number) { + this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition; + } getDomNode() { @@ -313,13 +318,14 @@ class StickyScrollCodeLine { root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`; root.style.overflow = 'hidden'; root.style.whiteSpace = 'nowrap'; + root.style.width = '100%'; root.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; root.style.height = this._editor.getOption(EditorOption.lineHeight).toString() + 'px'; // Special case for last line of sticky scroll - if (this._position) { - root.style.position = 'absolute'; - root.style.top = this._position + 'px'; + if (this._relativePosition) { + root.style.position = 'relative'; + root.style.top = this._relativePosition + 'px'; root.style.width = '100%'; } return root; @@ -334,6 +340,7 @@ class StickyScrollWidget implements IOverlayWidget { constructor(public readonly _editor: ICodeEditor) { this.rootDomNode = document.createElement('div'); this.rootDomNode.style.width = '100%'; + this.rootDomNode.style.boxShadow = `var(--vscode-scrollbar-shadow) 0 6px 6px -6px`; // '0px 0px 8px 2px #000000'; } get codeLineCount() { @@ -345,9 +352,12 @@ class StickyScrollWidget implements IOverlayWidget { } updateRootNode() { + let widgetHeight: number = 0; for (const line of this.arrayOfCodeLines) { + widgetHeight += line.effectiveLineHeight; this.rootDomNode.appendChild(line.getDomNode()); } + this.rootDomNode.style.height = widgetHeight.toString() + 'px'; } emptyRootNode() { From d01945923ca286e0ed113f47ab7020f5d1de4723 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:11:07 +0200 Subject: [PATCH 097/179] Git - Fix regression with Commit action button icon (#156417) Fix regression with Commit action button icon --- extensions/git/src/actionButton.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index ba11df7a2aa..a0d97dfadb8 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -111,10 +111,6 @@ export class ActionButtonCommand { } // Commit - let commandArg = ''; - let title = localize('scm button commit title', "{0} Commit", '$(check)'); - let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes"); - const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); const postCommitCommand = config.get('postCommitCommand'); @@ -127,6 +123,10 @@ export class ActionButtonCommand { // Icon const icon = alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined; + let commandArg = ''; + let title = localize('scm button commit title', "{0} Commit", icon ?? '$(check)'); + let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes"); + // Title, tooltip switch (postCommitCommand) { case 'push': { From cb48abb0c0470c6060ba34586aeb7053f9684ee8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 27 Jul 2022 13:12:07 +0200 Subject: [PATCH 098/179] fix errors in tests (#156420) --- src/vs/platform/userDataProfile/common/userDataProfile.ts | 2 +- .../userDataProfile/electron-main/userDataProfile.ts | 5 +++++ .../electron-main/workspacesManagementMainService.ts | 6 ++++-- .../extensionRecommendationsService.test.ts | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 3d0c1ba1b4c..1d7ad908f95 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -155,7 +155,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf readonly _serviceBrand: undefined; - private enabled: boolean = false; + protected enabled: boolean = false; protected readonly defaultProfileShouldIncludeExtensionsResourceAlways: boolean = false; readonly profilesHome: URI; diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index 0ac191f058a..db97f74bd82 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -17,6 +17,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; export const IUserDataProfilesMainService = refineServiceDecorator(IUserDataProfilesService); export interface IUserDataProfilesMainService extends IUserDataProfilesService { + isEnabled(): boolean; unsetWorkspace(workspaceIdentifier: WorkspaceIdentifier): Promise; readonly onWillCreateProfile: Event; readonly onWillRemoveProfile: Event; @@ -34,6 +35,10 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme super(stateMainService, uriIdentityService, environmentService, fileService, logService); } + isEnabled(): boolean { + return this.enabled; + } + protected override saveStoredProfiles(storedProfiles: StoredUserDataProfile[]): void { this.stateMainService.setItem(UserDataProfilesMainService.PROFILES_KEY, storedProfiles); } diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index 2ee6816721e..8e5d39ff29e 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -205,8 +205,10 @@ export class WorkspacesManagementMainService extends Disposable implements IWork // Delete from disk this.doDeleteUntitledWorkspaceSync(workspace); - // unset workspace from profiles - this.userDataProfilesMainService.unsetWorkspace(workspace); + if (this.userDataProfilesMainService.isEnabled()) { + // unset workspace from profiles + this.userDataProfilesMainService.unsetWorkspace(workspace); + } // Event this._onDidDeleteUntitledWorkspace.fire(workspace); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts index 03adbe3a5f0..030f0b5ca87 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts @@ -216,6 +216,7 @@ suite('ExtensionRecommendationsService Test', () => { onDidInstallExtensions: didInstallEvent.event, onUninstallExtension: uninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event, + onDidChangeProfileExtensions: Event.None, async getInstalled() { return []; }, async canInstall() { return true; }, async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, From a4b7d52ba133ad5fff17dc77602d540151a75a78 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 14:18:15 +0200 Subject: [PATCH 099/179] Only adjust changes when bracket pairs are completed. --- .../inlineCompletions/browser/inlineCompletionsModel.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index bb49228f345..02104cfe890 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -724,12 +724,12 @@ export async function provideInlineCompletions( model, languageConfigurationService ); - } - // Modify range depending on if brackets are added or removed - if (insertText.length !== item.insertText.length) { + // Modify range depending on if brackets are added or removed const diff = insertText.length - item.insertText.length; - range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff); + if (diff !== 0) { + range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff); + } } snippetInfo = undefined; From ff3a45d5be9dc9757b24e701d61b390e37fad865 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 27 Jul 2022 14:49:17 +0200 Subject: [PATCH 100/179] Calls onDidChangeModelTokens and updates when the range of update intersects with the line range of the sticky scroll widget --- .../contrib/stickyScroll/browser/stickyScroll.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 7d9cbf358ed..183314bb276 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -17,6 +17,7 @@ import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/vie import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; const enum ScrollDirection { Down = 0, @@ -66,12 +67,24 @@ class StickyScrollController extends Disposable implements IEditorContribution { this._editor.addOverlayWidget(this.stickyScrollWidget); this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); + this._sessionStore.add(this._editor.onDidChangeModelTokens((e) => this._onTokensChange(e))); this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule())); this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); this._update(true); } } + private _onTokensChange(event: IModelTokensChangedEvent) { + const beginningLine = this._editor.getVisibleRanges()[0].getStartPosition().lineNumber - 1; + const endLine = beginningLine + this.stickyScrollWidget.codeLineCount + 1; + const fromLineNumber = event.ranges[0].fromLineNumber; + const toLineNumber = event.ranges[0].toLineNumber; + if (fromLineNumber > endLine || beginningLine > toLineNumber) { + return; + } + this._update(false); + } + private async _update(updateOutline: boolean = false): Promise { if (updateOutline) { this._cts?.dispose(true); From 241c77020385e27ead8398ae02a9aed2ee7fd160 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 06:32:07 -0700 Subject: [PATCH 101/179] Exclude esbuild files from build (#156362) --- extensions/ipynb/.vscodeignore | 2 +- extensions/markdown-language-features/.vscodeignore | 3 ++- extensions/simple-browser/.vscodeignore | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/ipynb/.vscodeignore b/extensions/ipynb/.vscodeignore index 08245c01482..f45314d0c1e 100644 --- a/extensions/ipynb/.vscodeignore +++ b/extensions/ipynb/.vscodeignore @@ -6,4 +6,4 @@ extension.webpack.config.js extension-browser.webpack.config.js yarn.lock .gitignore - +esbuild.js diff --git a/extensions/markdown-language-features/.vscodeignore b/extensions/markdown-language-features/.vscodeignore index 1046b7ec26b..fa12077f015 100644 --- a/extensions/markdown-language-features/.vscodeignore +++ b/extensions/markdown-language-features/.vscodeignore @@ -12,7 +12,8 @@ cgmanifest.json yarn.lock preview-src/** webpack.config.js -esbuild.js +esbuild-notebook.js +esbuild-preview.js .gitignore server/src/** server/extension.webpack.config.js diff --git a/extensions/simple-browser/.vscodeignore b/extensions/simple-browser/.vscodeignore index ec298ce1768..d1006b25b79 100644 --- a/extensions/simple-browser/.vscodeignore +++ b/extensions/simple-browser/.vscodeignore @@ -11,3 +11,4 @@ cgmanifest.json yarn.lock preview-src/** webpack.config.js +esbuild-preview.js From 079c49ed1277fc42d8a49823dc6fbab473223503 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 27 Jul 2022 15:32:53 +0200 Subject: [PATCH 102/179] fix the printed installed extension version (#156422) --- .../common/extensionManagementCLIService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts b/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts index b36b6ea904d..65b2cea1af6 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts @@ -223,8 +223,8 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer output.log(version ? localize('installing with version', "Installing extension '{0}' v{1}...", id, version) : localize('installing', "Installing extension '{0}'...", id)); } - await this.extensionManagementService.installFromGallery(galleryExtension, { ...installOptions, installGivenVersion: !!version }); - output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, galleryExtension.version)); + const local = await this.extensionManagementService.installFromGallery(galleryExtension, { ...installOptions, installGivenVersion: !!version }); + output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, local.manifest.version)); return manifest; } catch (error) { if (isCancellationError(error)) { From 2ad2cd4e718dd3b292cd423921bcccd371f2c4f0 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 27 Jul 2022 15:41:27 +0200 Subject: [PATCH 103/179] Iterating over all the ranges in the onDidChangeModelTokens function --- .../stickyScroll/browser/stickyScroll.ts | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 183314bb276..0da33b17f98 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -75,14 +75,21 @@ class StickyScrollController extends Disposable implements IEditorContribution { } private _onTokensChange(event: IModelTokensChangedEvent) { - const beginningLine = this._editor.getVisibleRanges()[0].getStartPosition().lineNumber - 1; - const endLine = beginningLine + this.stickyScrollWidget.codeLineCount + 1; - const fromLineNumber = event.ranges[0].fromLineNumber; - const toLineNumber = event.ranges[0].toLineNumber; - if (fromLineNumber > endLine || beginningLine > toLineNumber) { - return; + const widgetLineRange = this.stickyScrollWidget.getCurrentLineRange(); + let rerender: boolean = false; + for (const range of event.ranges) { + const fromLineNumber = range.fromLineNumber; + const toLineNumber = range.toLineNumber; + const fromLineWidget = widgetLineRange[0]; + const toLineWidget = widgetLineRange[1]; + if (fromLineNumber <= toLineWidget && toLineNumber >= fromLineWidget) { + rerender = true; + break; + } + } + if (rerender === true) { + this._update(false); } - this._update(false); } private async _update(updateOutline: boolean = false): Promise { @@ -212,16 +219,16 @@ class StickyScrollController extends Disposable implements IEditorContribution { if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); + this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } } else { this._ranges.splice(index, 1); @@ -348,6 +355,7 @@ class StickyScrollCodeLine { class StickyScrollWidget implements IOverlayWidget { private readonly arrayOfCodeLines: StickyScrollCodeLine[] = []; + private readonly linesRange: number[] = []; private readonly rootDomNode: HTMLElement = document.createElement('div'); constructor(public readonly _editor: ICodeEditor) { @@ -360,7 +368,15 @@ class StickyScrollWidget implements IOverlayWidget { return this.arrayOfCodeLines.length; } - pushCodeLine(codeLine: StickyScrollCodeLine) { + getCurrentLineRange(): number[] { + const widgetLineRange = []; + widgetLineRange.push(this.linesRange[0]); + widgetLineRange.push(this.linesRange[this.linesRange.length - 1]); + return widgetLineRange; + } + + pushCodeLine(codeLineNumber: number, codeLine: StickyScrollCodeLine) { + this.linesRange.push(codeLineNumber); this.arrayOfCodeLines.push(codeLine); } From 878271b95f78398ca807a70e5f8ae888977494f6 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Wed, 27 Jul 2022 16:10:41 +0200 Subject: [PATCH 104/179] Updates model only if a sticky line is contained in a range of the model token change event --- .../stickyScroll/browser/stickyScroll.ts | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 0da33b17f98..002828096d5 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -74,20 +74,20 @@ class StickyScrollController extends Disposable implements IEditorContribution { } } - private _onTokensChange(event: IModelTokensChangedEvent) { - const widgetLineRange = this.stickyScrollWidget.getCurrentLineRange(); - let rerender: boolean = false; - for (const range of event.ranges) { - const fromLineNumber = range.fromLineNumber; - const toLineNumber = range.toLineNumber; - const fromLineWidget = widgetLineRange[0]; - const toLineWidget = widgetLineRange[1]; - if (fromLineNumber <= toLineWidget && toLineNumber >= fromLineWidget) { - rerender = true; - break; + private _needsUpdate(event: IModelTokensChangedEvent) { + const stickyLineNumbers = this.stickyScrollWidget.getCurrentLines(); + for (const stickyLineNumber of stickyLineNumbers) { + for (const range of event.ranges) { + if (stickyLineNumber >= range.fromLineNumber && stickyLineNumber <= range.toLineNumber) { + return true; + } } } - if (rerender === true) { + return false; + } + + private _onTokensChange(event: IModelTokensChangedEvent) { + if (this._needsUpdate(event)) { this._update(false); } } @@ -219,16 +219,16 @@ class StickyScrollController extends Disposable implements IEditorContribution { if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(start, new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } } else { this._ranges.splice(index, 1); @@ -255,6 +255,10 @@ class StickyScrollCodeLine { this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition; } + get lineNumber() { + return this._lineNumber; + } + getDomNode() { const root: HTMLElement = document.createElement('div'); @@ -355,7 +359,6 @@ class StickyScrollCodeLine { class StickyScrollWidget implements IOverlayWidget { private readonly arrayOfCodeLines: StickyScrollCodeLine[] = []; - private readonly linesRange: number[] = []; private readonly rootDomNode: HTMLElement = document.createElement('div'); constructor(public readonly _editor: ICodeEditor) { @@ -368,15 +371,15 @@ class StickyScrollWidget implements IOverlayWidget { return this.arrayOfCodeLines.length; } - getCurrentLineRange(): number[] { - const widgetLineRange = []; - widgetLineRange.push(this.linesRange[0]); - widgetLineRange.push(this.linesRange[this.linesRange.length - 1]); + getCurrentLines(): number[] { + const widgetLineRange: number[] = []; + for (const codeLine of this.arrayOfCodeLines) { + widgetLineRange.push(codeLine.lineNumber); + } return widgetLineRange; } - pushCodeLine(codeLineNumber: number, codeLine: StickyScrollCodeLine) { - this.linesRange.push(codeLineNumber); + pushCodeLine(codeLine: StickyScrollCodeLine) { this.arrayOfCodeLines.push(codeLine); } From a3b712e04e4e35ae3bd10676e219ba2b82c95fb7 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 27 Jul 2022 16:55:08 +0200 Subject: [PATCH 105/179] Create a `insiders.vscode.dev` link when I use insiders for sharing (#156436) Fixes #156255 --- extensions/github/src/commands.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/github/src/commands.ts b/extensions/github/src/commands.ts index 40a6927146d..af3484580fd 100644 --- a/extensions/github/src/commands.ts +++ b/extensions/github/src/commands.ts @@ -9,9 +9,13 @@ import { publishRepository } from './publish'; import { DisposableStore } from './util'; import { getPermalink } from './links'; +function getVscodeDevHost(): string { + return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`; +} + async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) { try { - const permalink = getPermalink(gitAPI, useSelection, 'https://vscode.dev/github'); + const permalink = getPermalink(gitAPI, useSelection, getVscodeDevHost()); if (permalink) { return vscode.env.clipboard.writeText(permalink); } @@ -22,7 +26,7 @@ async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) { async function openVscodeDevLink(gitAPI: GitAPI): Promise { try { - const permalink = getPermalink(gitAPI, true, 'https://vscode.dev/github'); + const permalink = getPermalink(gitAPI, true, getVscodeDevHost()); return permalink ? vscode.Uri.parse(permalink) : undefined; } catch (err) { vscode.window.showErrorMessage(err.message); From e572968d23fa5c80d407bac507143a6f60e2c0f8 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 27 Jul 2022 17:10:06 +0200 Subject: [PATCH 106/179] Retry up to 5 times the initial authority resolving and also retry up to 5 times the initial connection (#156444) Fixes #127565: Retry up to 5 times the initial authority resolving and retry up to 5 times the initial connection --- .../remote/common/remoteAgentConnection.ts | 60 ++++++++++++------- .../electronExtensionService.ts | 33 ++++++++-- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts index 2335efbde29..fde30c2d8a6 100644 --- a/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -417,30 +417,48 @@ export interface IAddressProvider { } export async function connectRemoteAgentManagement(options: IConnectionOptions, remoteAuthority: string, clientId: string): Promise { - try { - const reconnectionToken = generateUuid(); - const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null); - const { protocol } = await doConnectRemoteAgentManagement(simpleOptions, CancellationToken.None); - return new ManagementPersistentConnection(options, remoteAuthority, clientId, reconnectionToken, protocol); - } catch (err) { - options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`); - options.logService.error(err); - PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err)); - throw err; - } + return createInitialConnection( + options, + async (simpleOptions) => { + const { protocol } = await doConnectRemoteAgentManagement(simpleOptions, CancellationToken.None); + return new ManagementPersistentConnection(options, remoteAuthority, clientId, simpleOptions.reconnectionToken, protocol); + } + ); } export async function connectRemoteAgentExtensionHost(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise { - try { - const reconnectionToken = generateUuid(); - const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null); - const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments, CancellationToken.None); - return new ExtensionHostPersistentConnection(options, startArguments, reconnectionToken, protocol, debugPort); - } catch (err) { - options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`); - options.logService.error(err); - PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err)); - throw err; + return createInitialConnection( + options, + async (simpleOptions) => { + const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments, CancellationToken.None); + return new ExtensionHostPersistentConnection(options, startArguments, simpleOptions.reconnectionToken, protocol, debugPort); + } + ); +} + +/** + * Will attempt to connect 5 times. If it fails 5 consecutive times, it will give up. + */ +async function createInitialConnection(options: IConnectionOptions, connectionFactory: (simpleOptions: ISimpleConnectionOptions) => Promise): Promise { + const MAX_ATTEMPTS = 5; + + for (let attempt = 1; ; attempt++) { + try { + const reconnectionToken = generateUuid(); + const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null); + const result = await connectionFactory(simpleOptions); + return result; + } catch (err) { + if (attempt < MAX_ATTEMPTS) { + options.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! Will retry... Error:`); + options.logService.error(err); + } else { + options.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! It will be treated as a permanent error. Error:`); + options.logService.error(err); + PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err)); + throw err; + } + } } } diff --git a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts index 34cb13522aa..ee051e3d1f1 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts @@ -413,6 +413,32 @@ export abstract class ElectronExtensionService extends AbstractExtensionService throw new Error(`Cannot get canonical URI because no extension is installed to resolve ${getRemoteAuthorityPrefix(remoteAuthority)}`); } + private async _resolveAuthorityInitial(remoteAuthority: string): Promise { + const MAX_ATTEMPTS = 5; + + for (let attempt = 1; ; attempt++) { + const sw = StopWatch.create(false); + this._logService.info(`[attempt ${attempt}] Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`); + try { + const resolverResult = await this._resolveAuthority(remoteAuthority); + this._logService.info(`[attempt ${attempt}] resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${resolverResult.authority.host}:${resolverResult.authority.port}' after ${sw.elapsed()} ms`); + return resolverResult; + } catch (err) { + this._logService.error(`[attempt ${attempt}] resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned an error after ${sw.elapsed()} ms`, err); + + if (RemoteAuthorityResolverError.isNoResolverFound(err)) { + // There is no point in retrying if there is no resolver found + throw err; + } + + if (attempt >= MAX_ATTEMPTS) { + // Too many failed attempts, give up + throw err; + } + } + } + } + private async _resolveAuthorityAgain(): Promise { const remoteAuthority = this._environmentService.remoteAuthority; if (!remoteAuthority) { @@ -473,14 +499,9 @@ export abstract class ElectronExtensionService extends AbstractExtensionService } let resolverResult: ResolverResult; - - const sw = StopWatch.create(false); - this._logService.info(`Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`); try { - resolverResult = await this._resolveAuthority(remoteAuthority); - this._logService.info(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${resolverResult.authority.host}:${resolverResult.authority.port}' after ${sw.elapsed()} ms`); + resolverResult = await this._resolveAuthorityInitial(remoteAuthority); } catch (err) { - this._logService.error(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned an error after ${sw.elapsed()} ms`, err); if (RemoteAuthorityResolverError.isNoResolverFound(err)) { err.isHandled = await this._handleNoResolverFound(remoteAuthority); } else { From 18fb2dde5d56a464b39f7b93e40dd5e2f38fc74a Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 27 Jul 2022 08:38:12 -0700 Subject: [PATCH 107/179] Set initial debug session pick and edit pick prompt (#156387) Initially selected session/console in the quickpick should match the currently selected one Fixes #156310 --- .../debug/browser/debugSessionPicker.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugSessionPicker.ts b/src/vs/workbench/contrib/debug/browser/debugSessionPicker.ts index 98dfb2e82f5..9e3b5b7efff 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSessionPicker.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSessionPicker.ts @@ -24,11 +24,14 @@ export async function showDebugSessionMenu(accessor: ServicesAccessor, selectAnd const quickPick = quickInputService.createQuickPick(); localDisposableStore.add(quickPick); quickPick.matchOnLabel = quickPick.matchOnDescription = quickPick.matchOnDetail = quickPick.sortByLabel = false; - quickPick.placeholder = nls.localize('moveFocusedView.selectView', 'Search for debug session by name'); - quickPick.items = _getPicks(quickPick.value, selectAndStartID, debugService, viewsService, commandService); + quickPick.placeholder = nls.localize('moveFocusedView.selectView', 'Search debug sessions by name'); + + const pickItems = _getPicksAndActiveItem(quickPick.value, selectAndStartID, debugService, viewsService, commandService); + quickPick.items = pickItems.picks; + quickPick.activeItems = pickItems.activeItems; localDisposableStore.add(quickPick.onDidChangeValue(async () => { - quickPick.items = _getPicks(quickPick.value, selectAndStartID, debugService, viewsService, commandService); + quickPick.items = _getPicksAndActiveItem(quickPick.value, selectAndStartID, debugService, viewsService, commandService).picks; })); localDisposableStore.add(quickPick.onDidAccept(() => { const selectedItem = quickPick.selectedItems[0]; @@ -39,11 +42,13 @@ export async function showDebugSessionMenu(accessor: ServicesAccessor, selectAnd quickPick.show(); } -function _getPicks(filter: string, selectAndStartID: string, debugService: IDebugService, viewsService: IViewsService, commandService: ICommandService): Array { +function _getPicksAndActiveItem(filter: string, selectAndStartID: string, debugService: IDebugService, viewsService: IViewsService, commandService: ICommandService): { picks: Array; activeItems: Array } { const debugConsolePicks: Array = []; const headerSessions: IDebugSession[] = []; + const currSession = debugService.getViewModel().focusedSession; const sessions = debugService.getModel().getSessions(false); + const activeItems: Array = []; sessions.forEach((session) => { if (session.compact && session.parentSession) { @@ -61,6 +66,9 @@ function _getPicks(filter: string, selectAndStartID: string, debugService: IDebu const pick = _createPick(session, filter, debugService, viewsService, commandService); if (pick) { debugConsolePicks.push(pick); + if (session.getId() === currSession?.getId()) { + activeItems.push(pick); + } } } }); @@ -76,7 +84,7 @@ function _getPicks(filter: string, selectAndStartID: string, debugService: IDebu accept: () => commandService.executeCommand(selectAndStartID) }); - return debugConsolePicks; + return { picks: debugConsolePicks, activeItems }; } From 4474dab2fa8dcc12ece25e27b6422d3963e70fd6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 27 Jul 2022 17:40:15 +0200 Subject: [PATCH 108/179] Fix #156369 (#156433) --- src/vs/workbench/browser/web.main.ts | 5 +++++ .../relauncher/browser/relauncher.contribution.ts | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index a307a64ec7e..02ea6a2b6cb 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -295,6 +295,11 @@ export class BrowserMain extends Disposable { ]); userDataProfilesService.setEnablement(!!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/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index 1680881aeb1..2f96395016a 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -102,12 +102,6 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo changed = true; } - // Profiles - if (typeof config.workbench?.experimental?.settingsProfiles?.enabled === 'boolean' && config.workbench.experimental.settingsProfiles.enabled !== this.settingsProfilesEnabled) { - this.settingsProfilesEnabled = config.workbench.experimental.settingsProfiles.enabled; - changed = true; - } - // On linux turning on accessibility support will also pass this flag to the chrome renderer, thus a restart is required if (isLinux && typeof config.editor?.accessibilitySupport === 'string' && config.editor.accessibilitySupport !== this.accessibilitySupport) { this.accessibilitySupport = config.editor.accessibilitySupport; @@ -123,6 +117,12 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo } } + // Profiles + if (typeof config.workbench?.experimental?.settingsProfiles?.enabled === 'boolean' && config.workbench.experimental.settingsProfiles.enabled !== this.settingsProfilesEnabled) { + this.settingsProfilesEnabled = config.workbench.experimental.settingsProfiles.enabled; + changed = true; + } + // Notify only when changed and we are the focused window (avoids notification spam across windows) if (notify && changed) { this.doConfirm( From c6990190a4a670a32d89d1f7cf5f21a9a1af8e2a Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 17:50:38 +0200 Subject: [PATCH 109/179] Fixes https://github.com/microsoft/monaco-editor/issues/3070 (#156449) --- src/vs/editor/common/config/editorOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 943a8b7e018..b50d0d0e112 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -880,7 +880,7 @@ function applyUpdate(value: T | undefined, update: T): ApplyUpdateResult { } if (Array.isArray(value) || Array.isArray(update)) { const arrayEquals = Array.isArray(value) && Array.isArray(update) && arrays.equals(value, update); - return new ApplyUpdateResult(update, arrayEquals); + return new ApplyUpdateResult(update, !arrayEquals); } let didChange = false; for (const key in update) { From 482da8664a8e28e86439bd6eb9a8c743b9997ada Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 17:53:47 +0200 Subject: [PATCH 110/179] Re-Enables bracket pair matching/colorization for monarch (#156450) --- src/vs/editor/common/languages/supports/tokenization.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/editor/common/languages/supports/tokenization.ts b/src/vs/editor/common/languages/supports/tokenization.ts index 7fa14b20a5c..19d637e2e2e 100644 --- a/src/vs/editor/common/languages/supports/tokenization.ts +++ b/src/vs/editor/common/languages/supports/tokenization.ts @@ -230,10 +230,12 @@ export class TokenTheme { if (typeof result === 'undefined') { const rule = this._match(token); const standardToken = toStandardTokenType(token); + result = ( rule.metadata | (standardToken << MetadataConsts.TOKEN_TYPE_OFFSET) ) >>> 0; + result |= MetadataConsts.BALANCED_BRACKETS_MASK; this._cache.set(token, result); } From 2e697a4a5f32c382e1e91d8715db0b19c5f62afd Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 17:58:32 +0200 Subject: [PATCH 111/179] Revert "Re-Enables bracket pair matching/colorization for monarch (#156450)" This reverts commit 482da8664a8e28e86439bd6eb9a8c743b9997ada. --- src/vs/editor/common/languages/supports/tokenization.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/editor/common/languages/supports/tokenization.ts b/src/vs/editor/common/languages/supports/tokenization.ts index 19d637e2e2e..7fa14b20a5c 100644 --- a/src/vs/editor/common/languages/supports/tokenization.ts +++ b/src/vs/editor/common/languages/supports/tokenization.ts @@ -230,12 +230,10 @@ export class TokenTheme { if (typeof result === 'undefined') { const rule = this._match(token); const standardToken = toStandardTokenType(token); - result = ( rule.metadata | (standardToken << MetadataConsts.TOKEN_TYPE_OFFSET) ) >>> 0; - result |= MetadataConsts.BALANCED_BRACKETS_MASK; this._cache.set(token, result); } From 43bce132f90421f58e8b83e6cbdc708bf9feffd3 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 27 Jul 2022 08:58:49 -0700 Subject: [PATCH 112/179] fix shell integration link (#156455) --- .../workbench/contrib/terminal/browser/xterm/decorationAddon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index 964be5b8eb5..54373968a49 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -442,7 +442,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { const labelAbout = localize("terminal.learnShellIntegration", 'Learn About Shell Integration'); actions.push({ class: undefined, tooltip: labelAbout, dispose: () => { }, id: 'terminal.learnShellIntegration', label: labelAbout, enabled: true, - run: () => this._openerService.open('https://code.visualstudio.com/docs/editor/integrated-terminal#_shell-integration') + run: () => this._openerService.open('https://code.visualstudio.com/docs/terminal/shell-integration') }); return actions; } From 3cd638046c65a47a604ad995954b5fdda29ccce6 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 27 Jul 2022 18:05:02 +0200 Subject: [PATCH 113/179] Quick Diff editor gutter decoration hidden by comment gutter icon (diamond) (#156448) * Quick Diff editor gutter decoration hidden by comment gutter icon (diamond) Fixes #156264 * Update doc --- .../browser/commentsEditorContribution.ts | 22 +++++++++++++------ src/vscode-dts/vscode.d.ts | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 41ed64d6d55..5f859a45b0a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -664,6 +664,7 @@ export class CommentController implements IEditorContribution { const pendingCommentText = this._pendingCommentCache[e.owner] && this._pendingCommentCache[e.owner][thread.threadId!]; this.displayCommentThread(e.owner, thread, pendingCommentText); this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread); + this.tryUpdateReservedSpace(); }); this._commentThreadRangeDecorator.update(this.editor, commentInfo); })); @@ -841,15 +842,14 @@ export class CommentController implements IEditorContribution { return; } - private setComments(commentInfos: ICommentInfo[]): void { - if (!this.editor || !this.commentService.isCommentingEnabled) { - return; - } - - this._commentInfos = commentInfos; + private tryUpdateReservedSpace() { let lineDecorationsWidth: number = this.editor.getLayoutInfo().decorationsWidth; + const hasCommentsOrRanges = this._commentInfos.some(info => { + const hasRanges = Boolean(info.commentingRanges && (Array.isArray(info.commentingRanges) ? info.commentingRanges : info.commentingRanges.ranges).length); + return hasRanges || (info.threads.length > 0); + }); - if (this._commentInfos.some(info => Boolean(info.commentingRanges && (Array.isArray(info.commentingRanges) ? info.commentingRanges : info.commentingRanges.ranges).length))) { + if (hasCommentsOrRanges) { this._workspaceHasCommenting.set(true); if (!this._commentingRangeSpaceReserved) { this._commentingRangeSpaceReserved = true; @@ -879,7 +879,15 @@ export class CommentController implements IEditorContribution { }); } } + } + private setComments(commentInfos: ICommentInfo[]): void { + if (!this.editor || !this.commentService.isCommentingEnabled) { + return; + } + + this._commentInfos = commentInfos; + this.tryUpdateReservedSpace(); // create viewzones this.removeCommentWidgetsAndStoreCache(); diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index d0c64ae91ae..4938a81b628 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -15061,7 +15061,7 @@ declare module 'vscode' { /** * Optional commenting range provider. Provide a list {@link Range ranges} which support commenting to any given resource uri. * - * If not provided, users can leave comments in any document opened in the editor. + * If not provided, users cannot leave any comments. */ commentingRangeProvider?: CommentingRangeProvider; From ab836c829b6f73cc64fd78146d5c91e1f60924ac Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 18:16:27 +0200 Subject: [PATCH 114/179] Fixes #153961 by checking if models are disposed. --- .../contrib/mergeEditor/browser/model/diffComputer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts index 06401136b7a..2f769dadd9b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts @@ -24,6 +24,10 @@ export class EditorWorkerServiceDiffComputer implements IDiffComputer { async computeDiff(textModel1: ITextModel, textModel2: ITextModel): Promise { const diffs = await this.editorWorkerService.computeDiff(textModel1.uri, textModel2.uri, false, 1000); + if (textModel1.isDisposed() || textModel2.isDisposed()) { + // In the meantime, models could be disposed -> early return + return { diffs: null }; + } if (!diffs) { return { diffs: null }; } From e617076801f6716fee88418c8414984560bf0dd4 Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Wed, 27 Jul 2022 09:34:22 -0700 Subject: [PATCH 115/179] added `ipynb/esbuild.js` to the media scripts when building extensions --- build/lib/extensions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 89aa014a0d6..ddcb25483fb 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -486,6 +486,7 @@ const esbuildMediaScripts = [ 'markdown-language-features/esbuild-preview.js', 'markdown-math/esbuild.js', 'notebook-renderers/esbuild.js', + 'ipynb/esbuild.js', 'simple-browser/esbuild-preview.js', ]; From 31266e21424152d9146f32ee74bc6a4bc6e91c0c Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 18:34:26 +0200 Subject: [PATCH 116/179] Fixes #156180 by tweaking merge editor result shadow & gutter width (#156463) --- .../browser/view/editors/resultCodeEditorView.ts | 10 ++++++++++ 1 file changed, 10 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 e1557eb0c9a..844c64db291 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 { CompareResult } from 'vs/base/common/arrays'; +import { BugIndicatingError } from 'vs/base/common/errors'; import { autorun, derived } from 'vs/base/common/observable'; import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model'; import { localize } from 'vs/nls'; @@ -11,6 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti 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'; +import { EditorGutter } from 'vs/workbench/contrib/mergeEditor/browser/view/editorGutter'; import { CodeEditorView } from './codeEditorView'; export class ResultCodeEditorView extends CodeEditorView { @@ -106,6 +108,14 @@ export class ResultCodeEditorView extends CodeEditorView { this._register(applyObservableDecorations(this.editor, this.decorations)); + this.htmlElements.gutterDiv.style.width = '5px'; + + this._register( + new EditorGutter(this.editor, this.htmlElements.gutterDiv, { + getIntersectingGutterItems: (range, reader) => [], + createView: (item, target) => { throw new BugIndicatingError(); }, + }) + ); this._register(autorun('update remainingConflicts label', reader => { const model = this.model.read(reader); From ed78fe5771e2406e1a928239ce2f065f521d4f31 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 27 Jul 2022 09:50:29 -0700 Subject: [PATCH 117/179] Hide Open in Local Folder on web --- .../contrib/editSessions/browser/editSessions.contribution.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 0602d52a480..8ff2bb4f106 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -46,6 +46,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { EditSessionsContentProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsContentProvider'; +import { isNative } from 'vs/base/common/platform'; registerSingleton(IEditSessionsLogService, EditSessionsLogService); registerSingleton(IEditSessionsWorkbenchService, EditSessionsWorkbenchService); @@ -529,7 +530,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo private createPickItems(): ContinueEditSessionItem[] { const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when)); - if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined) { + if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) { items.push(new ContinueEditSessionItem( localize('continueEditSessionItem.openInLocalFolder', 'Open In Local Folder'), openLocalFolderCommand.id, From 8e49136c91044737516f2491c4e39f6d48e544d2 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 27 Jul 2022 09:59:58 -0700 Subject: [PATCH 118/179] Account menu to sign out of edit sessions should be specific to edit sessions --- .../editSessions/browser/editSessionsWorkbenchService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts index d8dbac59900..36f51b145a0 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts @@ -355,7 +355,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes constructor() { super({ id: 'workbench.editSessions.actions.resetAuth', - title: localize('reset auth', 'Sign Out'), + title: localize('reset auth.v2', 'Sign Out of Edit Sessions'), category: EDIT_SESSION_SYNC_CATEGORY, precondition: ContextKeyExpr.equals(EDIT_SESSIONS_SIGNED_IN_KEY, true), menu: [{ From 04dd05c0ed64e5d57075788b69e29a713a359516 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 27 Jul 2022 10:03:53 -0700 Subject: [PATCH 119/179] Hide Continue Edit Session when not in a folder --- .../contrib/editSessions/browser/editSessions.contribution.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 8ff2bb4f106..06a991fd12d 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -47,6 +47,7 @@ import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { EditSessionsContentProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsContentProvider'; import { isNative } from 'vs/base/common/platform'; +import { WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys'; registerSingleton(IEditSessionsLogService, EditSessionsLogService); registerSingleton(IEditSessionsWorkbenchService, EditSessionsWorkbenchService); @@ -55,6 +56,7 @@ const continueEditSessionCommand: IAction2Options = { id: '_workbench.experimental.editSessions.actions.continueEditSession', title: { value: localize('continue edit session', "Continue Edit Session..."), original: 'Continue Edit Session...' }, category: EDIT_SESSION_SYNC_CATEGORY, + precondition: WorkspaceFolderCountContext.notEqualsTo('0'), f1: true }; const openLocalFolderCommand: IAction2Options = { From 6fccf5d16e2359f6dde9f772166c6ff2f04872f0 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:09:41 -0700 Subject: [PATCH 120/179] "To" shouldn't be capitalized in the command "Go to Running Cell" (#156471) to should be capitalized in the command "Go to..." Fixes #156297 --- .../contrib/notebook/browser/controller/executeActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index 7b190d89c14..70d6930241c 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -544,8 +544,8 @@ registerAction2(class RevealRunningCellAction extends NotebookAction { constructor() { super({ id: REVEAL_RUNNING_CELL, - title: localize('revealRunningCell', "Go To Running Cell"), - tooltip: localize('revealRunningCell', "Go To Running Cell"), + title: localize('revealRunningCell', "Go to Running Cell"), + tooltip: localize('revealRunningCell', "Go to Running Cell"), shortTitle: localize('revealRunningCellShort', "Go To"), precondition: NOTEBOOK_HAS_RUNNING_CELL, menu: [ From bcba69611f62af31be86c7703caa8f5af003e9ab Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 27 Jul 2022 10:14:14 -0700 Subject: [PATCH 121/179] show all tasks when no tasks are found for given filter and go back is selected (#156458) fix #156286 --- src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 9df0e983136..3a0c564b42b 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2828,6 +2828,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer taskQuickPick.dispose(); return; } else { + if (!!filter) { + // filter yielded no results, so show all + this._runTaskCommand(); + } return; } } else { From 3c0dba1c00ef7c7ae55078a5fc0d5b03319c29b9 Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Wed, 27 Jul 2022 10:30:01 -0700 Subject: [PATCH 122/179] oh. had to run yarn compile from within the /build/ folder --- build/lib/extensions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 168cf8a5d00..808d817b815 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -399,6 +399,7 @@ const esbuildMediaScripts = [ 'markdown-language-features/esbuild-preview.js', 'markdown-math/esbuild.js', 'notebook-renderers/esbuild.js', + 'ipynb/esbuild.js', 'simple-browser/esbuild-preview.js', ]; async function webpackExtensions(taskName, isWatch, webpackConfigLocations) { From ead6a6f34feb4a2e566e39f367831c806f99c385 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 10:52:03 -0700 Subject: [PATCH 123/179] Revert "Temporarily comment out tuple type annotations (#156213)" (#156478) This reverts commit 8f10b21033161e235e9c14767c21efb550319848. --- src/vscode-dts/vscode.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 4938a81b628..d421e29ec0a 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -6019,7 +6019,7 @@ declare module 'vscode' { * To get an instance of a `DiagnosticCollection` use * {@link languages.createDiagnosticCollection createDiagnosticCollection}. */ - export interface DiagnosticCollection extends Iterable<[/*uri:*/ Uri, /*diagnostics:*/ readonly Diagnostic[]]> { + export interface DiagnosticCollection extends Iterable<[uri: Uri, diagnostics: readonly Diagnostic[]]> { /** * The name of this diagnostic collection, for instance `typescript`. Every diagnostic @@ -10159,7 +10159,7 @@ declare module 'vscode' { * data transfer. These additional mime types will only be included in the `handleDrop` when the the drag was initiated from * an element in the same drag and drop controller. */ - export class DataTransfer implements Iterable<[/*mimeType:*/ string, /*item:*/ DataTransferItem]> { + export class DataTransfer implements Iterable<[mimeType: string, item: DataTransferItem]> { /** * Retrieves the data transfer item for a given mime type. * @@ -10189,7 +10189,7 @@ declare module 'vscode' { /** * Get a new iterator with the `[mime, item]` pairs for each element in this data transfer. */ - [Symbol.iterator](): IterableIterator<[/*mimeType:*/ string, /*item:*/ DataTransferItem]>; + [Symbol.iterator](): IterableIterator<[mimeType: string, item: DataTransferItem]>; } /** @@ -10858,7 +10858,7 @@ declare module 'vscode' { /** * A collection of mutations that an extension can apply to a process environment. */ - export interface EnvironmentVariableCollection extends Iterable<[/*variable:*/ string, /*mutator:*/ EnvironmentVariableMutator]> { + export interface EnvironmentVariableCollection extends Iterable<[variable: string, mutator: EnvironmentVariableMutator]> { /** * Whether the collection should be cached for the workspace and applied to the terminal * across window reloads. When true the collection will be active immediately such when the @@ -15737,7 +15737,7 @@ declare module 'vscode' { * Collection of test items, found in {@link TestItem.children} and * {@link TestController.items}. */ - export interface TestItemCollection extends Iterable<[/*id:*/ string, /*testItem:*/ TestItem]> { + export interface TestItemCollection extends Iterable<[id: string, testItem: TestItem]> { /** * Gets the number of items in the collection. */ From be910fd929b84234fa2100ea9b01b5b509c7cbc0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 11:12:45 -0700 Subject: [PATCH 124/179] Use clearer parameter name (#156479) Fixes #156431 --- src/vscode-dts/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index d421e29ec0a..423ac8e7a4d 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -10184,7 +10184,7 @@ declare module 'vscode' { * @param callbackfn Callback for iteration through the data transfer items. * @param thisArg The `this` context used when invoking the handler function. */ - forEach(callbackfn: (value: DataTransferItem, key: string, dataTransfer: DataTransfer) => void, thisArg?: any): void; + forEach(callbackfn: (item: DataTransferItem, mimeType: string, dataTransfer: DataTransfer) => void, thisArg?: any): void; /** * Get a new iterator with the `[mime, item]` pairs for each element in this data transfer. From c8cf34a36f6ee3dcc5f75fdcc175e0346bf12b54 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 27 Jul 2022 20:13:13 +0200 Subject: [PATCH 125/179] Fixes #156037 by not highlighting non-conflicting changes. (#156482) --- .../view/editors/inputCodeEditorView.ts | 44 ++++++++++--------- .../view/editors/resultCodeEditorView.ts | 41 +++++++++-------- 2 files changed, 45 insertions(+), 40 deletions(-) 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 14e739314c3..29e74d70adf 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -65,37 +65,39 @@ export class InputCodeEditorView extends CodeEditorView { position: MinimapPosition.Gutter, color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, }, - overviewRuler: { + overviewRuler: modifiedBaseRange.isConflicting ? { position: OverviewRulerLane.Center, color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, - } + } : undefined } }); - const inputDiffs = modifiedBaseRange.getInputDiffs(this.inputNumber); - for (const diff of inputDiffs) { - const range = diff.outputRange.toInclusiveRange(); - if (range) { - result.push({ - range, - options: { - className: `merge-editor-diff ${inputClassName}`, - description: 'Merge Editor', - isWholeLine: true, - } - }); - } - - if (diff.rangeMappings) { - for (const d of diff.rangeMappings) { + if (modifiedBaseRange.isConflicting) { + const inputDiffs = modifiedBaseRange.getInputDiffs(this.inputNumber); + for (const diff of inputDiffs) { + const range = diff.outputRange.toInclusiveRange(); + if (range) { result.push({ - range: d.outputRange, + range, options: { - className: `merge-editor-diff-word ${inputClassName}`, - description: 'Merge Editor' + className: `merge-editor-diff ${inputClassName}`, + description: 'Merge Editor', + isWholeLine: true, } }); } + + if (diff.rangeMappings) { + for (const d of diff.rangeMappings) { + result.push({ + range: d.outputRange, + options: { + className: `merge-editor-diff-word ${inputClassName}`, + description: 'Merge Editor' + } + }); + } + } } } } 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 844c64db291..04ee5e94264 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts @@ -63,38 +63,41 @@ export class ResultCodeEditorView extends CodeEditorView { position: MinimapPosition.Gutter, color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, }, - overviewRuler: { + overviewRuler: modifiedBaseRange.isConflicting ? { position: OverviewRulerLane.Center, color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, - } + } : undefined } }); } } - for (const diff of m.rights) { - const range = diff.outputRange.toInclusiveRange(); - if (range) { - result.push({ - range, - options: { - className: `merge-editor-diff result`, - description: 'Merge Editor', - isWholeLine: true, - } - }); - } - if (diff.rangeMappings) { - for (const d of diff.rangeMappings) { + if (!modifiedBaseRange || modifiedBaseRange.isConflicting) { + for (const diff of m.rights) { + const range = diff.outputRange.toInclusiveRange(); + if (range) { result.push({ - range: d.outputRange, + range, options: { - className: `merge-editor-diff-word result`, - description: 'Merge Editor' + className: `merge-editor-diff result`, + description: 'Merge Editor', + isWholeLine: true, } }); } + + if (diff.rangeMappings) { + for (const d of diff.rangeMappings) { + result.push({ + range: d.outputRange, + options: { + className: `merge-editor-diff-word result`, + description: 'Merge Editor' + } + }); + } + } } } } From 93340ffab96937ef7b0f49822ccec067cef0c16e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 11:14:27 -0700 Subject: [PATCH 126/179] Log when encountering invalid json in vscode-context (#156485) Fixes #156416 --- .../contrib/webview/browser/pre/index-no-csp.html | 6 ++++-- src/vs/workbench/contrib/webview/browser/pre/index.html | 8 +++++--- 2 files changed, 9 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 8bba582ed17..d0ce103adc8 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 @@ -1070,8 +1070,10 @@ } try { - context = { ...JSON.parse(el.getAttribute('data-vscode-context')), ...context }; - } catch {} + context = { ...JSON.parse(el.dataset.vscodeContext), ...context }; + } catch (e) { + console.error(`Error parsing 'data-vscode-context' as json`, el, e) + } el = el.parentElement; } diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index 52276ac415c..6c00e8b5da2 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-JpX/ganPoxpavjxWCz9DUZgwVZ59o2lwSYTQrziPsdU=' 'self'; frame-src 'self'; style-src 'unsafe-inline';"> Date: Wed, 27 Jul 2022 20:27:47 +0200 Subject: [PATCH 127/179] devcontainer schema: handle deprecated properties (#156425) --- .../devContainer.codespaces.schema.json | 7 ++++++ .../schemas/devContainer.vscode.schema.json | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json index 6186ccd86ac..d224f919109 100644 --- a/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json @@ -177,6 +177,13 @@ } } } + }, + "codespaces": { + "type": "object", + "additionalProperties": true, + "description": "Codespaces-specific configuration.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/codespaces' instead" } } } diff --git a/extensions/configuration-editing/schemas/devContainer.vscode.schema.json b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json index 4eb7a2f62dc..e0f2a8aa68f 100644 --- a/extensions/configuration-editing/schemas/devContainer.vscode.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.vscode.schema.json @@ -28,6 +28,29 @@ } } } + }, + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string", + "pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)((@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|@prerelease)?$", + "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." + }, + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/extensions' instead" + }, + "settings": { + "$ref": "vscode://schemas/settings/machine", + "description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/settings' instead" + }, + "devPort": { + "type": "integer", + "description": "The port VS Code can use to connect to its backend.", + "deprecated": true, + "deprecationMessage": "Use 'customizations/vscode/devPort' instead" } } } From 9b44eda62a9ea9c6b9aa70f14edd7e876200dffa Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Wed, 27 Jul 2022 11:31:44 -0700 Subject: [PATCH 128/179] still allow system context menu in some cases (#156488) fixes #156222 --- .../platform/windows/electron-main/window.ts | 29 +++++++++++++++---- .../parts/titlebar/titlebarPart.ts | 17 +---------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index fce751e1f2d..938c6eb7300 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -305,14 +305,33 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._win.hookWindowMessage(WM_INITMENU, () => { const [x, y] = this._win.getPosition(); const cursorPos = screen.getCursorScreenPoint(); + const cx = cursorPos.x - x; + const cy = cursorPos.y - y; - // This is necessary to make sure the native system context menu does not show up. - this._win.setEnabled(false); - this._win.setEnabled(true); + // In some cases, show the default system context menu + // 1) The mouse position is not within the title bar + // 2) The mouse position is within the title bar, but over the app icon + // We do not know the exact title bar height but we make an estimate based on window height + const shouldTriggerDefaultSystemContextMenu = () => { + // Use the custom context menu when over the title bar, but not over the app icon + // The app icon is estimated to be 30px wide + // The title bar is estimated to be the max of 35px and 15% of the window height + if (cx > 30 && cy >= 0 && cy <= Math.max(this._win.getBounds().height * 0.15, 35)) { + return false; + } - this._onDidTriggerSystemContextMenu.fire({ x: cursorPos.x - x, y: cursorPos.y - y }); + return true; + }; - return 0; // skip native menu + if (!shouldTriggerDefaultSystemContextMenu()) { + // This is necessary to make sure the native system context menu does not show up. + this._win.setEnabled(false); + this._win.setEnabled(true); + + this._onDidTriggerSystemContextMenu.fire({ x: cx, y: cy }); + } + + return 0; }); } diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts index f6f5b60e313..4720f73a32a 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts @@ -207,22 +207,7 @@ export class TitlebarPart extends BrowserTitleBarPart { } const zoomFactor = getZoomFactor(); - const boundingRect = this.rootContainer.getBoundingClientRect(); - const eventPosition = { x, y }; - const relativeCoordinates = { x, y }; - // When comparing the coordinates with the title bar, account for zoom level if not using counter zoom. - if (!this.useCounterZoom) { - relativeCoordinates.x /= zoomFactor; - relativeCoordinates.y /= zoomFactor; - } - - // Don't trigger the menu if the click is not over the title bar - if (relativeCoordinates.x < boundingRect.left || relativeCoordinates.x > boundingRect.right || - relativeCoordinates.y < boundingRect.top || relativeCoordinates.y > boundingRect.bottom) { - return; - } - - this.onContextMenu(new MouseEvent('mouseup', { clientX: eventPosition.x / zoomFactor, clientY: eventPosition.y / zoomFactor }), MenuId.TitleBarContext); + this.onContextMenu(new MouseEvent('mouseup', { clientX: x / zoomFactor, clientY: y / zoomFactor }), MenuId.TitleBarContext); })); } From 9db76b0b15ac879d6bf6de68fb94c8ebf6331bc8 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 27 Jul 2022 11:47:58 -0700 Subject: [PATCH 129/179] Fix #156477. Interactive Window Restore (#156480) * Fix #156477. Interactive Window Restore * Fix #156487. Update description --- .../contrib/interactive/browser/interactive.contribution.ts | 6 +++--- .../contrib/interactive/browser/interactiveCommon.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index c6442b9ce9c..3db0fd13064 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -283,7 +283,7 @@ export class InteractiveEditorSerializer implements IEditorSerializer { } canSerialize(): boolean { - return this.configurationService.getValue(InteractiveWindowSetting.interactiveWindowHotExit); + return this.configurationService.getValue(InteractiveWindowSetting.interactiveWindowRestore); } serialize(input: EditorInput): string { @@ -763,10 +763,10 @@ Registry.as(ConfigurationExtensions.Configuration).regis default: true, markdownDescription: localize('interactiveWindow.alwaysScrollOnNewCell', "Automatically scroll the interactive window to show the output of the last statement executed. If this value is false, the window will only scroll if the last cell was already the one scrolled to.") }, - [InteractiveWindowSetting.interactiveWindowHotExit]: { + [InteractiveWindowSetting.interactiveWindowRestore]: { type: 'boolean', default: false, - markdownDescription: localize('interactiveWindow.hotExit', "Controls whether the interactive window sessions should be restored when the workspace reloads.") + markdownDescription: localize('interactiveWindow.restore', "Controls whether the Interactive Window sessions/history should be restored across window reloads. Whether the state of controllers used in Interactive Windows is persisted across window reloads are controlled by extensions contributing controllers.") } } }); diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveCommon.ts b/src/vs/workbench/contrib/interactive/browser/interactiveCommon.ts index edda5c7f25f..c98f2e6a7e0 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveCommon.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveCommon.ts @@ -9,5 +9,5 @@ export const INTERACTIVE_INPUT_CURSOR_BOUNDARY = new RawContextKey<'none' | 'top export const InteractiveWindowSetting = { interactiveWindowAlwaysScrollOnNewCell: 'interactiveWindow.alwaysScrollOnNewCell', - interactiveWindowHotExit: 'interactiveWindow.hotExit' + interactiveWindowRestore: 'interactiveWindow.restore' }; From 59afa0a8ee51352e7d1a26bfe1d6abf17d22b1dd Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 27 Jul 2022 20:53:49 +0200 Subject: [PATCH 130/179] Create and remove manual folding range use the same shortcut. (#156490) Create and remove manual folding range use the same shortcut. Fixes #156489 --- 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 279ab870eb5..6744508970d 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -1076,7 +1076,7 @@ class FoldRangeFromSelectionAction extends FoldingAction { precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, - primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Period), + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Comma), weight: KeybindingWeight.EditorContrib } }); From 00bb9bdefcfef4cb0ec92399e52dedee4b223ff7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 11:54:24 -0700 Subject: [PATCH 131/179] Always log tsserver exit code, even for kill processes (#156378) We suspect that some exit code info is being dropped since 1.61. Changing this code to always log, even when the user manually restarts the server --- .../src/typescriptServiceClient.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index b09593f6c59..4eec03b0471 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -430,13 +430,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); handle.onExit((data: TypeScriptServerExitEvent) => { - if (this.token !== mytoken) { - // this is coming from an old process - return; - } - const { code, signal } = data; - if (code === null || typeof code === 'undefined') { this.info(`TSServer exited. Signal: ${signal}`); } else { @@ -456,6 +450,11 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.logTelemetry('tsserver.exitWithCode', { code, signal: signal ?? undefined }); } + if (this.token !== mytoken) { + // this is coming from an old process + return; + } + if (handle.tsServerLogFile) { this.info(`TSServer log file: ${handle.tsServerLogFile}`); } From 4aa9759988b08626cf8a34ceaa9519c9af3e8676 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 12:02:01 -0700 Subject: [PATCH 132/179] Fix webview providerId not being restored on reload (#156492) Fixes #156491 --- .../customEditor/browser/customEditorInput.ts | 16 +++++++++----- .../browser/customEditorInputFactory.ts | 4 ++-- .../browser/webviewEditorInput.ts | 22 +++++++++++++++---- .../browser/webviewEditorInputSerializer.ts | 4 ++++ .../browser/webviewWorkbenchService.ts | 12 +++++----- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 116c74df092..a514a41b857 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -24,6 +24,12 @@ import { IWebviewService, IOverlayWebview } from 'vs/workbench/contrib/webview/b import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; +export interface CustomEditorInputInitInfo { + readonly resource: URI; + readonly viewType: string; + readonly id: string; +} + export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { static create( @@ -45,7 +51,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { contentOptions: {}, extension: undefined, }); - const input = instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, { untitledDocumentData: untitledDocumentData, oldResource: options?.oldResource }); + const input = instantiationService.createInstance(CustomEditorInput, { resource, viewType, id }, webview, { untitledDocumentData: untitledDocumentData, oldResource: options?.oldResource }); if (typeof group !== 'undefined') { input.updateGroup(group); } @@ -68,9 +74,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { private _modelRef?: IReference; constructor( - resource: URI, - viewType: string, - id: string, + init: CustomEditorInputInitInfo, webview: IOverlayWebview, options: { startsDirty?: boolean; backupId?: string; untitledDocumentData?: VSBuffer; readonly oldResource?: URI }, @IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService, @@ -81,8 +85,8 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { @IUndoRedoService private readonly undoRedoService: IUndoRedoService, @IFileService private readonly fileService: IFileService ) { - super(id, viewType, '', webview, webviewWorkbenchService); - this._editorResource = resource; + super({ id: init.id, providedId: init.viewType, viewType: init.viewType, name: '' }, webview, webviewWorkbenchService); + this._editorResource = init.resource; this.oldResource = options.oldResource; this._defaultDirtyState = options.startsDirty; this._backupId = options.backupId; diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index 9bc10254662..4277c67ab6a 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -100,7 +100,7 @@ export class CustomEditorInputSerializer extends WebviewEditorInputSerializer { } const webview = reviveWebview(this._webviewService, data); - const customInput = this._instantiationService.createInstance(CustomEditorInput, data.editorResource, data.viewType, data.id, webview, { startsDirty: data.dirty, backupId: data.backupId }); + const customInput = this._instantiationService.createInstance(CustomEditorInput, { resource: data.editorResource, viewType: data.viewType, id: data.id }, webview, { startsDirty: data.dirty, backupId: data.backupId }); if (typeof data.group === 'number') { customInput.updateGroup(data.group); } @@ -196,7 +196,7 @@ export class ComplexCustomWorkingCopyEditorHandler extends Disposable implements extension, }); - const editor = this._instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { backupId: backupData.backupId }); + const editor = this._instantiationService.createInstance(CustomEditorInput, { resource: URI.revive(backupData.editorResource), viewType: backupData.viewType, id }, webview, { backupId: backupData.backupId }); editor.updateGroup(0); return editor; } diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts index 63e3f1cc124..5a4ac6b904c 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts @@ -10,6 +10,13 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IOverlayWebview } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewIconManager, WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; +export interface WebviewInputInitInfo { + readonly id: string; + readonly viewType: string; + readonly providedId: string | undefined; + readonly name: string; +} + export class WebviewInput extends EditorInput { public static typeId = 'workbench.editors.webviewInput'; @@ -41,15 +48,22 @@ export class WebviewInput extends EditorInput { }); } + public readonly id: string; + public readonly viewType: string; + public readonly providedId: string | undefined; + constructor( - public readonly id: string, - public readonly viewType: string, - name: string, + init: WebviewInputInitInfo, webview: IOverlayWebview, private readonly _iconManager: WebviewIconManager, ) { super(); - this._name = name; + + this.id = init.id; + this.viewType = init.viewType; + this.providedId = init.providedId; + + this._name = init.name; this._webview = webview; } diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts index ec4f4c9ef91..483a6b37bc9 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts @@ -23,6 +23,7 @@ export interface SerializedWebview { readonly id: string; readonly origin: string | undefined; readonly viewType: string; + readonly providedId: string | undefined; readonly title: string; readonly options: SerializedWebviewOptions; readonly extensionLocation: UriComponents | undefined; @@ -36,6 +37,7 @@ export interface DeserializedWebview { readonly id: string; readonly origin: string | undefined; readonly viewType: string; + readonly providedId: string | undefined; readonly title: string; readonly webviewOptions: WebviewOptions; readonly contentOptions: WebviewContentOptions; @@ -78,6 +80,7 @@ export class WebviewEditorInputSerializer implements IEditorSerializer { return this._webviewWorkbenchService.reviveWebview({ webviewInitInfo: { id: data.id, + providedId: data.providedId, origin: data.origin, options: data.webviewOptions, contentOptions: data.contentOptions, @@ -107,6 +110,7 @@ export class WebviewEditorInputSerializer implements IEditorSerializer { id: input.id, origin: input.webview.origin, viewType: input.viewType, + providedId: input.providedId, title: input.getName(), options: { ...input.webview.options, ...input.webview.contentOptions }, extensionLocation: input.extension ? input.extension.location : undefined, diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts index 9c8629d7e5f..00232b050e9 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts @@ -20,7 +20,7 @@ import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewEle import { WebviewIconManager, WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; -import { WebviewInput } from './webviewEditorInput'; +import { WebviewInput, WebviewInputInitInfo } from './webviewEditorInput'; export const IWebviewWorkbenchService = createDecorator('webviewEditorService'); @@ -94,13 +94,11 @@ export class LazilyResolvedWebviewEditorInput extends WebviewInput { constructor( - id: string, - viewType: string, - name: string, + init: WebviewInputInitInfo, webview: IOverlayWebview, @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, ) { - super(id, viewType, name, webview, _webviewWorkbenchService.iconManager); + super(init, webview, _webviewWorkbenchService.iconManager); } override dispose() { @@ -244,7 +242,7 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc showOptions: ICreateWebViewShowOptions, ): WebviewInput { const webview = this._webviewService.createWebviewOverlay(webviewInitInfo); - const webviewInput = this._instantiationService.createInstance(WebviewInput, webviewInitInfo.id, viewType, title, webview, this.iconManager); + const webviewInput = this._instantiationService.createInstance(WebviewInput, { id: webviewInitInfo.id, viewType, name: title, providedId: webviewInitInfo.providedId }, webview, this.iconManager); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus, @@ -295,7 +293,7 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc const webview = this._webviewService.createWebviewOverlay(options.webviewInitInfo); webview.state = options.state; - const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, options.webviewInitInfo.id, options.viewType, options.title, webview); + const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, { id: options.webviewInitInfo.id, viewType: options.viewType, providedId: options.webviewInitInfo.providedId, name: options.title }, webview); webviewInput.iconPath = options.iconPath; if (typeof options.group === 'number') { From 7b376e070407a0e73332138ae1c7266e9aedbe4a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 27 Jul 2022 21:02:35 +0200 Subject: [PATCH 133/179] Remove Manual Folding Range doesn't work (#156493) Remove Manual Folding Range doesn't work. Fixes #156277 --- src/vs/editor/contrib/folding/browser/folding.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 6744508970d..fec26e69c77 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -1140,12 +1140,8 @@ class RemoveFoldRangeFromSelectionAction extends FoldingAction { if (selections) { const ranges: ILineRange[] = []; for (const selection of selections) { - let endLineNumber = selection.endLineNumber; - if (selection.endColumn === 1) { - --endLineNumber; - } - const startLineNumber = selection.startLineNumber; - ranges.push(endLineNumber >= selection.startLineNumber ? { startLineNumber, endLineNumber } : { endLineNumber, startLineNumber }); + const { startLineNumber, endLineNumber } = selection; + ranges.push(endLineNumber >= startLineNumber ? { startLineNumber, endLineNumber } : { endLineNumber, startLineNumber }); } foldingModel.removeManualRanges(ranges); foldingController.triggerFoldingModelChanged(); From 06f8d52e37f3ba31764103dd51f7c06a7bee5676 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 12:58:52 -0700 Subject: [PATCH 134/179] Always log on tsserver exits (#156495) This ensures we also log if the TS Server exits with no code but a valid signal. Useful for figuring out how many users are hitting OOM errors --- .../src/typescriptServiceClient.ts | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 4eec03b0471..0c740259823 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -431,24 +431,22 @@ export default class TypeScriptServiceClient extends Disposable implements IType handle.onExit((data: TypeScriptServerExitEvent) => { const { code, signal } = data; - if (code === null || typeof code === 'undefined') { - this.info(`TSServer exited. Signal: ${signal}`); - } else { - // In practice, the exit code is an integer with no ties to any identity, - // so it can be classified as SystemMetaData, rather than CallstackOrException. - this.error(`TSServer exited with code: ${code}. Signal: ${signal}`); - /* __GDPR__ - "tsserver.exitWithCode" : { - "owner": "mjbvz", - "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "${include}": [ - "${TypeScriptCommonProperties}" - ] - } - */ - this.logTelemetry('tsserver.exitWithCode', { code, signal: signal ?? undefined }); - } + this.error(`TSServer exited. Code: ${code}. Signal: ${signal}`); + + // In practice, the exit code is an integer with no ties to any identity, + // so it can be classified as SystemMetaData, rather than CallstackOrException. + /* __GDPR__ + "tsserver.exitWithCode" : { + "owner": "mjbvz", + "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${TypeScriptCommonProperties}" + ] + } + */ + this.logTelemetry('tsserver.exitWithCode', { code: code ?? undefined, signal: signal ?? undefined }); + if (this.token !== mytoken) { // this is coming from an old process From d48349a494df57dca14f2478ceb3055188341d47 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 27 Jul 2022 13:17:22 -0700 Subject: [PATCH 135/179] Default edit sessions to hidden for 1.70 (#156494) --- .../contrib/editSessions/browser/editSessions.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 06a991fd12d..2853ab2d422 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -594,7 +594,7 @@ Registry.as(Extensions.Configuration).registerConfigurat 'workbench.experimental.editSessions.enabled': { 'type': 'boolean', 'tags': ['experimental', 'usesOnlineServices'], - 'default': true, + 'default': false, 'markdownDescription': localize('editSessionsEnabled', "Controls whether to display cloud-enabled actions to store and resume uncommitted changes when switching between web, desktop, or devices."), }, } From 89c30e1b86f941db095d9f52b128287e5039e004 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 27 Jul 2022 23:02:44 +0200 Subject: [PATCH 136/179] manual folding ranges: memento does not store all sources (#156273) use source: fix memento does not store all sources --- .../editor/contrib/folding/browser/folding.ts | 5 +- .../contrib/folding/browser/foldingModel.ts | 24 ++-- .../contrib/folding/browser/foldingRanges.ts | 69 +++++++---- .../test/browser/foldingRanges.test.ts | 108 ++++++++---------- 4 files changed, 109 insertions(+), 97 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index fec26e69c77..c35cdb69a65 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -32,7 +32,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { editorSelectionBackground, iconForeground, registerColor, transparent } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { foldingCollapsedIcon, FoldingDecorationProvider, foldingExpandedIcon, foldingManualCollapsedIcon, foldingManualExpandedIcon } from './foldingDecorations'; -import { FoldingRegion, FoldingRegions, FoldRange, ILineRange } from './foldingRanges'; +import { FoldingRegion, FoldingRegions, FoldRange, FoldSource, ILineRange } from './foldingRanges'; import { SyntaxRangeProvider } from './syntaxRangeProvider'; import { INotificationService } from 'vs/platform/notification/common/notification'; import Severity from 'vs/base/common/severity'; @@ -1097,8 +1097,7 @@ class FoldRangeFromSelectionAction extends FoldingAction { endLineNumber: endLineNumber, type: undefined, isCollapsed: true, - isUserDefined: true, - isRecovered: false + source: FoldSource.userDefined }); editor.setSelection({ startLineNumber: selection.startLineNumber, diff --git a/src/vs/editor/contrib/folding/browser/foldingModel.ts b/src/vs/editor/contrib/folding/browser/foldingModel.ts index f3bc09b1ce3..936e83b605f 100644 --- a/src/vs/editor/contrib/folding/browser/foldingModel.ts +++ b/src/vs/editor/contrib/folding/browser/foldingModel.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; -import { FoldingRegion, FoldingRegions, ILineRange, FoldRange } from './foldingRanges'; +import { FoldingRegion, FoldingRegions, ILineRange, FoldRange, FoldSource } from './foldingRanges'; import { hash } from 'vs/base/common/hash'; export interface IDecorationProvider { @@ -22,7 +22,7 @@ export interface FoldingModelChangeEvent { interface ILineMemento extends ILineRange { checksum?: number; isCollapsed?: boolean; - isUserDefined?: boolean; + source?: FoldSource; } export type CollapseMemento = ILineMemento[]; @@ -64,7 +64,7 @@ export class FoldingModel { const endLineNumber = this._regions.getEndLineNumber(k); const isCollapsed = this._regions.isCollapsed(k); if (endLineNumber <= dirtyRegionEndLine) { - const isManual = this.regions.isUserDefined(k) || this.regions.isRecovered(k); + const isManual = this.regions.getSource(k) !== FoldSource.provider; accessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual)); } if (isCollapsed && endLineNumber > lastHiddenLine) { @@ -104,7 +104,7 @@ export class FoldingModel { }; for (let i = 0; i < this._regions.length; i++) { const foldRange = this._regions.toFoldRange(i); - if (!foldRange.isUserDefined && !foldRange.isRecovered || !intersects(foldRange)) { + if (foldRange.source === FoldSource.provider || !intersects(foldRange)) { newFoldingRanges.push(foldRange); } } @@ -124,7 +124,7 @@ export class FoldingModel { const startLineNumber = newRegions.getStartLineNumber(index); const endLineNumber = newRegions.getEndLineNumber(index); const isCollapsed = newRegions.isCollapsed(index); - const isManual = newRegions.isUserDefined(index) || newRegions.isRecovered(index); + const isManual = newRegions.getSource(index) !== FoldSource.provider; const decorationRange = { startLineNumber: startLineNumber, startColumn: this._textModel.getLineMaxColumn(startLineNumber), @@ -155,9 +155,8 @@ export class FoldingModel { const foldedRanges: FoldRange[] = []; for (let i = 0, limit = this._regions.length; i < limit; i++) { let isCollapsed = this.regions.isCollapsed(i); - const isUserDefined = this.regions.isUserDefined(i); - const isRecovered = this.regions.isRecovered(i); - if (isCollapsed || isUserDefined || isRecovered) { + const source = this.regions.getSource(i); + if (isCollapsed || source !== FoldSource.provider) { const foldRange = this._regions.toFoldRange(i); const decRange = this._textModel.getDecorationRange(this._editorDecorationIds[i]); if (decRange) { @@ -169,8 +168,7 @@ export class FoldingModel { endLineNumber: decRange.endLineNumber, type: foldRange.type, isCollapsed, - isUserDefined, - isRecovered + source }); } } @@ -192,7 +190,7 @@ export class FoldingModel { startLineNumber: range.startLineNumber, endLineNumber: range.endLineNumber, isCollapsed: range.isCollapsed, - isUserDefined: range.isRecovered, + source: range.source, checksum: checksum }); } @@ -214,14 +212,12 @@ export class FoldingModel { } const checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber); if (!range.checksum || checksum === range.checksum) { - const isUserDefined = range.isUserDefined === true; rangesToRestore.push({ startLineNumber: range.startLineNumber, endLineNumber: range.endLineNumber, type: undefined, isCollapsed: range.isCollapsed ?? true, - isUserDefined, - isRecovered: !isUserDefined + source: range.source ?? FoldSource.provider }); } } diff --git a/src/vs/editor/contrib/folding/browser/foldingRanges.ts b/src/vs/editor/contrib/folding/browser/foldingRanges.ts index 2dfb1e50003..8beb820778d 100644 --- a/src/vs/editor/contrib/folding/browser/foldingRanges.ts +++ b/src/vs/editor/contrib/folding/browser/foldingRanges.ts @@ -8,13 +8,18 @@ export interface ILineRange { endLineNumber: number; } +export const enum FoldSource { + provider = 0, + userDefined = 1, + recovered = 2 +} + export interface FoldRange { startLineNumber: number; endLineNumber: number; type: string | undefined; isCollapsed: boolean; - isUserDefined: boolean; - isRecovered: boolean; + source: FoldSource; } export const MAX_FOLDING_REGIONS = 0xFFFF; @@ -123,22 +128,44 @@ export class FoldingRegions { this._collapseStates.set(index, newState); } - public isUserDefined(index: number): boolean { + private isUserDefined(index: number): boolean { return this._userDefinedStates.get(index); } - public setUserDefined(index: number, newState: boolean) { + private setUserDefined(index: number, newState: boolean) { return this._userDefinedStates.set(index, newState); } - public isRecovered(index: number): boolean { + private isRecovered(index: number): boolean { return this._recoveredStates.get(index); } - public setRecovered(index: number, newState: boolean) { + private setRecovered(index: number, newState: boolean) { return this._recoveredStates.set(index, newState); } + public getSource(index: number): FoldSource { + if (this.isUserDefined(index)) { + return FoldSource.userDefined; + } else if (this.isRecovered(index)) { + return FoldSource.recovered; + } + return FoldSource.provider; + } + + public setSource(index: number, source: FoldSource): void { + if (source === FoldSource.userDefined) { + this.setUserDefined(index, true); + this.setRecovered(index, false); + } else if (source === FoldSource.recovered) { + this.setUserDefined(index, false); + this.setRecovered(index, true); + } else { + this.setUserDefined(index, false); + this.setRecovered(index, false); + } + } + public setCollapsedAllOfType(type: string, newState: boolean) { let hasChanged = false; if (this._types) { @@ -203,10 +230,16 @@ export class FoldingRegions { return -1; } + private readonly sourceAbbr = { + [FoldSource.provider]: ' ', + [FoldSource.userDefined]: 'u', + [FoldSource.recovered]: 'r', + }; + public toString() { const res: string[] = []; for (let i = 0; i < this.length; i++) { - res[i] = `[${this.isUserDefined(i) ? '*' : ' '}${this.isRecovered(i) ? 'r' : ' '}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`; + res[i] = `[${this.sourceAbbr[this.getSource(i)]}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`; } return res.join(', '); } @@ -217,8 +250,7 @@ export class FoldingRegions { endLineNumber: this._endIndexes[index] & MAX_LINE_NUMBER, type: this._types ? this._types[index] : undefined, isCollapsed: this.isCollapsed(index), - isUserDefined: this.isUserDefined(index), - isRecovered: this.isRecovered(index) + source: this.getSource(index) }; } @@ -245,12 +277,7 @@ export class FoldingRegions { if (ranges[i].isCollapsed) { regions.setCollapsed(i, true); } - if (ranges[i].isUserDefined) { - regions.setUserDefined(i, true); - } - if (ranges[i].isRecovered) { - regions.setRecovered(i, true); - } + regions.setSource(i, ranges[i].source); } return regions; } @@ -296,23 +323,21 @@ export class FoldingRegions { let useRange: FoldRange | undefined = undefined; if (nextB && (!nextA || nextA.startLineNumber >= nextB.startLineNumber)) { if (nextA && nextA.startLineNumber === nextB.startLineNumber) { - if (nextB.isUserDefined) { + if (nextB.source === FoldSource.userDefined) { // a user defined range (possibly unfolded) useRange = nextB; } else { // a previously folded range or a (possibly unfolded) recovered range useRange = nextA; useRange.isCollapsed = nextB.isCollapsed && nextA.endLineNumber === nextB.endLineNumber; - useRange.isUserDefined = false; - useRange.isRecovered = false; + useRange.source = FoldSource.provider; } nextA = getA(++indexA); // not necessary, just for speed } else { useRange = nextB; - if (nextB.isCollapsed && !nextB.isUserDefined && !nextB.isRecovered) { + if (nextB.isCollapsed && nextB.source === FoldSource.provider) { // a previously collapsed range - useRange.isRecovered = true; - useRange.isUserDefined = false; + useRange.source = FoldSource.recovered; } } nextB = getB(++indexB); @@ -326,7 +351,7 @@ export class FoldingRegions { useRange = nextA; break; // no conflict, use this nextA } - if (prescanB.isUserDefined && prescanB.endLineNumber > nextA!.endLineNumber) { + if (prescanB.source === FoldSource.userDefined && prescanB.endLineNumber > nextA!.endLineNumber) { // we found a user folded range, it wins break; // without setting nextResult, so this nextA gets skipped } diff --git a/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts b/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts index 671277579ee..9f6a381afbd 100644 --- a/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts +++ b/src/vs/editor/contrib/folding/test/browser/foldingRanges.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { FoldingMarkers } from 'vs/editor/common/languages/languageConfiguration'; -import { MAX_FOLDING_REGIONS, FoldRange, FoldingRegions } from 'vs/editor/contrib/folding/browser/foldingRanges'; +import { MAX_FOLDING_REGIONS, FoldRange, FoldingRegions, FoldSource } from 'vs/editor/contrib/folding/browser/foldingRanges'; import { computeRanges } from 'vs/editor/contrib/folding/browser/indentRangeProvider'; import { createTextModel } from 'vs/editor/test/common/testTextModel'; @@ -14,30 +14,22 @@ const markers: FoldingMarkers = { end: /^\s*#endregion\b/ }; -enum State { - none = 0, - userDefined = 1, - recovered = 2 -} - suite('FoldingRanges', () => { - const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, state: State = State.none, type: string | undefined = undefined) => + const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, source: FoldSource = FoldSource.provider, type: string | undefined = undefined) => { startLineNumber: from, endLineNumber: to, type: type, isCollapsed: collapsed || false, - isUserDefined: state === State.userDefined, - isRecovered: state === State.recovered, + source }; const assertEqualRanges = (range1: FoldRange, range2: FoldRange, msg: string) => { assert.strictEqual(range1.startLineNumber, range2.startLineNumber, msg + ' start'); assert.strictEqual(range1.endLineNumber, range2.endLineNumber, msg + ' end'); assert.strictEqual(range1.type, range2.type, msg + ' type'); assert.strictEqual(range1.isCollapsed, range2.isCollapsed, msg + ' collapsed'); - assert.strictEqual(range1.isUserDefined, range2.isUserDefined, msg + ' userDefined'); - assert.strictEqual(range1.isRecovered, range2.isRecovered, msg + ' recovered'); + assert.strictEqual(range1.source, range2.source, msg + ' source'); }; test('test max folding regions', () => { @@ -130,88 +122,88 @@ suite('FoldingRanges', () => { test('sanitizeAndMerge1', () => { const regionSet1: FoldRange[] = [ foldRange(0, 100), // invalid, should be removed - foldRange(1, 100, false, State.none, 'A'), // valid - foldRange(1, 100, false, State.none, 'Z'), // invalid, duplicate start + foldRange(1, 100, false, FoldSource.provider, 'A'), // valid + foldRange(1, 100, false, FoldSource.provider, 'Z'), // invalid, duplicate start foldRange(10, 10, false), // invalid, should be removed - foldRange(20, 80, false, State.none, 'C1'), // valid inside 'B' - foldRange(22, 80, true, State.none, 'D1'), // valid inside 'C1' + foldRange(20, 80, false, FoldSource.provider, 'C1'), // valid inside 'B' + foldRange(22, 80, true, FoldSource.provider, 'D1'), // valid inside 'C1' foldRange(90, 101), // invalid, should be removed ]; const regionSet2: FoldRange[] = [ foldRange(20, 80, true), // should merge with C1 foldRange(18, 80, true), // invalid, out of order - foldRange(21, 81, true, State.none, 'Z'), // invalid, overlapping - foldRange(22, 80, true, State.none, 'D2'), // should merge with D1 + foldRange(21, 81, true, FoldSource.provider, 'Z'), // invalid, overlapping + foldRange(22, 80, true, FoldSource.provider, 'D2'), // should merge with D1 ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 3, 'result length1'); - assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'A'), 'A1'); - assertEqualRanges(result[1], foldRange(20, 80, true, State.none, 'C1'), 'C1'); - assertEqualRanges(result[2], foldRange(22, 80, true, State.none, 'D1'), 'D1'); + assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'A'), 'A1'); + assertEqualRanges(result[1], foldRange(20, 80, true, FoldSource.provider, 'C1'), 'C1'); + assertEqualRanges(result[2], foldRange(22, 80, true, FoldSource.provider, 'D1'), 'D1'); }); test('sanitizeAndMerge2', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, State.none, 'a1'), // valid - foldRange(2, 100, false, State.none, 'a2'), // valid - foldRange(3, 19, false, State.none, 'a3'), // valid - foldRange(20, 71, false, State.none, 'a4'), // overlaps b3 - foldRange(21, 29, false, State.none, 'a5'), // valid - foldRange(81, 91, false, State.none, 'a6'), // overlaps b4 + foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid + foldRange(2, 100, false, FoldSource.provider, 'a2'), // valid + foldRange(3, 19, false, FoldSource.provider, 'a3'), // valid + foldRange(20, 71, false, FoldSource.provider, 'a4'), // overlaps b3 + foldRange(21, 29, false, FoldSource.provider, 'a5'), // valid + foldRange(81, 91, false, FoldSource.provider, 'a6'), // overlaps b4 ]; const regionSet2: FoldRange[] = [ - foldRange(30, 39, true, State.none, 'b1'), // valid, will be recovered - foldRange(40, 49, true, State.userDefined, 'b2'), // valid - foldRange(50, 100, true, State.userDefined, 'b3'), // overlaps a4 - foldRange(80, 90, true, State.userDefined, 'b4'), // overlaps a6 - foldRange(92, 100, true, State.userDefined, 'b5'), // valid + foldRange(30, 39, true, FoldSource.provider, 'b1'), // valid, will be recovered + foldRange(40, 49, true, FoldSource.userDefined, 'b2'), // valid + foldRange(50, 100, true, FoldSource.userDefined, 'b3'), // overlaps a4 + foldRange(80, 90, true, FoldSource.userDefined, 'b4'), // overlaps a6 + foldRange(92, 100, true, FoldSource.userDefined, 'b5'), // valid ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 9, 'result length1'); - assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'P1'); - assertEqualRanges(result[1], foldRange(2, 100, false, State.none, 'a2'), 'P2'); - assertEqualRanges(result[2], foldRange(3, 19, false, State.none, 'a3'), 'P3'); - assertEqualRanges(result[3], foldRange(21, 29, false, State.none, 'a5'), 'P4'); - assertEqualRanges(result[4], foldRange(30, 39, true, State.recovered, 'b1'), 'P5'); - assertEqualRanges(result[5], foldRange(40, 49, true, State.userDefined, 'b2'), 'P6'); - assertEqualRanges(result[6], foldRange(50, 100, true, State.userDefined, 'b3'), 'P7'); - assertEqualRanges(result[7], foldRange(80, 90, true, State.userDefined, 'b4'), 'P8'); - assertEqualRanges(result[8], foldRange(92, 100, true, State.userDefined, 'b5'), 'P9'); + assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'P1'); + assertEqualRanges(result[1], foldRange(2, 100, false, FoldSource.provider, 'a2'), 'P2'); + assertEqualRanges(result[2], foldRange(3, 19, false, FoldSource.provider, 'a3'), 'P3'); + assertEqualRanges(result[3], foldRange(21, 29, false, FoldSource.provider, 'a5'), 'P4'); + assertEqualRanges(result[4], foldRange(30, 39, true, FoldSource.recovered, 'b1'), 'P5'); + assertEqualRanges(result[5], foldRange(40, 49, true, FoldSource.userDefined, 'b2'), 'P6'); + assertEqualRanges(result[6], foldRange(50, 100, true, FoldSource.userDefined, 'b3'), 'P7'); + assertEqualRanges(result[7], foldRange(80, 90, true, FoldSource.userDefined, 'b4'), 'P8'); + assertEqualRanges(result[8], foldRange(92, 100, true, FoldSource.userDefined, 'b5'), 'P9'); }); test('sanitizeAndMerge3', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, State.none, 'a1'), // valid - foldRange(10, 29, false, State.none, 'a2'), // matches manual hidden - foldRange(35, 39, true, State.recovered, 'a3'), // valid + foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid + foldRange(10, 29, false, FoldSource.provider, 'a2'), // matches manual hidden + foldRange(35, 39, true, FoldSource.recovered, 'a3'), // valid ]; const regionSet2: FoldRange[] = [ - foldRange(10, 29, true, State.recovered, 'b1'), // matches a - foldRange(20, 28, true, State.none, 'b2'), // should remain - foldRange(30, 39, true, State.recovered, 'b3'), // should remain + foldRange(10, 29, true, FoldSource.recovered, 'b1'), // matches a + foldRange(20, 28, true, FoldSource.provider, 'b2'), // should remain + foldRange(30, 39, true, FoldSource.recovered, 'b3'), // should remain ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 5, 'result length3'); - assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'R1'); - assertEqualRanges(result[1], foldRange(10, 29, true, State.none, 'a2'), 'R2'); - assertEqualRanges(result[2], foldRange(20, 28, true, State.recovered, 'b2'), 'R3'); - assertEqualRanges(result[3], foldRange(30, 39, true, State.recovered, 'b3'), 'R3'); - assertEqualRanges(result[4], foldRange(35, 39, true, State.recovered, 'a3'), 'R4'); + assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'R1'); + assertEqualRanges(result[1], foldRange(10, 29, true, FoldSource.provider, 'a2'), 'R2'); + assertEqualRanges(result[2], foldRange(20, 28, true, FoldSource.recovered, 'b2'), 'R3'); + assertEqualRanges(result[3], foldRange(30, 39, true, FoldSource.recovered, 'b3'), 'R3'); + assertEqualRanges(result[4], foldRange(35, 39, true, FoldSource.recovered, 'a3'), 'R4'); }); test('sanitizeAndMerge4', () => { const regionSet1: FoldRange[] = [ - foldRange(1, 100, false, State.none, 'a1'), // valid + foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid ]; const regionSet2: FoldRange[] = [ - foldRange(20, 28, true, State.none, 'b1'), // hidden - foldRange(30, 38, true, State.none, 'b2'), // hidden + foldRange(20, 28, true, FoldSource.provider, 'b1'), // hidden + foldRange(30, 38, true, FoldSource.provider, 'b2'), // hidden ]; const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100); assert.strictEqual(result.length, 3, 'result length4'); - assertEqualRanges(result[0], foldRange(1, 100, false, State.none, 'a1'), 'R1'); - assertEqualRanges(result[1], foldRange(20, 28, true, State.recovered, 'b1'), 'R2'); - assertEqualRanges(result[2], foldRange(30, 38, true, State.recovered, 'b2'), 'R3'); + assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'R1'); + assertEqualRanges(result[1], foldRange(20, 28, true, FoldSource.recovered, 'b1'), 'R2'); + assertEqualRanges(result[2], foldRange(30, 38, true, FoldSource.recovered, 'b2'), 'R3'); }); }); From af67e60687f02256ded9f5d5cedb2a4a9a195dfc Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 27 Jul 2022 14:34:48 -0700 Subject: [PATCH 137/179] fix naming on hover --- src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index dc1a9a5031b..d3a15fec005 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -141,7 +141,7 @@ class CodeMenuRenderer implements IListRenderer { const [accept, preview] = this.acceptKeybindings; - data.root.title = localize({ key: 'label', comment: ['placeholders are keybindings, e.g "F2 to Refactor, Shift+F2 to Preview"'] }, "{0} to Rename, {1} to Preview", this.keybindingService.lookupKeybinding(accept)?.getLabel(), this.keybindingService.lookupKeybinding(preview)?.getLabel()); + data.root.title = localize({ key: 'label', comment: ['placeholders are keybindings, e.g "F2 to Refactor, Shift+F2 to Preview"'] }, "{0} to Refactor, {1} to Preview", this.keybindingService.lookupKeybinding(accept)?.getLabel(), this.keybindingService.lookupKeybinding(preview)?.getLabel()); // data.root.title = this.keybindingService.lookupKeybinding(accept)?.getLabel() + ' to Refactor, ' + this.keybindingService.lookupKeybinding(preview)?.getLabel() + ' to Preview'; }; updateLabel(); From d949bdfb48025dd1b0e22b05501860b8f9fb6cb8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 14:52:17 -0700 Subject: [PATCH 138/179] Clarify wording in api (#156500) Clairify wording in api Fixes #156376 --- src/vscode-dts/vscode.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 423ac8e7a4d..36aee9c2f76 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -5430,7 +5430,9 @@ declare module 'vscode' { /** * Provider which handles dropping of resources into a text editor. * - * The user can drop into a text editor by holding down `shift` while dragging. Requires `editor.dropIntoEditor.enabled` to be on. + * This allows users to drag and drop resources (including resources from external apps) into the editor. While dragging + * and dropping files, users can hold down `shift` to drop the file into the editor instead of opening it. + * Requires `editor.dropIntoEditor.enabled` to be on. */ export interface DocumentDropEditProvider { /** From 99cf19c04206beffd16dae6c824509d6d721b75b Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 27 Jul 2022 15:30:01 -0700 Subject: [PATCH 139/179] debug: bump js-debug and visualizer for 1.70 (#156508) --- product.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/product.json b/product.json index a50c00f6cf3..0e0d703e181 100644 --- a/product.json +++ b/product.json @@ -46,7 +46,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.69.0", + "version": "1.70.0", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", @@ -61,7 +61,7 @@ }, { "name": "ms-vscode.vscode-js-profile-table", - "version": "1.0.2", + "version": "1.0.3", "repo": "https://github.com/microsoft/vscode-js-profile-visualizer", "metadata": { "id": "7e52b41b-71ad-457b-ab7e-0620f1fc4feb", From 083728eb874d5b1529db7b7ab29e3cce476c694b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 15:43:40 -0700 Subject: [PATCH 140/179] Fix drop indicator showing up even if you have disabled dropIntoEditor (#156506) This fixes a number of places where we were adding `dropIntoEditor` to the config override, which also overrides the user's configation. Instead we can check if the editor is readonly in `codeEditorWidget` --- src/vs/editor/browser/widget/codeEditorWidget.ts | 9 +++++++-- src/vs/workbench/browser/parts/editor/textDiffEditor.ts | 2 -- src/vs/workbench/browser/parts/editor/textEditor.ts | 7 +------ .../notebook/browser/view/cellParts/markdownCell.ts | 1 - .../notebook/browser/view/renderers/cellRenderer.ts | 1 - 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index bed9912d2d3..32b66fa6680 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -368,10 +368,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._actions[internalAction.id] = internalAction; }); + const isDropIntoEnabled = () => { + return !this._configuration.options.get(EditorOption.readOnly) + && this._configuration.options.get(EditorOption.dropIntoEditor).enabled; + }; + this._register(new dom.DragAndDropObserver(this._domElement, { onDragEnter: () => undefined, onDragOver: e => { - if (!this._configuration.options.get(EditorOption.dropIntoEditor).enabled) { + if (!isDropIntoEnabled()) { return; } @@ -381,7 +386,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } }, onDrop: async e => { - if (!this._configuration.options.get(EditorOption.dropIntoEditor).enabled) { + if (!isDropIntoEnabled()) { return; } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 2dcf135be7c..a638504849a 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -240,7 +240,6 @@ export class TextDiffEditor extends AbstractTextEditor imp return { ...super.getConfigurationOverrides(), readOnly, - dropIntoEditor: { enabled: !readOnly }, originalEditable: this.input instanceof DiffEditorInput && !this.input.original.hasCapability(EditorInputCapabilities.Readonly), lineDecorationsWidth: '2ch' }; @@ -251,7 +250,6 @@ export class TextDiffEditor extends AbstractTextEditor imp this.diffEditorControl?.updateOptions({ readOnly: input.hasCapability(EditorInputCapabilities.Readonly), originalEditable: !input.original.hasCapability(EditorInputCapabilities.Readonly), - dropIntoEditor: { enabled: !input.hasCapability(EditorInputCapabilities.Readonly) } }); } else { super.updateReadonly(input); diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index b43dd3baa8d..da518cdc0e7 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -135,11 +135,7 @@ export abstract class AbstractTextEditor extends Abs protected updateReadonly(input: EditorInput): void { const readOnly = input.hasCapability(EditorInputCapabilities.Readonly); - - this.updateEditorControlOptions({ - readOnly, - dropIntoEditor: { enabled: !readOnly }, - }); + this.updateEditorControlOptions({ readOnly }); } protected getConfigurationOverrides(): ICodeEditorOptions { @@ -150,7 +146,6 @@ export abstract class AbstractTextEditor extends Abs lineNumbersMinChars: 3, fixedOverflowWidgets: true, readOnly, - dropIntoEditor: { enabled: !readOnly }, renderValidationDecorations: 'on' // render problems even in readonly editors (https://github.com/microsoft/vscode/issues/89057) }; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts index 813a6ef4354..ac666a052eb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts @@ -329,7 +329,6 @@ export class StatefulMarkdownCell extends Disposable { width: width, height: editorHeight }, - dropIntoEditor: { enabled: true }, // overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index fff16d43316..8e3ab0b4640 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -275,7 +275,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende width: 0, height: 0 }, - dropIntoEditor: { enabled: true }, }, { contributions: this.notebookEditor.creationOptions.cellEditorContributions }); From 0e5245ccc780813981650fc7bb3fa854e423b5d1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 27 Jul 2022 20:22:19 -0700 Subject: [PATCH 141/179] Revert fix for #150995 (#156516) Fixes #156352 --- src/vs/workbench/browser/parts/editor/editorDropTarget.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 947f4475f3b..9e46f90b593 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -597,11 +597,6 @@ export class EditorDropTarget extends Themable { private registerListeners(): void { this._register(addDisposableListener(this.container, EventType.DRAG_ENTER, e => this.onDragEnter(e))); this._register(addDisposableListener(this.container, EventType.DRAG_LEAVE, () => this.onDragLeave())); - this._register(addDisposableListener(this.container, EventType.DRAG_OVER, e => { - if (!this.overlay) { - this.onDragEnter(e); - } - })); [this.container, window].forEach(node => this._register(addDisposableListener(node as HTMLElement, EventType.DRAG_END, () => this.onDragEnd()))); } From 3e26d50f995f4ed76adedff0138138b29b958625 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 28 Jul 2022 06:11:05 +0200 Subject: [PATCH 142/179] Revert "Warn user when they open a file within the install folder tree (#138815) (#155443)" (#156403) This reverts commit 688c30e498f16686cc0c681e9fdc65d770b2c69a. --- src/vs/workbench/electron-sandbox/window.ts | 57 +-------------------- 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 0d197e84c16..f044363676a 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -65,7 +65,6 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { registerWindowDriver } from 'vs/platform/driver/electron-sandbox/driver'; import { ILabelService } from 'vs/platform/label/common/label'; import { dirname } from 'vs/base/common/resources'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; export class NativeWindow extends Disposable { @@ -116,8 +115,7 @@ export class NativeWindow extends Disposable { @IInstantiationService private readonly instantiationService: IInstantiationService, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService, @IProgressService private readonly progressService: IProgressService, - @ILabelService private readonly labelService: ILabelService, - @IUriIdentityService private readonly uriIdentityService: IUriIdentityService + @ILabelService private readonly labelService: ILabelService ) { super(); @@ -131,18 +129,7 @@ export class NativeWindow extends Disposable { this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); // React to editor input changes - const appRootUri = URI.file(this.environmentService.appRoot); - this._register(this.editorService.onDidActiveEditorChange(() => { - - // Touchbar - this.updateTouchbarMenu(); - - // Potential data loss when editing files - // from within the installation app root - if (this.environmentService.isBuilt) { - this.notifyOnAppRootEditors(appRootUri); - } - })); + this._register(this.editorService.onDidActiveEditorChange(() => this.updateTouchbarMenu())); // prevent opening a real URL inside the window for (const event of [EventType.DRAG_OVER, EventType.DROP]) { @@ -808,46 +795,6 @@ export class NativeWindow extends Disposable { } } - private notifyOnAppRootEditors(appRootUri: URI): void { - const resourceUri = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.BOTH }); - const isResourceAppRootedFn = (uri: URI): boolean => this.uriIdentityService.extUri.isEqualOrParent(uri, appRootUri); - let isResourceAppRooted = false; - if (URI.isUri(resourceUri)) { - if (isResourceAppRootedFn(resourceUri)) { - isResourceAppRooted = true; - } - } else if (resourceUri) { - if (resourceUri.primary && isResourceAppRootedFn(resourceUri.primary)) { - isResourceAppRooted = true; - } else if (resourceUri.secondary && isResourceAppRootedFn(resourceUri.secondary)) { - isResourceAppRooted = true; - } - } - - // It is dangerous to edit files in the installation directory of Code because - // an update will remove all files and replace them with the new version. - // As such, we notify the user whenever an editor opens that is located somewhere - // in the installation directory. - // https://github.com/microsoft/vscode/issues/138815 - - if (isResourceAppRooted) { - this.notificationService.prompt( - Severity.Warning, - localize('notifyOnAppRootEditors', "Files within the installation folder of '{0}' ({1}) will be OVERWRITTEN or DELETED IRREVERSIBLY without warning during a future update.", this.productService.nameShort, this.environmentService.appRoot), - [{ - label: localize('understood', 'Understood'), - run: async () => { - // Nothing to do - } - }], - { - neverShowAgain: { id: 'window.notifyOnAppRootEditors', isSecondary: true }, - sticky: true - } - ); - } - } - private onAddFoldersRequest(request: IAddFoldersRequest): void { // Buffer all pending requests From 916f7677fceedc80bfa3dbc037daddb78e949b01 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 28 Jul 2022 06:23:17 +0200 Subject: [PATCH 143/179] Fix #156321 (#156524) --- .../common/userDataProfileActions.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts index f1d27222b50..62e3de604fe 100644 --- a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts @@ -375,6 +375,7 @@ registerAction2(class ImportProfileAction extends Action2 { const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService); const dialogService = accessor.get(IDialogService); const contextKeyService = accessor.get(IContextKeyService); + const notificationService = accessor.get(INotificationService); const isSettingProfilesEnabled = contextKeyService.contextMatchesRules(PROFILES_ENABLEMENT_CONTEXT); @@ -401,14 +402,18 @@ registerAction2(class ImportProfileAction extends Action2 { quickPick.matchOnLabel = false; quickPick.matchOnDescription = false; disposables.add(quickPick.onDidAccept(async () => { - quickPick.hide(); - const profile = quickPick.selectedItems[0].description ? await this.getProfileFromURL(quickPick.value, requestService) : await this.getProfileFromFileSystem(fileDialogService, fileService); - if (profile) { - if (isSettingProfilesEnabled) { - await userDataProfileImportExportService.importProfile(profile); - } else { - await userDataProfileImportExportService.setProfile(profile); + try { + quickPick.hide(); + const profile = quickPick.selectedItems[0].description ? await this.getProfileFromURL(quickPick.value, requestService) : await this.getProfileFromFileSystem(fileDialogService, fileService); + if (profile) { + if (isSettingProfilesEnabled) { + await userDataProfileImportExportService.importProfile(profile); + } else { + await userDataProfileImportExportService.setProfile(profile); + } } + } catch (error) { + notificationService.error(error); } })); disposables.add(quickPick.onDidHide(() => disposables.dispose())); From 4ee1d1a248dee5a5c5902bedadd094784366c8c6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 28 Jul 2022 06:27:21 +0200 Subject: [PATCH 144/179] Fix #153942 (#156525) --- src/vs/workbench/contrib/extensions/browser/extensionsList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 84eaa15be18..92938e503e5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -119,8 +119,8 @@ export class Renderer implements IPagedRenderer { const actions = [ this.instantiationService.createInstance(ExtensionStatusLabelAction), this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, true), - this.instantiationService.createInstance(UpdateAction), reloadAction, + this.instantiationService.createInstance(UpdateAction), this.instantiationService.createInstance(InstallDropdownAction), this.instantiationService.createInstance(InstallingLabelAction), this.instantiationService.createInstance(SetLanguageAction), From b4d5b4ed69af953901051b1f049851b9dca3563e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 28 Jul 2022 06:46:36 +0200 Subject: [PATCH 145/179] Fix #156468 (#156528) --- src/vs/workbench/contrib/extensions/browser/extensionsList.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 92938e503e5..c5a4a64a417 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 } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +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 { 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'; @@ -124,6 +124,7 @@ export class Renderer implements IPagedRenderer { this.instantiationService.createInstance(InstallDropdownAction), this.instantiationService.createInstance(InstallingLabelAction), this.instantiationService.createInstance(SetLanguageAction), + this.instantiationService.createInstance(ClearLanguageAction), this.instantiationService.createInstance(RemoteInstallAction, false), this.instantiationService.createInstance(LocalInstallAction), this.instantiationService.createInstance(WebInstallAction), From c4d99090fcfb199f12965594952c81fbdd6f5a7f Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:50:51 +0300 Subject: [PATCH 146/179] Engineering - Code OSS pipeline to use generic node modules cache (#156537) Code OSS pipeline to use generic node modules cache --- .../linux/product-build-linux-client.yml | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 1f57307739a..97a9cf31d66 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -93,12 +93,21 @@ steps: node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash displayName: Prepare yarn cache flags - - task: Cache@2 - inputs: - key: "nodeModules | $(Agent.OS) | .build/yarnlockhash" - path: .build/node_modules_cache - cacheHitVar: NODE_MODULES_RESTORED - displayName: Restore node_modules cache + - ${{ 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 + + - ${{ 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 - script: | set -e From 3f502b2bcff29d983b67c5a145ad10524c080d49 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 28 Jul 2022 08:56:31 +0200 Subject: [PATCH 147/179] Fix #154485 (#156533) --- .../browser/userDataProfileManagement.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index 5fab982a11c..7b124b207ca 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -87,7 +87,16 @@ export class UserDataProfileManagementService extends Disposable implements IUse } private async enterProfile(profile: IUserDataProfile, preserveData: boolean, reloadMessage?: string): Promise { - if (this.environmentService.remoteAuthority) { + const isRemoteWindow = !!this.environmentService.remoteAuthority; + + if (!isRemoteWindow) { + this.extensionService.stopExtensionHosts(); + } + + // In a remote window update current profile before reloading so that data is preserved from current profile if asked to preserve + await this.userDataProfileService.updateCurrentProfile(profile, preserveData); + + if (isRemoteWindow) { const result = await this.dialogService.confirm({ type: 'info', message: reloadMessage ?? localize('reload message', "Switching a settings profile requires reloading VS Code."), @@ -96,12 +105,9 @@ export class UserDataProfileManagementService extends Disposable implements IUse if (result.confirmed) { await this.hostService.reload(); } - return; + } else { + await this.extensionService.startExtensionHosts(); } - - this.extensionService.stopExtensionHosts(); - await this.userDataProfileService.updateCurrentProfile(profile, preserveData); - await this.extensionService.startExtensionHosts(); } } From 96c1ab3fa94e48dde6a6182769055d09380ea1c4 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 28 Jul 2022 10:25:22 +0300 Subject: [PATCH 148/179] Engineering - Add missing variable to cache maintenance job (#156540) Add missing variable to cache maintenance job --- build/azure-pipelines/product-build-pr.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index 8f06bcfd09c..1a782b100ee 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -30,6 +30,8 @@ stages: - job: MaintainNodeModulesCache displayName: Maintain node_modules cache pool: vscode-1es-vscode-linux-20.04 + variables: + VSCODE_ARCH: x64 steps: - template: product-build-pr-cache.yml From 09935be99be55eb2374927030d3c4de9d5639d95 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 28 Jul 2022 12:33:14 +0200 Subject: [PATCH 149/179] Rename `getViewLineRenderingData` to `getViewportViewLineRenderingData` --- .../common/viewLayout/viewLinesViewportData.ts | 2 +- src/vs/editor/common/viewModel.ts | 2 +- src/vs/editor/common/viewModel/viewModelImpl.ts | 2 +- .../browser/viewModel/viewModelDecorations.test.ts | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/common/viewLayout/viewLinesViewportData.ts b/src/vs/editor/common/viewLayout/viewLinesViewportData.ts index de06a61132e..8ddcfddb99d 100644 --- a/src/vs/editor/common/viewLayout/viewLinesViewportData.ts +++ b/src/vs/editor/common/viewLayout/viewLinesViewportData.ts @@ -70,7 +70,7 @@ export class ViewportData { } public getViewLineRenderingData(lineNumber: number): ViewLineRenderingData { - return this._model.getViewLineRenderingData(this.visibleRange, lineNumber); + return this._model.getViewportViewLineRenderingData(this.visibleRange, lineNumber); } public getDecorationsInViewport(): ViewModelDecoration[] { diff --git a/src/vs/editor/common/viewModel.ts b/src/vs/editor/common/viewModel.ts index e582f7dc719..06e3164ba07 100644 --- a/src/vs/editor/common/viewModel.ts +++ b/src/vs/editor/common/viewModel.ts @@ -41,7 +41,7 @@ export interface IViewModel extends ICursorSimpleModel { onCompositionEnd(): void; getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[]; - getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData; + getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData; getViewLineData(lineNumber: number): ViewLineData; getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData; getCompletelyVisibleViewRange(): Range; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index c55cf3d02d1..a990823ab9d 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -679,7 +679,7 @@ export class ViewModel extends Disposable implements IViewModel { return this._lines.getInjectedTextAt(viewPosition); } - public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData { + public getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData { const mightContainRTL = this.model.mightContainRTL(); const mightContainNonBasicASCII = this.model.mightContainNonBasicASCII(); const tabSize = this.getTabSize(); diff --git a/src/vs/editor/test/browser/viewModel/viewModelDecorations.test.ts b/src/vs/editor/test/browser/viewModel/viewModelDecorations.test.ts index 3c0942117e1..9a057ea0ec3 100644 --- a/src/vs/editor/test/browser/viewModel/viewModelDecorations.test.ts +++ b/src/vs/editor/test/browser/viewModel/viewModelDecorations.test.ts @@ -97,7 +97,7 @@ suite('ViewModelDecorations', () => { 'dec14', ]); - const inlineDecorations1 = viewModel.getViewLineRenderingData( + const inlineDecorations1 = viewModel.getViewportViewLineRenderingData( new Range(1, viewModel.getLineMinColumn(1), 2, viewModel.getLineMaxColumn(2)), 1 ).inlineDecorations; @@ -118,7 +118,7 @@ suite('ViewModelDecorations', () => { new InlineDecoration(new Range(1, 2, 1, 2), 'b-dec5', InlineDecorationType.Before), ]); - const inlineDecorations2 = viewModel.getViewLineRenderingData( + const inlineDecorations2 = viewModel.getViewportViewLineRenderingData( new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)), 2 ).inlineDecorations; @@ -148,7 +148,7 @@ suite('ViewModelDecorations', () => { new InlineDecoration(new Range(2, 3, 2, 3), 'b-dec12', InlineDecorationType.Before), ]); - const inlineDecorations3 = viewModel.getViewLineRenderingData( + const inlineDecorations3 = viewModel.getViewportViewLineRenderingData( new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)), 3 ).inlineDecorations; @@ -198,13 +198,13 @@ suite('ViewModelDecorations', () => { ).filter(x => Boolean(x.options.beforeContentClassName)); assert.deepStrictEqual(decorations, []); - const inlineDecorations1 = viewModel.getViewLineRenderingData( + const inlineDecorations1 = viewModel.getViewportViewLineRenderingData( new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)), 2 ).inlineDecorations; assert.deepStrictEqual(inlineDecorations1, []); - const inlineDecorations2 = viewModel.getViewLineRenderingData( + const inlineDecorations2 = viewModel.getViewportViewLineRenderingData( new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)), 3 ).inlineDecorations; @@ -229,7 +229,7 @@ suite('ViewModelDecorations', () => { ); }); - const inlineDecorations = viewModel.getViewLineRenderingData( + const inlineDecorations = viewModel.getViewportViewLineRenderingData( new Range(1, 1, 1, 1), 1 ).inlineDecorations; From 8ced34cb3172528b2c97c2993e7a358c501989bc Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 28 Jul 2022 13:38:45 +0300 Subject: [PATCH 150/179] Engineering - unify all Code OSS pipeline jobs (#156552) --- build/azure-pipelines/product-build-pr.yml | 328 ++++++++++----------- 1 file changed, 160 insertions(+), 168 deletions(-) diff --git a/build/azure-pipelines/product-build-pr.yml b/build/azure-pipelines/product-build-pr.yml index 1a782b100ee..8362da25ee5 100644 --- a/build/azure-pipelines/product-build-pr.yml +++ b/build/azure-pipelines/product-build-pr.yml @@ -22,176 +22,168 @@ variables: - name: VSCODE_STEP_ON_IT value: false -stages: - - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: - - stage: MaintainNodeModulesCache - displayName: Maintain node_modules cache - jobs: - - job: MaintainNodeModulesCache - displayName: Maintain node_modules cache - pool: vscode-1es-vscode-linux-20.04 - variables: - VSCODE_ARCH: x64 - steps: - - template: product-build-pr-cache.yml - +jobs: - ${{ if ne(variables['VSCODE_CIBUILD'], true) }}: - - stage: Compile + - job: Compile displayName: Compile & Hygiene - jobs: - - job: Compile - displayName: Compile & Hygiene - pool: vscode-1es-vscode-linux-20.04 - variables: - VSCODE_ARCH: x64 - steps: - - template: product-compile.yml - parameters: - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + steps: + - template: product-compile.yml + parameters: + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - - stage: Test - dependsOn: [] - jobs: - - job: Linuxx64UnitTest - displayName: Linux (Unit Tests) - pool: vscode-1es-vscode-linux-20.04 - # container: vscode-bionic-x64 - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: true - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64IntegrationTest - displayName: Linux (Integration Tests) - pool: vscode-1es-vscode-linux-20.04 - # container: vscode-bionic-x64 - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: true - VSCODE_RUN_SMOKE_TESTS: false - - job: Linuxx64SmokeTest - displayName: Linux (Smoke Tests) - pool: vscode-1es-vscode-linux-20.04 - # container: vscode-bionic-x64 - timeoutInMinutes: 60 - variables: - VSCODE_ARCH: x64 - NPM_ARCH: x64 - DISPLAY: ":10" - steps: - - template: linux/product-build-linux-client.yml - parameters: - VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - VSCODE_RUN_UNIT_TESTS: false - VSCODE_RUN_INTEGRATION_TESTS: false - VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64UnitTest + displayName: Linux (Unit Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: true + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: false - # - job: macOSUnitTest - # displayName: macOS (Unit Tests) - # pool: - # vmImage: macOS-latest - # timeoutInMinutes: 60 - # variables: - # BUILDSECMON_OPT_IN: true - # VSCODE_ARCH: x64 - # steps: - # - template: darwin/product-build-darwin.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: true - # VSCODE_RUN_INTEGRATION_TESTS: false - # VSCODE_RUN_SMOKE_TESTS: false - # - job: macOSIntegrationTest - # displayName: macOS (Integration Tests) - # pool: - # vmImage: macOS-latest - # timeoutInMinutes: 60 - # variables: - # BUILDSECMON_OPT_IN: true - # VSCODE_ARCH: x64 - # steps: - # - template: darwin/product-build-darwin.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: false - # VSCODE_RUN_INTEGRATION_TESTS: true - # VSCODE_RUN_SMOKE_TESTS: false - # - job: macOSSmokeTest - # displayName: macOS (Smoke Tests) - # pool: - # vmImage: macOS-latest - # timeoutInMinutes: 60 - # variables: - # BUILDSECMON_OPT_IN: true - # VSCODE_ARCH: x64 - # steps: - # - template: darwin/product-build-darwin.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: false - # VSCODE_RUN_INTEGRATION_TESTS: false - # VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64IntegrationTest + displayName: Linux (Integration Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: true + VSCODE_RUN_SMOKE_TESTS: false - # - job: WindowsUnitTests - # displayName: Windows (Unit Tests) - # pool: vscode-1es-vscode-windows-2019 - # timeoutInMinutes: 60 - # variables: - # VSCODE_ARCH: x64 - # steps: - # - template: win32/product-build-win32.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: true - # VSCODE_RUN_INTEGRATION_TESTS: false - # VSCODE_RUN_SMOKE_TESTS: false - # - job: WindowsIntegrationTests - # displayName: Windows (Integration Tests) - # pool: vscode-1es-vscode-windows-2019 - # timeoutInMinutes: 60 - # variables: - # VSCODE_ARCH: x64 - # steps: - # - template: win32/product-build-win32.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: false - # VSCODE_RUN_INTEGRATION_TESTS: true - # VSCODE_RUN_SMOKE_TESTS: false - # - job: WindowsSmokeTests - # displayName: Windows (Smoke Tests) - # pool: vscode-1es-vscode-windows-2019 - # timeoutInMinutes: 60 - # variables: - # VSCODE_ARCH: x64 - # steps: - # - template: win32/product-build-win32.yml - # parameters: - # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} - # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} - # VSCODE_RUN_UNIT_TESTS: false - # VSCODE_RUN_INTEGRATION_TESTS: false - # VSCODE_RUN_SMOKE_TESTS: true + - job: Linuxx64SmokeTest + displayName: Linux (Smoke Tests) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + NPM_ARCH: x64 + DISPLAY: ":10" + steps: + - template: linux/product-build-linux-client.yml + parameters: + VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_RUN_UNIT_TESTS: false + VSCODE_RUN_INTEGRATION_TESTS: false + VSCODE_RUN_SMOKE_TESTS: true + + - ${{ if eq(variables['VSCODE_CIBUILD'], true) }}: + - job: Linuxx64MaintainNodeModulesCache + displayName: Linux (Maintain node_modules cache) + pool: vscode-1es-vscode-linux-20.04 + timeoutInMinutes: 30 + variables: + VSCODE_ARCH: x64 + steps: + - template: product-build-pr-cache.yml + + # - job: macOSUnitTest + # displayName: macOS (Unit Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: true + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: false + # - job: macOSIntegrationTest + # displayName: macOS (Integration Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: true + # VSCODE_RUN_SMOKE_TESTS: false + # - job: macOSSmokeTest + # displayName: macOS (Smoke Tests) + # pool: + # vmImage: macOS-latest + # timeoutInMinutes: 60 + # variables: + # BUILDSECMON_OPT_IN: true + # VSCODE_ARCH: x64 + # steps: + # - template: darwin/product-build-darwin.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: true + + # - job: WindowsUnitTests + # displayName: Windows (Unit Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: true + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: false + # - job: WindowsIntegrationTests + # displayName: Windows (Integration Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: true + # VSCODE_RUN_SMOKE_TESTS: false + # - job: WindowsSmokeTests + # displayName: Windows (Smoke Tests) + # pool: vscode-1es-vscode-windows-2019 + # timeoutInMinutes: 60 + # variables: + # VSCODE_ARCH: x64 + # steps: + # - template: win32/product-build-win32.yml + # parameters: + # VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }} + # VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + # VSCODE_RUN_UNIT_TESTS: false + # VSCODE_RUN_INTEGRATION_TESTS: false + # VSCODE_RUN_SMOKE_TESTS: true From 463d53f24eac85c81e57371135c3bc744157d5e1 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 28 Jul 2022 13:12:20 +0200 Subject: [PATCH 151/179] Fixes #156328: Use editor API to determine the top and bottom for line numbers Co-authored-by: aiday-mar --- src/vs/editor/browser/editorBrowser.ts | 7 +++- .../stickyScroll/browser/stickyScroll.ts | 40 +++++-------------- src/vs/monaco.d.ts | 6 ++- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index f91574dc4cb..25c2bbe8445 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -899,10 +899,15 @@ export interface ICodeEditor extends editorCommon.IEditor { getWhitespaces(): IEditorWhitespace[]; /** - * Get the vertical position (top offset) for the line w.r.t. to the first line. + * Get the vertical position (top offset) for the line's top w.r.t. to the first line. */ getTopForLineNumber(lineNumber: number): number; + /** + * Get the vertical position (top offset) for the line's bottom w.r.t. to the first line. + */ + getBottomForLineNumber(lineNumber: number): number; + /** * Get the vertical position (top offset) for the position w.r.t. to the first line. */ diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 002828096d5..d7f669d3caa 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -19,12 +19,6 @@ import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; -const enum ScrollDirection { - Down = 0, - Up = 1, - None = 2 -} - class StickyScrollController extends Disposable implements IEditorContribution { static readonly ID = 'store.contrib.stickyScrollController'; @@ -36,7 +30,6 @@ class StickyScrollController extends Disposable implements IEditorContribution { private _ranges: [number, number, number][] = []; private _rangesVersionId: number = 0; private _cts: CancellationTokenSource | undefined; - private _lastScrollPosition: number = -1; private readonly _updateSoon: RunOnceScheduler; constructor( @@ -191,42 +184,27 @@ class StickyScrollController extends Disposable implements IEditorContribution { return; } const scrollTop = this._editor.getScrollTop(); - let scrollDirection: ScrollDirection; - if (this._lastScrollPosition < scrollTop) { - scrollDirection = ScrollDirection.Down; - } else { - scrollDirection = ScrollDirection.Up; - } - this._lastScrollPosition = scrollTop; - const scrollToBottomOfWidget = this._editor.getScrollTop() + this.stickyScrollWidget.codeLineCount * lineHeight; this.stickyScrollWidget.emptyRootNode(); const beginningLinesConsidered: Set = new Set(); - let topOfElementAtDepth: number; - let bottomOfElementAtDepth: number; - let bottomOfBeginningLine: number; - let topOfEndLine: number; - let bottomOfEndLine: number; for (const [index, arr] of this._ranges.entries()) { const [start, end, depth] = arr; if (end - start > 0 && model.getLineContent(start) !== '') { - topOfElementAtDepth = this._editor.getScrollTop() + (depth - 1) * lineHeight; - bottomOfElementAtDepth = this._editor.getScrollTop() + depth * lineHeight; - bottomOfBeginningLine = start * lineHeight; - topOfEndLine = (end - 1) * lineHeight; - bottomOfEndLine = end * lineHeight; + const topOfElementAtDepth = (depth - 1) * lineHeight; + const bottomOfElementAtDepth = depth * lineHeight; + + const bottomOfBeginningLine = this._editor.getBottomForLineNumber(start) - scrollTop; + const topOfEndLine = this._editor.getTopForLineNumber(end) - scrollTop; + const bottomOfEndLine = this._editor.getBottomForLineNumber(end) - scrollTop; + if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } - else if (scrollDirection === ScrollDirection.Down && bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { - beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); - } else if (scrollDirection === ScrollDirection.Up && scrollToBottomOfWidget > bottomOfBeginningLine - 1 && scrollToBottomOfWidget < bottomOfEndLine || - scrollDirection === ScrollDirection.Up && bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < topOfEndLine - 1) { + else if (bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); } @@ -262,7 +240,7 @@ class StickyScrollCodeLine { getDomNode() { const root: HTMLElement = document.createElement('div'); - const lineRenderingData = this._editor._getViewModel().getViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); + const lineRenderingData = this._editor._getViewModel().getViewportViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); let actualInlineDecorations: LineDecoration[]; try { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index db39c17f9c6..91b72dd4d11 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5372,9 +5372,13 @@ declare namespace monaco.editor { */ getVisibleRanges(): Range[]; /** - * Get the vertical position (top offset) for the line w.r.t. to the first line. + * Get the vertical position (top offset) for the line's top w.r.t. to the first line. */ getTopForLineNumber(lineNumber: number): number; + /** + * Get the vertical position (top offset) for the line's bottom w.r.t. to the first line. + */ + getBottomForLineNumber(lineNumber: number): number; /** * Get the vertical position (top offset) for the position w.r.t. to the first line. */ From 469465b703e1594d62c65379b4189da0985a07a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 12:28:43 +0100 Subject: [PATCH 152/179] fix issue with multiple tree filters related to #156127 --- src/vs/base/browser/ui/tree/abstractTree.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 7a75aa8070a..9f0b7aef2fc 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -593,11 +593,11 @@ class FindFilter implements ITreeFilter, IDi } filter(element: T, parentVisibility: TreeVisibility): TreeFilterResult { + let visibility = TreeVisibility.Visible; + if (this._filter) { const result = this._filter.filter(element, parentVisibility); - let visibility: TreeVisibility; - if (typeof result === 'boolean') { visibility = result ? TreeVisibility.Visible : TreeVisibility.Hidden; } else if (isFilterResult(result)) { @@ -615,7 +615,7 @@ class FindFilter implements ITreeFilter, IDi if (!this._pattern) { this._matchCount++; - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } const label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element); @@ -624,22 +624,22 @@ class FindFilter implements ITreeFilter, IDi for (const l of labels) { const labelStr = l && l.toString(); if (typeof labelStr === 'undefined') { - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } const score = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true }); if (score) { this._matchCount++; return labels.length === 1 ? - { data: score, visibility: true } : - { data: { label: labelStr, score: score }, visibility: true }; + { data: score, visibility } : + { data: { label: labelStr, score: score }, visibility }; } } if (this.tree.findMode === TreeFindMode.Filter) { return TreeVisibility.Recurse; } else { - return { data: FuzzyScore.Default, visibility: true }; + return { data: FuzzyScore.Default, visibility }; } } From baa2e394fb9b6bdde2ad40e60cd7ec382d5077e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 12:37:10 +0100 Subject: [PATCH 153/179] disable find widget for testing view --- src/vs/base/browser/ui/tree/abstractTree.ts | 3 ++- .../workbench/contrib/testing/browser/testingExplorerView.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 9f0b7aef2fc..8b99d57080c 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1022,6 +1022,7 @@ export interface IAbstractTreeOptions extends IAbstractTr readonly filter?: ITreeFilter; readonly dnd?: ITreeDragAndDrop; readonly additionalScrollHeight?: number; + readonly findWidgetEnabled?: boolean; } function dfs(node: ITreeNode, fn: (node: ITreeNode) => void): void { @@ -1436,7 +1437,7 @@ export abstract class AbstractTree implements IDisposable onKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables); } - if (_options.keyboardNavigationLabelProvider && _options.contextViewProvider) { + if ((_options.findWidgetEnabled ?? true) && _options.keyboardNavigationLabelProvider && _options.contextViewProvider) { this.findController = new FindController(this, this.model, this.view, filter!, _options.contextViewProvider); this.focusNavigationFilter = node => this.findController!.shouldAllowFocus(node); this.onDidChangeFindOpenState = this.findController.onDidChangeOpenState; diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 2281441286a..a326f747bc5 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -491,6 +491,7 @@ export class TestingExplorerViewModel extends Disposable { keyboardNavigationLabelProvider: instantiationService.createInstance(TreeKeyboardNavigationLabelProvider), accessibilityProvider: instantiationService.createInstance(ListAccessibilityProvider), filter: this.filter, + findWidgetEnabled: false }) as WorkbenchObjectTree; this._register(this.tree.onDidChangeCollapseState(evt => { From 95fd5bf198bc9f0083421ce5a53c05ca0294a7fd Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 28 Jul 2022 15:10:19 +0200 Subject: [PATCH 154/179] Make sure to use view line numbers when fetching data from the view model (#156569) Fixes #156413: Make sure to use view line numbers when fetching data from the view model Co-authored-by: aiday-mar Co-authored-by: aiday-mar --- src/vs/editor/common/viewModel.ts | 1 + .../common/viewModel/viewModelDecorations.ts | 14 +++++++++----- src/vs/editor/common/viewModel/viewModelImpl.ts | 15 ++++++++++++--- .../contrib/stickyScroll/browser/stickyScroll.ts | 15 +++++++++------ 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/common/viewModel.ts b/src/vs/editor/common/viewModel.ts index 06e3164ba07..d4b67391d99 100644 --- a/src/vs/editor/common/viewModel.ts +++ b/src/vs/editor/common/viewModel.ts @@ -42,6 +42,7 @@ export interface IViewModel extends ICursorSimpleModel { getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[]; getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData; + getViewLineRenderingData(lineNumber: number): ViewLineRenderingData; getViewLineData(lineNumber: number): ViewLineData; getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData; getCompletelyVisibleViewRange(): Range; diff --git a/src/vs/editor/common/viewModel/viewModelDecorations.ts b/src/vs/editor/common/viewModel/viewModelDecorations.ts index 909d9f19bc3..25edc82d950 100644 --- a/src/vs/editor/common/viewModel/viewModelDecorations.ts +++ b/src/vs/editor/common/viewModel/viewModelDecorations.ts @@ -100,17 +100,21 @@ export class ViewModelDecorations implements IDisposable { let cacheIsValid = (this._cachedModelDecorationsResolver !== null); cacheIsValid = cacheIsValid && (viewRange.equalsRange(this._cachedModelDecorationsResolverViewRange)); if (!cacheIsValid) { - this._cachedModelDecorationsResolver = this._getDecorationsViewportData(viewRange); + this._cachedModelDecorationsResolver = this._getDecorationsInRange(viewRange); this._cachedModelDecorationsResolverViewRange = viewRange; } return this._cachedModelDecorationsResolver!; } - private _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData { - const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, filterValidationDecorations(this.configuration.options)); + public getInlineDecorationsOnLine(lineNumber: number): InlineDecoration[] { + const range = new Range(lineNumber, this._linesCollection.getViewLineMinColumn(lineNumber), lineNumber, this._linesCollection.getViewLineMaxColumn(lineNumber)); + return this._getDecorationsInRange(range).inlineDecorations[0]; + } - const startLineNumber = viewportRange.startLineNumber; - const endLineNumber = viewportRange.endLineNumber; + private _getDecorationsInRange(viewRange: Range): IDecorationsViewportData { + const modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, filterValidationDecorations(this.configuration.options)); + const startLineNumber = viewRange.startLineNumber; + const endLineNumber = viewRange.endLineNumber; const decorationsInViewport: ViewModelDecoration[] = []; let decorationsInViewportLen = 0; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index a990823ab9d..160d63c8b33 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -34,7 +34,7 @@ import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout'; import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker'; import { ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText } from 'vs/editor/common/modelLineProjectionData'; import { ViewEventHandler } from 'vs/editor/common/viewEventHandler'; -import { ICoordinatesConverter, IViewModel, IWhitespaceChangeAccessor, MinimapLinesRenderingData, OverviewRulerDecorationsGroup, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel'; +import { ICoordinatesConverter, InlineDecoration, IViewModel, IWhitespaceChangeAccessor, MinimapLinesRenderingData, OverviewRulerDecorationsGroup, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel'; import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations'; import { FocusChangedEvent, ModelContentChangedEvent, ModelDecorationsChangedEvent, ModelLanguageChangedEvent, ModelLanguageConfigurationChangedEvent, ModelOptionsChangedEvent, ModelTokensChangedEvent, OutgoingViewModelEvent, ReadOnlyEditAttemptEvent, ScrollChangedEvent, ViewModelEventDispatcher, ViewModelEventsCollector, ViewZonesChangedEvent } from 'vs/editor/common/viewModelEventDispatcher'; import { IViewModelLines, ViewModelLinesFromModelAsIs, ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines'; @@ -680,12 +680,21 @@ export class ViewModel extends Disposable implements IViewModel { } public getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData { + const allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations; + const inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber]; + return this._getViewLineRenderingData(lineNumber, inlineDecorations); + } + + public getViewLineRenderingData(lineNumber: number): ViewLineRenderingData { + const inlineDecorations = this._decorations.getInlineDecorationsOnLine(lineNumber); + return this._getViewLineRenderingData(lineNumber, inlineDecorations); + } + + private _getViewLineRenderingData(lineNumber: number, inlineDecorations: InlineDecoration[]): ViewLineRenderingData { const mightContainRTL = this.model.mightContainRTL(); const mightContainNonBasicASCII = this.model.mightContainNonBasicASCII(); const tabSize = this.getTabSize(); const lineData = this._lines.getViewLineData(lineNumber); - const allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations; - let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber]; if (lineData.inlineDecorations) { inlineDecorations = [ diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index d7f669d3caa..899d3db5fc6 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -18,6 +18,7 @@ import { SymbolKind } from 'vs/editor/common/languages'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; +import { Position } from 'vs/editor/common/core/position'; class StickyScrollController extends Disposable implements IEditorContribution { @@ -201,12 +202,12 @@ class StickyScrollController extends Disposable implements IEditorContribution { if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } else if (bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(model.getLineContent(start), start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, this._editor, 0, 0)); } } else { this._ranges.splice(index, 1); @@ -228,7 +229,7 @@ class StickyScrollCodeLine { public readonly effectiveLineHeight: number = 0; - constructor(private readonly _line: string, private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, + constructor(private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, private readonly _zIndex: number, private readonly _relativePosition: number) { this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition; } @@ -240,16 +241,18 @@ class StickyScrollCodeLine { getDomNode() { const root: HTMLElement = document.createElement('div'); - const lineRenderingData = this._editor._getViewModel().getViewportViewLineRenderingData(this._editor.getVisibleRangesPlusViewportAboveBelow()[0], this._lineNumber); + const viewModel = this._editor._getViewModel(); + const viewLineNumber = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(this._lineNumber, 1)).lineNumber; + const lineRenderingData = viewModel.getViewLineRenderingData(viewLineNumber); let actualInlineDecorations: LineDecoration[]; try { - actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, this._lineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); + actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, viewLineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn); } catch (err) { actualInlineDecorations = []; } - const renderLineInput: RenderLineInput = new RenderLineInput(true, true, this._line, lineRenderingData.continuesWithWrappedLine, + const renderLineInput: RenderLineInput = new RenderLineInput(true, true, lineRenderingData.content, lineRenderingData.continuesWithWrappedLine, lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize, lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null); From e65cf31952eb7d7a925b12da13726ea832c56b34 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Thu, 28 Jul 2022 15:23:14 +0200 Subject: [PATCH 155/179] Fix view model event and expose a way to get hidden areas (#156571) * Fix emitting of wrong event in view model * Add `IViewModel.getHiddenAreas` --- src/vs/editor/common/viewModel.ts | 2 ++ src/vs/editor/common/viewModel/viewModelImpl.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/viewModel.ts b/src/vs/editor/common/viewModel.ts index d4b67391d99..55f613af360 100644 --- a/src/vs/editor/common/viewModel.ts +++ b/src/vs/editor/common/viewModel.ts @@ -48,6 +48,8 @@ export interface IViewModel extends ICursorSimpleModel { getCompletelyVisibleViewRange(): Range; getCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range; + getHiddenAreas(): Range[]; + getLineCount(): number; getLineContent(lineNumber: number): string; getLineLength(lineNumber: number): number; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 160d63c8b33..a241643468e 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -36,7 +36,7 @@ import { ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText } from 'v import { ViewEventHandler } from 'vs/editor/common/viewEventHandler'; import { ICoordinatesConverter, InlineDecoration, IViewModel, IWhitespaceChangeAccessor, MinimapLinesRenderingData, OverviewRulerDecorationsGroup, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel'; import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations'; -import { FocusChangedEvent, ModelContentChangedEvent, ModelDecorationsChangedEvent, ModelLanguageChangedEvent, ModelLanguageConfigurationChangedEvent, ModelOptionsChangedEvent, ModelTokensChangedEvent, OutgoingViewModelEvent, ReadOnlyEditAttemptEvent, ScrollChangedEvent, ViewModelEventDispatcher, ViewModelEventsCollector, ViewZonesChangedEvent } from 'vs/editor/common/viewModelEventDispatcher'; +import { FocusChangedEvent, HiddenAreasChangedEvent, ModelContentChangedEvent, ModelDecorationsChangedEvent, ModelLanguageChangedEvent, ModelLanguageConfigurationChangedEvent, ModelOptionsChangedEvent, ModelTokensChangedEvent, OutgoingViewModelEvent, ReadOnlyEditAttemptEvent, ScrollChangedEvent, ViewModelEventDispatcher, ViewModelEventsCollector, ViewZonesChangedEvent } from 'vs/editor/common/viewModelEventDispatcher'; import { IViewModelLines, ViewModelLinesFromModelAsIs, ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -485,7 +485,7 @@ export class ViewModel extends Disposable implements IViewModel { this._updateConfigurationViewLineCount.schedule(); if (lineMappingChanged) { - this._eventDispatcher.emitOutgoingEvent(new ViewZonesChangedEvent()); + this._eventDispatcher.emitOutgoingEvent(new HiddenAreasChangedEvent()); } } @@ -508,6 +508,10 @@ export class ViewModel extends Disposable implements IViewModel { return this._toModelVisibleRanges(visibleViewRange); } + public getHiddenAreas(): Range[] { + return this._lines.getHiddenAreas(); + } + private _toModelVisibleRanges(visibleViewRange: Range): Range[] { const visibleRange = this.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange); const hiddenAreas = this._lines.getHiddenAreas(); From 1fdade8d07d9c8b0aca3923fc7bb52df4c104264 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 28 Jul 2022 15:26:16 +0200 Subject: [PATCH 156/179] TreeView reveal fails to scroll to item when focusing and a different selection exists (#156572) Fixes #152803 --- src/vs/workbench/browser/parts/views/treeView.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 4f8aa7d5b3a..3c9b24faefd 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -496,12 +496,12 @@ abstract class AbstractTreeView extends Disposable implements ITreeView { protected abstract activate(): void; - focus(reveal: boolean = true): void { + focus(reveal: boolean = true, revealItem?: ITreeItem): void { if (this.tree && this.root.children && this.root.children.length > 0) { // Make sure the current selected element is revealed - const selectedElement = this.tree.getSelection()[0]; - if (selectedElement && reveal) { - this.tree.reveal(selectedElement, 0.5); + const element = revealItem ?? this.tree.getSelection()[0]; + if (element && reveal) { + this.tree.reveal(element, 0.5); } // Pass Focus to Viewer @@ -784,7 +784,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView { setFocus(item: ITreeItem): void { if (this.tree) { - this.focus(); + this.focus(true, item); this.tree.setFocus([item]); } } From cb7a75ea2d379ed103314ecd5887edddf4f08efb Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 28 Jul 2022 15:32:17 +0200 Subject: [PATCH 157/179] Consider using regular folding icons for manual or preserved folding ranges. Fixes #156279 (#156573) --- src/vs/editor/contrib/folding/browser/folding.css | 3 --- src/vs/editor/contrib/folding/browser/foldingDecorations.ts | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/folding/browser/folding.css b/src/vs/editor/contrib/folding/browser/folding.css index 232384ce3d5..4f70d1097fe 100644 --- a/src/vs/editor/contrib/folding/browser/folding.css +++ b/src/vs/editor/contrib/folding/browser/folding.css @@ -32,6 +32,3 @@ cursor: pointer; } -.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-expanded::before { - transform: rotate(90deg); -} diff --git a/src/vs/editor/contrib/folding/browser/foldingDecorations.ts b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts index 9ad6cb77605..413d0ae9a74 100644 --- a/src/vs/editor/contrib/folding/browser/foldingDecorations.ts +++ b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts @@ -14,8 +14,8 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; export const foldingExpandedIcon = registerIcon('folding-expanded', Codicon.chevronDown, localize('foldingExpandedIcon', 'Icon for expanded ranges in the editor glyph margin.')); export const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.chevronRight, localize('foldingCollapsedIcon', 'Icon for collapsed ranges in the editor glyph margin.')); -export const foldingManualCollapsedIcon = registerIcon('folding-manual-collapsed', Codicon.ellipsis, localize('foldingManualCollapedIcon', 'Icon for manually collapsed ranges in the editor glyph margin.')); -export const foldingManualExpandedIcon = registerIcon('folding-manual-expanded', Codicon.ellipsis, localize('foldingManualExpandedIcon', 'Icon for manually expanded ranges in the editor glyph margin.')); +export const foldingManualCollapsedIcon = registerIcon('folding-manual-collapsed', foldingCollapsedIcon, localize('foldingManualCollapedIcon', 'Icon for manually collapsed ranges in the editor glyph margin.')); +export const foldingManualExpandedIcon = registerIcon('folding-manual-expanded', foldingExpandedIcon, localize('foldingManualExpandedIcon', 'Icon for manually expanded ranges in the editor glyph margin.')); export class FoldingDecorationProvider implements IDecorationProvider { From 589aba9097a564d85719a4c955a06e377aa96365 Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Thu, 28 Jul 2022 16:09:08 +0200 Subject: [PATCH 158/179] Filtering the ranges with the hidden ranges from folding. Fixes #156268. --- .../editor/contrib/stickyScroll/browser/stickyScroll.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 899d3db5fc6..637f7e4ab73 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -19,6 +19,7 @@ import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; class StickyScrollController extends Disposable implements IEditorContribution { @@ -61,6 +62,7 @@ class StickyScrollController extends Disposable implements IEditorContribution { this._editor.addOverlayWidget(this.stickyScrollWidget); this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true))); this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false))); + this._sessionStore.add(this._editor.onDidChangeHiddenAreas(() => this._update(true))); this._sessionStore.add(this._editor.onDidChangeModelTokens((e) => this._onTokensChange(e))); this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule())); this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true))); @@ -92,6 +94,12 @@ class StickyScrollController extends Disposable implements IEditorContribution { this._cts = new CancellationTokenSource(); await this._updateOutlineModel(this._cts.token); } + const hiddenRanges: Range[] | undefined = this._editor._getViewModel()?.getHiddenAreas(); + if (hiddenRanges) { + for (const hiddenRange of hiddenRanges) { + this._ranges = this._ranges.filter(range => { return !(range[0] >= hiddenRange.startLineNumber && range[1] <= hiddenRange.endLineNumber + 1); }); + } + } this._renderStickyScroll(); } From 3bf342b7c4d0cf504c78fe2731259b41af17c90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 16:19:32 +0200 Subject: [PATCH 159/179] Adjust tree find widget padding (#156577) fixes #156244 --- src/vs/base/browser/ui/tree/media/tree.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index f6dceb39e95..7f740a6ee1a 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -87,6 +87,7 @@ align-items: center; justify-content: center; cursor: grab; + margin-right: 2px; } .monaco-tree-type-filter-grab.grabbing { @@ -98,12 +99,16 @@ } .monaco-tree-type-filter-input .monaco-inputbox { - height: 26px; + height: 23px; } .monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .input, .monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .mirror { - padding: 2px; + padding: 2px 4px; +} + +.monaco-tree-type-filter-input .monaco-findInput > .controls { + top: 2px; } .monaco-tree-type-filter-actionbar { From fad1b7c7c2ca0097b4007027cfcc9b485d78b590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 16:33:50 +0200 Subject: [PATCH 160/179] Fine tune tree find widget layout (#156579) fixes #156247 --- src/vs/base/browser/ui/tree/abstractTree.ts | 2 +- src/vs/base/browser/ui/tree/media/tree.css | 3 ++- 2 files 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 7a75aa8070a..618efe8b08c 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -799,7 +799,7 @@ class FindWidget extends Disposable { layout(width: number = this.width): void { this.width = width; - this.right = Math.min(Math.max(20, this.right), Math.max(20, width - 170)); + this.right = clamp(this.right, 0, Math.max(0, width - 212)); this.elements.root.style.right = `${this.right}px`; } diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index 7f740a6ee1a..1a2c0492ea7 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -74,8 +74,9 @@ display: flex; padding: 3px; transition: top 0.3s; - width: 160px; + max-width: 200px; z-index: 100; + margin: 0 6px; } .monaco-tree-type-filter.disabled { From f4d4971d75fe4ee2ee9b096f565141b9e61a2747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 16:37:06 +0200 Subject: [PATCH 161/179] Existing trees should react to changes to `workbench.list.defaultFindMode` (#156581) fixes #156249 --- src/vs/base/browser/ui/tree/abstractTree.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 618efe8b08c..ca481ab1f31 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -876,7 +876,8 @@ class FindController implements IDisposable { return; } - this.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this._mode, this.styles); + this.mode = this.tree.options.defaultFindMode ?? TreeFindMode.Highlight; + this.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this.mode, this.styles); this.enabledDisposables.add(this.widget); this.widget.onDidChangeValue(this.onDidChangeValue, this, this.enabledDisposables); From 5d16a27d452dbbd1f6fc77ea2330a4f1139b06cc Mon Sep 17 00:00:00 2001 From: aiday-mar Date: Thu, 28 Jul 2022 17:10:33 +0200 Subject: [PATCH 162/179] Rendering the sticky line when one pixel into the line. Fixes #156566. --- .../contrib/stickyScroll/browser/stickyScroll.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index 637f7e4ab73..c42d96dff27 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -210,12 +210,12 @@ class StickyScrollController extends Disposable implements IEditorContribution { if (!beginningLinesConsidered.has(start)) { if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth)); break; } - else if (bottomOfElementAtDepth > bottomOfBeginningLine - 1 && bottomOfElementAtDepth < bottomOfEndLine - 1) { + else if (bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < bottomOfEndLine - 1) { beginningLinesConsidered.add(start); - this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, this._editor, 0, 0)); + this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, 0, 0)); } } else { this._ranges.splice(index, 1); @@ -237,7 +237,7 @@ class StickyScrollCodeLine { public readonly effectiveLineHeight: number = 0; - constructor(private readonly _lineNumber: number, private readonly _editor: IActiveCodeEditor, + constructor(private readonly _lineNumber: number, private readonly _depth: number, private readonly _editor: IActiveCodeEditor, private readonly _zIndex: number, private readonly _relativePosition: number) { this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition; } @@ -302,8 +302,9 @@ class StickyScrollCodeLine { root.onclick = e => { e.stopPropagation(); e.preventDefault(); - this._editor.revealLine(this._lineNumber); + this._editor.revealPosition({ lineNumber: this._lineNumber - this._depth + 1, column: 1 }); }; + root.onmouseover = e => { innerLineNumberHTML.style.background = `var(--vscode-editorStickyScrollHover-background)`; lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`; @@ -353,7 +354,7 @@ class StickyScrollWidget implements IOverlayWidget { constructor(public readonly _editor: ICodeEditor) { this.rootDomNode = document.createElement('div'); this.rootDomNode.style.width = '100%'; - this.rootDomNode.style.boxShadow = `var(--vscode-scrollbar-shadow) 0 6px 6px -6px`; // '0px 0px 8px 2px #000000'; + this.rootDomNode.style.boxShadow = `var(--vscode-scrollbar-shadow) 0 6px 6px -6px`; } get codeLineCount() { From 9c4a29cc58ce0e8f6eeb8a555a40e5d73435ea88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 17:27:00 +0200 Subject: [PATCH 163/179] Make sure tree find widget can be moved using the keyboard (#156583) fixes #156251 --- src/vs/base/browser/dom.ts | 6 +++-- src/vs/base/browser/ui/tree/abstractTree.ts | 26 +++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 4019ea90b61..06d13c90d93 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1869,9 +1869,11 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & Partia typeof cssValue === 'number' ? cssValue + 'px' : '' + cssValue ); } - continue; + } else if (key === 'tabIndex') { + el.tabIndex = value; + } else { + el.setAttribute(camelCaseToHyphenCase(key), value.toString()); } - el.setAttribute(camelCaseToHyphenCase(key), value.toString()); } result['root'] = el; diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 45c7e9e98db..1032f3e48a9 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -685,7 +685,7 @@ export enum TreeFindMode { class FindWidget extends Disposable { private readonly elements = h('.monaco-tree-type-filter', [ - h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab'), + h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab', { tabIndex: 0 }), h('.monaco-tree-type-filter-input@findInput'), h('.monaco-tree-type-filter-actionbar@actionbar'), ]); @@ -699,7 +699,7 @@ class FindWidget extends Disposable { private readonly findInput: FindInput; private readonly actionbar: ActionBar; private width = 0; - private right = 4; + private right = 0; readonly _onDidDisable = new Emitter(); readonly onDidDisable = this._onDidDisable.event; @@ -772,6 +772,28 @@ class FindWidget extends Disposable { })); })); + const onGrabKeyDown = this._register(Event.chain(this._register(new DomEmitter(this.elements.grab, 'keydown')).event)) + .map(e => new StandardKeyboardEvent(e)) + .event; + + this._register(onGrabKeyDown((e): any => { + let right: number | undefined; + + if (e.keyCode === KeyCode.LeftArrow) { + right = Number.POSITIVE_INFINITY; + } else if (e.keyCode === KeyCode.RightArrow) { + right = 0; + } else if (e.keyCode === KeyCode.Space) { + right = this.right === 0 ? Number.POSITIVE_INFINITY : 0; + } + + if (right !== undefined) { + e.preventDefault(); + e.stopPropagation(); + this.right = right; + this.layout(); + } + })); this.onDidChangeValue = this.findInput.onDidChange; this.style(options ?? {}); From e45b7a5a426802fb475b3a0856b80b313f2c9411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 28 Jul 2022 17:27:25 +0200 Subject: [PATCH 164/179] Tree keyboard navigation should not steal keybindings (#156575) fixes #155571 --- src/vs/platform/list/browser/listService.ts | 28 +++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 9716ea6dc75..2bd9c44b14d 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -189,7 +189,6 @@ class MultipleSelectionController extends Disposable implements IMultipleSele function toWorkbenchListOptions( accessor: ServicesAccessor, - container: HTMLElement, options: IListOptions, ): [IListOptions, IDisposable] { const configurationService = accessor.get(IConfigurationService); @@ -203,7 +202,7 @@ function toWorkbenchListOptions( mouseWheelScrollSensitivity: configurationService.getValue(mouseWheelScrollSensitivityKey), fastScrollSensitivity: configurationService.getValue(fastScrollSensitivityKey), multipleSelectionController: options.multipleSelectionController ?? disposables.add(new MultipleSelectionController(configurationService)), - keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService), + keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(keybindingService), }; return [result, disposables]; @@ -244,7 +243,7 @@ export class WorkbenchList extends List { @IInstantiationService instantiationService: IInstantiationService ) { const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); - const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options); + const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options); super(user, container, delegate, renderers, { @@ -384,7 +383,7 @@ export class WorkbenchPagedList extends PagedList { @IInstantiationService instantiationService: IInstantiationService ) { const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); - const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options); + const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options); super(user, container, delegate, renderers, { keyboardSupport: false, @@ -517,7 +516,7 @@ export class WorkbenchTable extends Table { @IInstantiationService instantiationService: IInstantiationService ) { const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); - const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options); + const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options); super(user, container, delegate, columns, renderers, { @@ -812,7 +811,7 @@ class TreeResourceNavigator extends ResourceNavigator { } } -function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingService: IKeybindingService): IKeyboardNavigationEventFilter { +function createKeyboardNavigationEventFilter(keybindingService: IKeybindingService): IKeyboardNavigationEventFilter { let inChord = false; return event => { @@ -825,7 +824,7 @@ function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingS return false; } - const result = keybindingService.softDispatch(event, container); + const result = keybindingService.softDispatch(event, event.target); if (result?.enterChord) { inChord = true; @@ -862,7 +861,7 @@ export class WorkbenchObjectTree, TFilterData = void> @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService ) { - const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any); + const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any); super(user, container, delegate, renderers, treeOptions); this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService); @@ -903,7 +902,7 @@ export class WorkbenchCompressibleObjectTree, TFilter @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService ) { - const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any); + const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any); super(user, container, delegate, renderers, treeOptions); this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService); @@ -950,7 +949,7 @@ export class WorkbenchDataTree extends DataTree extends Async @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService ) { - const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any); + const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any); super(user, container, delegate, renderers, dataSource, treeOptions); this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService); @@ -1042,7 +1041,7 @@ export class WorkbenchCompressibleAsyncDataTree e @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService ) { - const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any); + const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any); super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions); this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService); @@ -1077,11 +1076,9 @@ function getDefaultTreeFindMode(configurationService: IConfigurationService) { function workbenchTreeDataPreamble | IAsyncDataTreeOptions>( accessor: ServicesAccessor, - container: HTMLElement, options: TOptions, ): { options: TOptions; getTypeNavigationMode: () => TypeNavigationMode | undefined; disposable: IDisposable } { const configurationService = accessor.get(IConfigurationService); - const keybindingService = accessor.get(IKeybindingService); const contextViewService = accessor.get(IContextViewService); const contextKeyService = accessor.get(IContextKeyService); const instantiationService = accessor.get(IInstantiationService); @@ -1107,7 +1104,7 @@ function workbenchTreeDataPreamble(treeExpandMode) === 'doubleClick'), From 4017fd126ffb62def37c3bb380eb1a1866884ebe Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 28 Jul 2022 10:26:18 -0700 Subject: [PATCH 165/179] Show quick pick when redirect fails to complete redirect to be more robust (#156515) * show quick pick when redirect fails to complete redirect to be more robust * matt feedback --- .../microsoft-authentication/src/AADHelper.ts | 63 +++++++++++++------ .../microsoft-authentication/src/utils.ts | 33 ++++++++++ 2 files changed, 78 insertions(+), 18 deletions(-) diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index bb22142e584..4c3b9f2a38e 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -11,7 +11,7 @@ import * as nls from 'vscode-nls'; import { v4 as uuid } from 'uuid'; import fetch, { Response } from 'node-fetch'; import Logger from './logger'; -import { toBase64UrlEncoding } from './utils'; +import { isSupportedEnvironment, toBase64UrlEncoding } from './utils'; import { sha256 } from './env/node/sha256'; import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecretStorage'; import { LoopbackAuthServer } from './authServer'; @@ -319,13 +319,7 @@ export class AzureActiveDirectoryService { }, 5000); } - const token = await this.exchangeCodeForToken(codeToExchange, codeVerifier, scopeData); - if (token.expiresIn) { - this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); - } - await this.setToken(token, scopeData); - Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`); - const session = await this.convertToSession(token); + const session = await this.exchangeCodeForSession(codeToExchange, codeVerifier, scopeData); return session; } @@ -355,9 +349,11 @@ export class AzureActiveDirectoryService { const uri = vscode.Uri.parse(`${signInUrl}?${oauthStartQuery.toString()}`); vscode.env.openExternal(uri); + let inputBox: vscode.InputBox | undefined; const timeoutPromise = new Promise((_: (value: vscode.AuthenticationSession) => void, reject) => { const wait = setTimeout(() => { clearTimeout(wait); + inputBox?.dispose(); reject('Login timed out.'); }, 1000 * 60 * 5); }); @@ -369,7 +365,12 @@ export class AzureActiveDirectoryService { // before completing it. let existingPromise = this._codeExchangePromises.get(scopeData.scopeStr); if (!existingPromise) { - existingPromise = this.handleCodeResponse(scopeData); + if (isSupportedEnvironment(callbackUri)) { + existingPromise = this.handleCodeResponse(scopeData); + } else { + inputBox = vscode.window.createInputBox(); + existingPromise = Promise.race([this.handleCodeInputBox(inputBox, codeVerifier, scopeData), this.handleCodeResponse(scopeData)]); + } this._codeExchangePromises.set(scopeData.scopeStr, existingPromise); } @@ -659,13 +660,7 @@ export class AzureActiveDirectoryService { throw new Error('No available code verifier'); } - const token = await this.exchangeCodeForToken(code, verifier, scopeData); - if (token.expiresIn) { - this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); - } - await this.setToken(token, scopeData); - - const session = await this.convertToSession(token); + const session = await this.exchangeCodeForSession(code, verifier, scopeData); resolve(session); } catch (err) { reject(err); @@ -680,8 +675,33 @@ export class AzureActiveDirectoryService { }); } - private async exchangeCodeForToken(code: string, codeVerifier: string, scopeData: IScopeData): Promise { + 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...'); + return new Promise((resolve: (value: vscode.AuthenticationSession) => void, reject) => { + inputBox.show(); + inputBox.onDidAccept(async () => { + const code = inputBox.value; + if (code) { + inputBox.dispose(); + const session = await this.exchangeCodeForSession(code, verifier, scopeData); + resolve(session); + } + }); + inputBox.onDidHide(() => { + if (!inputBox.value) { + inputBox.dispose(); + reject('Cancelled'); + } + }); + }); + } + + private async exchangeCodeForSession(code: string, codeVerifier: string, scopeData: IScopeData): Promise { Logger.info(`Exchanging login code for token for scopes: ${scopeData.scopeStr}`); + let token: IToken | undefined; try { const postData = querystring.stringify({ grant_type: 'authorization_code', @@ -698,11 +718,18 @@ export class AzureActiveDirectoryService { const json = await this.fetchTokenResponse(endpoint, postData, scopeData); Logger.info(`Exchanging login code for token (for scopes: ${scopeData.scopeStr}) succeeded!`); - return this.convertToTokenSync(json, scopeData); + token = this.convertToTokenSync(json, scopeData); } catch (e) { Logger.error(`Error exchanging code for token (for scopes ${scopeData.scopeStr}): ${e}`); throw e; } + + if (token.expiresIn) { + this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER); + } + await this.setToken(token, scopeData); + Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`); + return await this.convertToSession(token); } private async fetchTokenResponse(endpoint: string, postData: string, scopeData: IScopeData): Promise { diff --git a/extensions/microsoft-authentication/src/utils.ts b/extensions/microsoft-authentication/src/utils.ts index 164f2236221..443bb2dc048 100644 --- a/extensions/microsoft-authentication/src/utils.ts +++ b/extensions/microsoft-authentication/src/utils.ts @@ -2,7 +2,40 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { env, UIKind, Uri } from 'vscode'; export function toBase64UrlEncoding(base64string: string) { return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding } + +const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1']; +function isLocalhost(uri: Uri): boolean { + if (!/^https?$/i.test(uri.scheme)) { + return false; + } + const host = uri.authority.split(':')[0]; + return LOCALHOST_ADDRESSES.indexOf(host) >= 0; +} + +export function isSupportedEnvironment(uri: Uri): boolean { + if (env.uiKind === UIKind.Desktop) { + return true; + } + // local development (localhost:* or 127.0.0.1:*) + if (isLocalhost(uri)) { + return true; + } + // At this point we should only ever see https + if (uri.scheme !== 'https') { + return false; + } + + return ( + // vscode.dev & insiders.vscode.dev + /(?:^|\.)vscode\.dev$/.test(uri.authority) || + // github.dev & codespaces + /(?:^|\.)github\.dev$/.test(uri.authority) || + // github.dev/codespaces local setup (github.localhost) + /(?:^|\.)github\.localhost$/.test(uri.authority) + ); +} From fb66467d1e4f8c420803de5e0a10bc4467cebf5c Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Thu, 28 Jul 2022 11:35:10 -0700 Subject: [PATCH 166/179] Bugfix on enter/arrow/mouse interaction for code action widget (fixes #156587) * fix on hover vs key bindings interaction * removed allowClick boolean, modified current selected item for widget * modifed var types --- .../codeAction/browser/codeActionMenu.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index d3a15fec005..aa51bc780af 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -161,7 +161,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { private _ctxMenuWidgetVisible: IContextKey; private viewItems: ICodeActionMenuItem[] = []; private focusedEnabledItem: number | undefined; - private currSelectedItem: number = 0; + private currSelectedItem: number | undefined; private hasSeperator: boolean = false; private block?: HTMLElement; @@ -213,21 +213,24 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { e.elements.forEach(element => { if (element.isEnabled) { element.action.run(); + this.hideCodeActionWidget(); } }); - this.hideCodeActionWidget(); } } - private _onListHover(e: IListMouseEvent): void { if (!e.element) { + this.currSelectedItem = undefined; this.codeActionList.value?.setFocus([]); } else { if (e.element?.isEnabled) { this.codeActionList.value?.setFocus([e.element.index]); this.focusedEnabledItem = this.viewItems.indexOf(e.element); this.currSelectedItem = e.element.index; + } else { + this.currSelectedItem = undefined; + this.codeActionList.value?.setFocus([e.element.index]); } } } @@ -318,7 +321,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { // List selection if (this.viewItems.length < 1 || this.viewItems.every(item => item.isDocumentation)) { - this.currSelectedItem = 0; + this.currSelectedItem = undefined; } else { this.focusedEnabledItem = 0; this.currSelectedItem = this.viewItems[0].index; @@ -391,7 +394,9 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { } public onEnterSet() { - this.codeActionList.value?.setSelection([this.currSelectedItem]); + if (typeof this.currSelectedItem === 'number') { + this.codeActionList.value?.setSelection([this.currSelectedItem]); + } } override dispose() { @@ -403,7 +408,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution { this.options = []; this.viewItems = []; this.focusedEnabledItem = 0; - this.currSelectedItem = 0; + this.currSelectedItem = undefined; this.hasSeperator = false; this._contextViewService.hideContextView({ source: this }); } From 33a08dc6f4386aaa7067575dc8929183df080ae2 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 28 Jul 2022 11:40:11 -0700 Subject: [PATCH 167/179] use `task` instead of `taskName` (#156603) fix #155635 --- .../contrib/tasks/browser/abstractTaskService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 3a0c564b42b..18a68093766 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -398,9 +398,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer type: 'string', description: nls.localize('runTask.type', "The contributed task type") }, - taskName: { + task: { type: 'string', - description: nls.localize('runTask.taskName', "The task's label or a term to filter by") + description: nls.localize('runTask.task', "The task's label or a term to filter by") } } } @@ -2700,7 +2700,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer })) === true; } - private async _runTaskCommand(filter?: { type?: string; taskName?: string } | string): Promise { + private async _runTaskCommand(filter?: any | { type?: string; task?: string }): Promise { if (!this._canRunCommand()) { return; } @@ -2708,8 +2708,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let typeFilter: boolean = false; if (filter && typeof filter !== 'string') { // name takes precedence - typeFilter = !filter?.taskName && !!filter?.type; - filter = filter?.taskName || filter?.type; + typeFilter = !filter?.task && !!filter?.type; + filter = filter?.task || filter?.type; } const taskIdentifier: KeyedTaskIdentifier | undefined | string = this._getTaskIdentifier(filter); From 35a17f42e89ee15966dbe805d5faed63ec9b34c1 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 28 Jul 2022 11:48:33 -0700 Subject: [PATCH 168/179] fix another command to use ILocalizedString (#156615) --- src/vs/workbench/contrib/testing/browser/testExplorerActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 556f7f4e65d..53579678c41 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -249,7 +249,7 @@ export class ConfigureTestProfilesAction extends Action2 { constructor() { super({ id: TestCommandId.ConfigureTestProfilesAction, - title: localize('testing.configureProfile', 'Configure Test Profiles'), + title: { value: localize('testing.configureProfile', 'Configure Test Profiles'), original: 'Configure Test Profiles' }, icon: icons.testingUpdateProfiles, f1: true, category, From 0a65bea3573d503c3078eff3e4b7f26f138e967d Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Thu, 28 Jul 2022 11:52:52 -0700 Subject: [PATCH 169/179] allow context menu on command center (#156614) fixes #156512 --- .../workbench/browser/parts/titlebar/commandCenterControl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts index 25e9213343e..3856e6439a2 100644 --- a/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/commandCenterControl.ts @@ -114,7 +114,8 @@ export class CommandCenterControl { } else { return createActionViewItem(instantiationService, action, { hoverDelegate }); } - } + }, + allowContextMenu: true }); const menu = this._disposables.add(menuService.createMenu(MenuId.CommandCenter, contextKeyService)); const menuDisposables = this._disposables.add(new DisposableStore()); From 6fbee10cc199f1d48f9d1b32f89021fbfba00a8d Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Thu, 28 Jul 2022 11:53:51 -0700 Subject: [PATCH 170/179] more checking for undefined objects, fixed bug casuing markdown renderer to entirely crash --- extensions/ipynb/src/cellAttachmentRenderer.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/extensions/ipynb/src/cellAttachmentRenderer.ts b/extensions/ipynb/src/cellAttachmentRenderer.ts index 7e05834dbcb..69e294d57b9 100644 --- a/extensions/ipynb/src/cellAttachmentRenderer.ts +++ b/extensions/ipynb/src/cellAttachmentRenderer.ts @@ -22,11 +22,19 @@ export async function activate(ctx: RendererContext) { md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => { const token = tokens[idx]; const src = token.attrGet('src'); - const attachments: Record> = env.outputItem.metadata?.custom?.attachments; + const attachments: Record> = env.outputItem.metadata?.custom?.attachments; // this stores attachment entries for every image in the cell if (attachments && src) { - const [attachmentKey, attachmentVal] = Object.entries(attachments[src.replace('attachment:', '')])[0]; - const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal; - token.attrSet('src', b64Markdown); + const imageAttachment = attachments[src.replace('attachment:', '')]; + if (imageAttachment) { + // objEntries will always be length 1, with objEntries[0] holding [0]=mime,[1]=b64 + // if length = 0, something is wrong with the attachment, mime/b64 weren't copied over + const objEntries = Object.entries(imageAttachment); + if (objEntries.length) { + const [attachmentKey, attachmentVal] = objEntries[0]; + const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal; + token.attrSet('src', b64Markdown); + } + } } if (original) { From 0e2e0e2833b55469a585ccd4854748c5c7860971 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Thu, 28 Jul 2022 12:45:48 -0700 Subject: [PATCH 171/179] add tooltip tech to dropdown buttons (#156621) fixes #153429 --- .../browser/ui/dropdown/dropdownActionViewItem.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 0af76e3b6a0..00b21774ea0 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -126,9 +126,22 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { }; } + this.updateTooltip(); this.updateEnabled(); } + override getTooltip(): string | undefined { + let title: string | null = null; + + if (this.getAction().tooltip) { + title = this.getAction().tooltip; + } else if (this.getAction().label) { + title = this.getAction().label; + } + + return title ?? undefined; + } + override setActionContext(newContext: unknown): void { super.setActionContext(newContext); From 743b016722db90df977feecde0a4b3b4f58c2a4c Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 28 Jul 2022 14:27:45 -0700 Subject: [PATCH 172/179] Have padding on qp list not the whole widget (#156624) --- src/vs/base/parts/quickinput/browser/media/quickInput.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/parts/quickinput/browser/media/quickInput.css b/src/vs/base/parts/quickinput/browser/media/quickInput.css index efab21e77bf..e3357d75fe8 100644 --- a/src/vs/base/parts/quickinput/browser/media/quickInput.css +++ b/src/vs/base/parts/quickinput/browser/media/quickInput.css @@ -7,7 +7,6 @@ position: absolute; width: 600px; z-index: 2550; - padding: 0 1px 1px 1px; left: 50%; margin-left: -300px; -webkit-app-region: no-drag; @@ -151,6 +150,7 @@ .quick-input-list { line-height: 22px; margin-top: 6px; + padding: 0px 1px 1px 1px; } .quick-input-widget.hidden-input .quick-input-list { From e8ee2cf78ffe38e878fc0faa652f9515502fe58c Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 29 Jul 2022 00:45:18 -0700 Subject: [PATCH 173/179] Avoid List View default find widget steal keybindings. (#156637) --- src/vs/platform/list/browser/listService.ts | 5 +++++ src/vs/workbench/browser/actions/listCommands.ts | 4 ++-- src/vs/workbench/contrib/preferences/browser/settingsTree.ts | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 2bd9c44b14d..5af76e7958e 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -125,6 +125,7 @@ export const WorkbenchTreeElementHasParent = new RawContextKey('treeEle export const WorkbenchTreeElementCanExpand = new RawContextKey('treeElementCanExpand', false); export const WorkbenchTreeElementHasChild = new RawContextKey('treeElementHasChild', false); export const WorkbenchTreeFindOpen = new RawContextKey('treeFindOpen', false); +export const WorkbenchTreeSupportsFind = new RawContextKey('treeSupportsFind', true); const WorkbenchListTypeNavigationModeKey = 'listTypeNavigationMode'; /** @@ -1143,6 +1144,7 @@ class WorkbenchTreeInternals { private treeElementCanExpand: IContextKey; private treeElementHasChild: IContextKey; private treeFindOpen: IContextKey; + private treeSupportFindWidget: IContextKey; private _useAltAsMultipleSelectionModifier: boolean; private disposables: IDisposable[] = []; private styler: IDisposable | undefined; @@ -1176,7 +1178,10 @@ class WorkbenchTreeInternals { this.treeElementHasParent = WorkbenchTreeElementHasParent.bindTo(this.contextKeyService); this.treeElementCanExpand = WorkbenchTreeElementCanExpand.bindTo(this.contextKeyService); this.treeElementHasChild = WorkbenchTreeElementHasChild.bindTo(this.contextKeyService); + this.treeFindOpen = WorkbenchTreeFindOpen.bindTo(this.contextKeyService); + this.treeSupportFindWidget = WorkbenchTreeSupportsFind.bindTo(this.contextKeyService); + this.treeSupportFindWidget.set(options.findWidgetEnabled ?? true); this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService); diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index ee4848ce1ae..f6d73f19284 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -7,7 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { List } from 'vs/base/browser/ui/list/listWidget'; -import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation, WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent, WorkbenchTreeElementHasChild, WorkbenchTreeElementCanExpand, RawWorkbenchListFocusContextKey, WorkbenchTreeFindOpen } from 'vs/platform/list/browser/listService'; +import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation, WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent, WorkbenchTreeElementHasChild, WorkbenchTreeElementCanExpand, RawWorkbenchListFocusContextKey, WorkbenchTreeFindOpen, WorkbenchTreeSupportsFind } from 'vs/platform/list/browser/listService'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { equals, range } from 'vs/base/common/arrays'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -634,7 +634,7 @@ CommandsRegistry.registerCommandAlias('list.toggleFilterOnType', 'list.toggleFin KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'list.find', weight: KeybindingWeight.WorkbenchContrib, - when: RawWorkbenchListFocusContextKey, + when: ContextKeyExpr.and(RawWorkbenchListFocusContextKey, WorkbenchTreeSupportsFind), primary: KeyMod.CtrlCmd | KeyCode.KeyF, secondary: [KeyCode.F3], handler: (accessor) => { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 90a8b212b6c..2ad3516e3e9 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -2367,6 +2367,7 @@ export class SettingsTree extends WorkbenchObjectTree { filter: instantiationService.createInstance(SettingsTreeFilter, viewState), smoothScrolling: configurationService.getValue('workbench.list.smoothScrolling'), multipleSelectionSupport: false, + findWidgetEnabled: false }, instantiationService, contextKeyService, From d708be4ae49cc3144c50d52dc9dcb5e0807a6f2f Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 29 Jul 2022 10:47:17 +0200 Subject: [PATCH 174/179] Fixes #156645: Change the sticky scroll option to `editor.experimental.stickyScroll` --- src/vs/editor/common/config/editorOptions.ts | 55 +++--- .../common/standalone/standaloneEnums.ts | 146 +++++++-------- .../stickyScroll/browser/stickyScroll.ts | 6 +- src/vs/monaco.d.ts | 172 +++++++++--------- 4 files changed, 195 insertions(+), 184 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index b50d0d0e112..15b9d5cddd8 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -170,9 +170,9 @@ export interface IEditorOptions { */ scrollbar?: IEditorScrollbarOptions; /** - * Control the behavior of the sticky scroll + * Control the behavior of experimental options */ - stickyScroll?: IEditorStickyScrollOptions; + experimental?: IEditorExperimentalOptions; /** * Control the behavior and rendering of the minimap. */ @@ -2508,48 +2508,51 @@ class EditorLightbulb extends BaseEditorOption>; - -class EditorStickyScroll extends BaseEditorOption { +class EditorExperimental extends BaseEditorOption { constructor() { - const defaults: EditorStickyScrollOptions = { enabled: false }; + const defaults: EditorExperimentalOptions = { stickyScroll: { enabled: false } }; super( - EditorOption.stickyScroll, 'stickyScroll', defaults, + EditorOption.experimental, 'experimental', defaults, { - 'editor.stickyScroll.enabled': { + 'editor.experimental.stickyScroll.enabled': { type: 'boolean', - default: defaults.enabled, - description: nls.localize('editor.stickyScroll', "Shows the nested current scopes during the scroll at the top of the editor.") + default: defaults.stickyScroll.enabled, + description: nls.localize('editor.experimental.stickyScroll', "Shows the nested current scopes during the scroll at the top of the editor.") }, } ); } - public validate(_input: any): EditorStickyScrollOptions { + public validate(_input: any): EditorExperimentalOptions { if (!_input || typeof _input !== 'object') { return this.defaultValue; } - const input = _input as IEditorStickyScrollOptions; + const input = _input as IEditorExperimentalOptions; return { - enabled: boolean(input.enabled, this.defaultValue.enabled) + stickyScroll: { + enabled: boolean(input.stickyScroll?.enabled, this.defaultValue.stickyScroll.enabled) + } }; } } @@ -4550,6 +4553,7 @@ export const enum EditorOption { dragAndDrop, dropIntoEditor, emptySelectionClipboard, + experimental, extraEditorClassName, fastScrollSensitivity, find, @@ -4622,7 +4626,6 @@ export const enum EditorOption { smartSelect, smoothScrolling, stickyTabStops, - stickyScroll, stopRenderingLineAfter, suggest, suggestFontSize, @@ -4859,6 +4862,7 @@ export const EditorOptions = { )), emptySelectionClipboard: register(new EditorEmptySelectionClipboard()), dropIntoEditor: register(new EditorDropIntoEditor()), + experimental: register(new EditorExperimental()), extraEditorClassName: register(new EditorStringOption( EditorOption.extraEditorClassName, 'extraEditorClassName', '', )), @@ -5177,7 +5181,6 @@ export const EditorOptions = { EditorOption.smoothScrolling, 'smoothScrolling', false, { description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") } )), - stickyScroll: register(new EditorStickyScroll()), stopRenderingLineAfter: register(new EditorIntOption( EditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter', 10000, -1, Constants.MAX_SAFE_SMALL_INTEGER, diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index c62e7fc404f..5b9c0195e7b 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -206,79 +206,79 @@ export enum EditorOption { dragAndDrop = 31, dropIntoEditor = 32, emptySelectionClipboard = 33, - extraEditorClassName = 34, - fastScrollSensitivity = 35, - find = 36, - fixedOverflowWidgets = 37, - folding = 38, - foldingStrategy = 39, - foldingHighlight = 40, - foldingImportsByDefault = 41, - foldingMaximumRegions = 42, - unfoldOnClickAfterEndOfLine = 43, - fontFamily = 44, - fontInfo = 45, - fontLigatures = 46, - fontSize = 47, - fontWeight = 48, - formatOnPaste = 49, - formatOnType = 50, - glyphMargin = 51, - gotoLocation = 52, - hideCursorInOverviewRuler = 53, - hover = 54, - inDiffEditor = 55, - inlineSuggest = 56, - letterSpacing = 57, - lightbulb = 58, - lineDecorationsWidth = 59, - lineHeight = 60, - lineNumbers = 61, - lineNumbersMinChars = 62, - linkedEditing = 63, - links = 64, - matchBrackets = 65, - minimap = 66, - mouseStyle = 67, - mouseWheelScrollSensitivity = 68, - mouseWheelZoom = 69, - multiCursorMergeOverlapping = 70, - multiCursorModifier = 71, - multiCursorPaste = 72, - occurrencesHighlight = 73, - overviewRulerBorder = 74, - overviewRulerLanes = 75, - padding = 76, - parameterHints = 77, - peekWidgetDefaultFocus = 78, - definitionLinkOpensInPeek = 79, - quickSuggestions = 80, - quickSuggestionsDelay = 81, - readOnly = 82, - renameOnType = 83, - renderControlCharacters = 84, - renderFinalNewline = 85, - renderLineHighlight = 86, - renderLineHighlightOnlyWhenFocus = 87, - renderValidationDecorations = 88, - renderWhitespace = 89, - revealHorizontalRightPadding = 90, - roundedSelection = 91, - rulers = 92, - scrollbar = 93, - scrollBeyondLastColumn = 94, - scrollBeyondLastLine = 95, - scrollPredominantAxis = 96, - selectionClipboard = 97, - selectionHighlight = 98, - selectOnLineNumbers = 99, - showFoldingControls = 100, - showUnused = 101, - snippetSuggestions = 102, - smartSelect = 103, - smoothScrolling = 104, - stickyTabStops = 105, - stickyScroll = 106, + experimental = 34, + extraEditorClassName = 35, + fastScrollSensitivity = 36, + find = 37, + fixedOverflowWidgets = 38, + folding = 39, + foldingStrategy = 40, + foldingHighlight = 41, + foldingImportsByDefault = 42, + foldingMaximumRegions = 43, + unfoldOnClickAfterEndOfLine = 44, + fontFamily = 45, + fontInfo = 46, + fontLigatures = 47, + fontSize = 48, + fontWeight = 49, + formatOnPaste = 50, + formatOnType = 51, + glyphMargin = 52, + gotoLocation = 53, + hideCursorInOverviewRuler = 54, + hover = 55, + inDiffEditor = 56, + inlineSuggest = 57, + letterSpacing = 58, + lightbulb = 59, + lineDecorationsWidth = 60, + lineHeight = 61, + lineNumbers = 62, + lineNumbersMinChars = 63, + linkedEditing = 64, + links = 65, + matchBrackets = 66, + minimap = 67, + mouseStyle = 68, + mouseWheelScrollSensitivity = 69, + mouseWheelZoom = 70, + multiCursorMergeOverlapping = 71, + multiCursorModifier = 72, + multiCursorPaste = 73, + occurrencesHighlight = 74, + overviewRulerBorder = 75, + overviewRulerLanes = 76, + padding = 77, + parameterHints = 78, + peekWidgetDefaultFocus = 79, + definitionLinkOpensInPeek = 80, + quickSuggestions = 81, + quickSuggestionsDelay = 82, + readOnly = 83, + renameOnType = 84, + renderControlCharacters = 85, + renderFinalNewline = 86, + renderLineHighlight = 87, + renderLineHighlightOnlyWhenFocus = 88, + renderValidationDecorations = 89, + renderWhitespace = 90, + revealHorizontalRightPadding = 91, + roundedSelection = 92, + rulers = 93, + scrollbar = 94, + scrollBeyondLastColumn = 95, + scrollBeyondLastLine = 96, + scrollPredominantAxis = 97, + selectionClipboard = 98, + selectionHighlight = 99, + selectOnLineNumbers = 100, + showFoldingControls = 101, + showUnused = 102, + snippetSuggestions = 103, + smartSelect = 104, + smoothScrolling = 105, + stickyTabStops = 106, stopRenderingLineAfter = 107, suggest = 108, suggestFontSize = 109, diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index c42d96dff27..d76b699dd54 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -43,7 +43,7 @@ class StickyScrollController extends Disposable implements IEditorContribution { this._languageFeaturesService = _languageFeaturesService; this.stickyScrollWidget = new StickyScrollWidget(this._editor); this._register(this._editor.onDidChangeConfiguration(e => { - if (e.hasChanged(EditorOption.stickyScroll)) { + if (e.hasChanged(EditorOption.experimental)) { this.onConfigurationChange(); } })); @@ -52,8 +52,8 @@ class StickyScrollController extends Disposable implements IEditorContribution { } private onConfigurationChange() { - const options = this._editor.getOption(EditorOption.stickyScroll); - if (options.enabled === false) { + const options = this._editor.getOption(EditorOption.experimental); + if (options.stickyScroll.enabled === false) { this.stickyScrollWidget.emptyRootNode(); this._editor.removeOverlayWidget(this.stickyScrollWidget); this._sessionStore.clear(); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 91b72dd4d11..8b0f9bbc295 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2947,9 +2947,9 @@ declare namespace monaco.editor { */ scrollbar?: IEditorScrollbarOptions; /** - * Control the behavior of the sticky scroll + * Control the behavior of experimental options */ - stickyScroll?: IEditorStickyScrollOptions; + experimental?: IEditorExperimentalOptions; /** * Control the behavior and rendering of the minimap. */ @@ -3808,14 +3808,22 @@ declare namespace monaco.editor { enabled?: boolean; } - /** - * Configuration options for editor sticky scroll - */ - export interface IEditorStickyScrollOptions { + export interface IEditorExperimentalOptions { /** - * Enable the sticky scroll + * Configuration options for editor sticky scroll */ - enabled?: boolean; + stickyScroll?: { + /** + * Enable the sticky scroll + */ + enabled?: boolean; + }; + } + + export interface EditorExperimentalOptions { + stickyScroll: { + enabled: boolean; + }; } /** @@ -4376,79 +4384,79 @@ declare namespace monaco.editor { dragAndDrop = 31, dropIntoEditor = 32, emptySelectionClipboard = 33, - extraEditorClassName = 34, - fastScrollSensitivity = 35, - find = 36, - fixedOverflowWidgets = 37, - folding = 38, - foldingStrategy = 39, - foldingHighlight = 40, - foldingImportsByDefault = 41, - foldingMaximumRegions = 42, - unfoldOnClickAfterEndOfLine = 43, - fontFamily = 44, - fontInfo = 45, - fontLigatures = 46, - fontSize = 47, - fontWeight = 48, - formatOnPaste = 49, - formatOnType = 50, - glyphMargin = 51, - gotoLocation = 52, - hideCursorInOverviewRuler = 53, - hover = 54, - inDiffEditor = 55, - inlineSuggest = 56, - letterSpacing = 57, - lightbulb = 58, - lineDecorationsWidth = 59, - lineHeight = 60, - lineNumbers = 61, - lineNumbersMinChars = 62, - linkedEditing = 63, - links = 64, - matchBrackets = 65, - minimap = 66, - mouseStyle = 67, - mouseWheelScrollSensitivity = 68, - mouseWheelZoom = 69, - multiCursorMergeOverlapping = 70, - multiCursorModifier = 71, - multiCursorPaste = 72, - occurrencesHighlight = 73, - overviewRulerBorder = 74, - overviewRulerLanes = 75, - padding = 76, - parameterHints = 77, - peekWidgetDefaultFocus = 78, - definitionLinkOpensInPeek = 79, - quickSuggestions = 80, - quickSuggestionsDelay = 81, - readOnly = 82, - renameOnType = 83, - renderControlCharacters = 84, - renderFinalNewline = 85, - renderLineHighlight = 86, - renderLineHighlightOnlyWhenFocus = 87, - renderValidationDecorations = 88, - renderWhitespace = 89, - revealHorizontalRightPadding = 90, - roundedSelection = 91, - rulers = 92, - scrollbar = 93, - scrollBeyondLastColumn = 94, - scrollBeyondLastLine = 95, - scrollPredominantAxis = 96, - selectionClipboard = 97, - selectionHighlight = 98, - selectOnLineNumbers = 99, - showFoldingControls = 100, - showUnused = 101, - snippetSuggestions = 102, - smartSelect = 103, - smoothScrolling = 104, - stickyTabStops = 105, - stickyScroll = 106, + experimental = 34, + extraEditorClassName = 35, + fastScrollSensitivity = 36, + find = 37, + fixedOverflowWidgets = 38, + folding = 39, + foldingStrategy = 40, + foldingHighlight = 41, + foldingImportsByDefault = 42, + foldingMaximumRegions = 43, + unfoldOnClickAfterEndOfLine = 44, + fontFamily = 45, + fontInfo = 46, + fontLigatures = 47, + fontSize = 48, + fontWeight = 49, + formatOnPaste = 50, + formatOnType = 51, + glyphMargin = 52, + gotoLocation = 53, + hideCursorInOverviewRuler = 54, + hover = 55, + inDiffEditor = 56, + inlineSuggest = 57, + letterSpacing = 58, + lightbulb = 59, + lineDecorationsWidth = 60, + lineHeight = 61, + lineNumbers = 62, + lineNumbersMinChars = 63, + linkedEditing = 64, + links = 65, + matchBrackets = 66, + minimap = 67, + mouseStyle = 68, + mouseWheelScrollSensitivity = 69, + mouseWheelZoom = 70, + multiCursorMergeOverlapping = 71, + multiCursorModifier = 72, + multiCursorPaste = 73, + occurrencesHighlight = 74, + overviewRulerBorder = 75, + overviewRulerLanes = 76, + padding = 77, + parameterHints = 78, + peekWidgetDefaultFocus = 79, + definitionLinkOpensInPeek = 80, + quickSuggestions = 81, + quickSuggestionsDelay = 82, + readOnly = 83, + renameOnType = 84, + renderControlCharacters = 85, + renderFinalNewline = 86, + renderLineHighlight = 87, + renderLineHighlightOnlyWhenFocus = 88, + renderValidationDecorations = 89, + renderWhitespace = 90, + revealHorizontalRightPadding = 91, + roundedSelection = 92, + rulers = 93, + scrollbar = 94, + scrollBeyondLastColumn = 95, + scrollBeyondLastLine = 96, + scrollPredominantAxis = 97, + selectionClipboard = 98, + selectionHighlight = 99, + selectOnLineNumbers = 100, + showFoldingControls = 101, + showUnused = 102, + snippetSuggestions = 103, + smartSelect = 104, + smoothScrolling = 105, + stickyTabStops = 106, stopRenderingLineAfter = 107, suggest = 108, suggestFontSize = 109, @@ -4515,6 +4523,7 @@ declare namespace monaco.editor { dragAndDrop: IEditorOption; emptySelectionClipboard: IEditorOption; dropIntoEditor: IEditorOption>>; + experimental: IEditorOption; extraEditorClassName: IEditorOption; fastScrollSensitivity: IEditorOption; find: IEditorOption>>; @@ -4587,7 +4596,6 @@ declare namespace monaco.editor { snippetSuggestions: IEditorOption; smartSelect: IEditorOption>>; smoothScrolling: IEditorOption; - stickyScroll: IEditorOption>>; stopRenderingLineAfter: IEditorOption; suggest: IEditorOption>>; inlineSuggest: IEditorOption>>; From 84dc769b20d232daa03472cb29d3ccc67b91e3e7 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 29 Jul 2022 11:11:12 +0200 Subject: [PATCH 175/179] Include namespace in the sticky scroll. Fixes https://github.com/microsoft/vscode/issues/156611. (#156649) Sticks namespace {} to the sticky scroll widget too. Fixes https://github.com/microsoft/vscode/issues/156611. --- src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts index d76b699dd54..b394b835466 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScroll.ts @@ -108,7 +108,7 @@ class StickyScrollController extends Disposable implements IEditorContribution { let didRecursion: boolean = false; for (const outline of outlineElement?.children.values()) { const kind: SymbolKind = outline.symbol.kind; - if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) { didRecursion = true; this._findLineRanges(outline, depth + 1); } @@ -127,7 +127,7 @@ class StickyScrollController extends Disposable implements IEditorContribution { while (outlineElement) { const kind: SymbolKind = outlineElement.symbol.kind; - if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) { currentStartLine = outlineElement?.symbol.range.startLineNumber as number; currentEndLine = outlineElement?.symbol.range.endLineNumber as number; this._ranges.push([currentStartLine, currentEndLine, depth]); @@ -154,7 +154,7 @@ class StickyScrollController extends Disposable implements IEditorContribution { for (const outline of outlineModel.children.values()) { if (outline instanceof OutlineElement) { const kind: SymbolKind = outline.symbol.kind; - if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method) { + if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) { this._findLineRanges(outline, 1); } else { this._findLineRanges(outline, 0); From 12b08be500f8a307f30e92cbc3ee39ba115eab69 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 29 Jul 2022 12:30:05 +0200 Subject: [PATCH 176/179] Only use the commit in share link when upstream (#156658) Fixes #156627 --- extensions/github/src/links.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/github/src/links.ts b/extensions/github/src/links.ts index 22ede57ccbd..66f5b071ecd 100644 --- a/extensions/github/src/links.ts +++ b/extensions/github/src/links.ts @@ -125,11 +125,11 @@ export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: return; } - const commitHash = gitRepo.state.HEAD?.commit; + const commitHash = (gitRepo.state.HEAD?.ahead === 0) ? `/blob/${gitRepo.state.HEAD?.commit}` : ''; const fileSegments = fileAndPosition.type === LinkType.File ? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '') : (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : ''); - return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash + return `${hostPrefix}/${repo.owner}/${repo.repo}${commitHash }${fileSegments}`; } From 03214ee7b9b94d9498450b86f633b1a77b9ad6a9 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Fri, 29 Jul 2022 12:09:35 -0700 Subject: [PATCH 177/179] delay title bar adjustments until after menu bar is updated (#156688) fixes #156483 --- src/vs/workbench/browser/parts/titlebar/titlebarPart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 31f4d9b6e27..34edabed458 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -461,12 +461,12 @@ export class TitlebarPart extends Part implements ITitleService { this.element.style.setProperty('--zoom-factor', zoomFactor.toString()); this.rootContainer.classList.toggle('counter-zoom', this.useCounterZoom); - runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter()); - if (this.customMenubar) { const menubarDimension = new Dimension(0, dimension.height); this.customMenubar.layout(menubarDimension); } + + runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter()); } } From b96204a2406f895e04f466da7a3107090afa6715 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 29 Jul 2022 13:12:51 -0700 Subject: [PATCH 178/179] Show Edit Sessions should focus view, not container (#156678) Show Edit Sessions should focus view not container --- .../contrib/editSessions/browser/editSessions.contribution.ts | 4 ++-- .../contrib/editSessions/browser/editSessionsViews.ts | 4 ++-- src/vs/workbench/contrib/editSessions/common/editSessions.ts | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 2853ab2d422..3d96c44b96f 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 { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_DATA_VIEW_ID } 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 } from 'vs/platform/workspace/common/workspace'; @@ -199,7 +199,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo async run(accessor: ServicesAccessor) { that.shouldShowViewsContext.set(true); const viewsService = accessor.get(IViewsService); - await viewsService.openViewContainer(EDIT_SESSIONS_CONTAINER_ID); + await viewsService.openView(EDIT_SESSIONS_DATA_VIEW_ID); } })); } diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index 36b0c497939..28dfa2257e4 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_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions'; +import { EDIT_SESSIONS_DATA_VIEW_ID, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } 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'; @@ -30,7 +30,7 @@ export class EditSessionsDataViews extends Disposable { } private registerViews(container: ViewContainer): void { - const viewId = 'workbench.views.editSessions.data'; + const viewId = EDIT_SESSIONS_DATA_VIEW_ID; const name = localize('edit sessions data', 'All Sessions'); const treeView = this.instantiationService.createInstance(TreeView, viewId, name); treeView.showCollapseAllAction = true; diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index da791afa9df..c4a2801d9ff 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -71,6 +71,7 @@ export const EDIT_SESSIONS_SIGNED_IN_KEY = 'editSessionsSignedIn'; export const EDIT_SESSIONS_SIGNED_IN = new RawContextKey(EDIT_SESSIONS_SIGNED_IN_KEY, false); export const EDIT_SESSIONS_CONTAINER_ID = 'workbench.view.editSessions'; +export const EDIT_SESSIONS_DATA_VIEW_ID = 'workbench.views.editSessions.data'; export const EDIT_SESSIONS_TITLE = localize('edit sessions', 'Edit Sessions'); export const EDIT_SESSIONS_VIEW_ICON = registerIcon('edit-sessions-view-icon', Codicon.cloudDownload, localize('editSessionViewIcon', 'View icon of the edit sessions view.')); From dbae720630e5996cc4d05c14649480a19b077d78 Mon Sep 17 00:00:00 2001 From: Evpok Date: Sat, 30 Jul 2022 03:59:55 +0200 Subject: [PATCH 179/179] Enable Wayland build for snaps (#156551) Enable Wayland build --- resources/linux/snap/snapcraft.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml index 8bbad497ace..fc775b6554f 100644 --- a/resources/linux/snap/snapcraft.yaml +++ b/resources/linux/snap/snapcraft.yaml @@ -58,11 +58,9 @@ apps: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --no-sandbox common-id: @@NAME@@.desktop environment: - DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas url-handler: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --open-url --no-sandbox environment: - DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas