From 8472ca94896efeccf2abd80b330e183b7dd82c11 Mon Sep 17 00:00:00 2001 From: Malige Julien Date: Wed, 26 Sep 2018 11:25:45 +0200 Subject: [PATCH 001/111] PreserveCase visual component --- src/vs/editor/contrib/find/findWidget.css | 26 +++++++++++++++++++ src/vs/editor/contrib/find/findWidget.ts | 21 +++++++++++++++ .../find/images/preserve-case-dark.svg | 1 + .../contrib/find/images/preserve-case.svg | 1 + 4 files changed, 49 insertions(+) create mode 100644 src/vs/editor/contrib/find/images/preserve-case-dark.svg create mode 100644 src/vs/editor/contrib/find/images/preserve-case.svg diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index faf3f7efe98..8c570d5977a 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -83,6 +83,11 @@ width: 100% !important; padding-right: 66px; } + +.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { + padding-right: 22px; +} + .monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input, .monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { padding-top: 2px; @@ -215,6 +220,10 @@ background-image: url('images/expando-collapsed.svg'); } +.monaco-editor .find-widget .preserve-case { + background: url('images/preserve-case.svg') center center no-repeat; +} + .monaco-editor .find-widget .replace { background-image: url('images/replace.svg'); } @@ -228,12 +237,19 @@ } .monaco-editor .find-widget > .replace-part > .replace-input { + position: relative; display: flex; display: -webkit-flex; vertical-align: middle; width: auto !important; } +.monaco-editor .find-widget > .replace-part > .replace-input > .controls { + position: absolute; + top: 3px; + right: 2px; +} + /* REDUCED */ .monaco-editor .find-widget.reduced-find-widget .matchesCount, .monaco-editor .find-widget.reduced-find-widget .monaco-checkbox { @@ -306,6 +322,16 @@ background-image: url('images/close-dark.svg'); } +.monaco-editor.hc-black .find-widget .preserve-case-dark, +.monaco-editor.vs-dark .find-widget .preserve-case-dark { + background-image: url('images/preserve-case-dark.svg'); +} + +.monaco-editor.hc-black .find-widget .preserve-case, +.monaco-editor.vs-dark .find-widget .preserve-case { + background: url('images/preserve-case-dark.svg') center center no-repeat; +} + .monaco-editor.hc-black .find-widget .replace, .monaco-editor.vs-dark .find-widget .replace { background-image: url('images/replace-inverse.svg'); diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index a86d207d76a..7c39aedfbf9 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -18,6 +18,7 @@ import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findIn import { IMessage as InputBoxMessage, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { Widget } from 'vs/base/browser/ui/widget'; import { Sash, IHorizontalSashLayoutProvider, ISashEvent, Orientation } from 'vs/base/browser/ui/sash/sash'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { FIND_IDS, MATCHES_LIMIT, CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel'; @@ -45,6 +46,7 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind' const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace"); const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace"); +const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case"); const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace"); const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All"); const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode"); @@ -99,6 +101,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _nextBtn: SimpleButton; private _toggleSelectionFind: SimpleCheckbox; private _closeBtn: SimpleButton; + private _preserveCase: Checkbox; private _replaceBtn: SimpleButton; private _replaceAllBtn: SimpleButton; @@ -862,6 +865,18 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._state.change({ replaceString: this._replaceInputBox.value }, false); })); + this._preserveCase = this._register(new Checkbox({ + actionClassName: 'preserve-case', + title: NLS_PRESERVE_CASE_LABEL, + isChecked: false + })); + this._preserveCase.checked = !!this._state.preserveCase; + this._register(this._preserveCase.onChange(viaKeyboard => { + if (!viaKeyboard) { + this._replaceInputBox.focus(); + } + })); + // Replace one button this._replaceBtn = this._register(new SimpleButton({ label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction), @@ -886,6 +901,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } })); + let controls = document.createElement('div'); + controls.className = 'controls'; + controls.style.display = 'block'; + controls.appendChild(this._preserveCase.domNode); + replaceInput.appendChild(controls); + let replacePart = document.createElement('div'); replacePart.className = 'replace-part'; replacePart.appendChild(replaceInput); diff --git a/src/vs/editor/contrib/find/images/preserve-case-dark.svg b/src/vs/editor/contrib/find/images/preserve-case-dark.svg new file mode 100644 index 00000000000..ae540172027 --- /dev/null +++ b/src/vs/editor/contrib/find/images/preserve-case-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/preserve-case.svg b/src/vs/editor/contrib/find/images/preserve-case.svg new file mode 100644 index 00000000000..1f3b1a2c57e --- /dev/null +++ b/src/vs/editor/contrib/find/images/preserve-case.svg @@ -0,0 +1 @@ + \ No newline at end of file From 73af37ceefee11038a1e6aeac16163e7f62dbb67 Mon Sep 17 00:00:00 2001 From: Malige Julien Date: Tue, 9 Oct 2018 14:06:29 +0200 Subject: [PATCH 002/111] Build ReplaceString preserving case --- src/vs/editor/contrib/find/findController.ts | 14 +++++++++++-- src/vs/editor/contrib/find/findModel.ts | 5 +++-- src/vs/editor/contrib/find/findState.ts | 21 ++++++++++++++++++++ src/vs/editor/contrib/find/findWidget.ts | 3 ++- src/vs/editor/contrib/find/replacePattern.ts | 17 ++++++++++++++-- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index c633e761e24..ccf388a4b7f 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -109,7 +109,8 @@ export class CommonFindController extends Disposable implements editorCommon.IEd searchScope: null, matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false) }, false); if (shouldRestartFind) { @@ -167,13 +168,17 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (e.matchCase) { this._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE); } + if (e.preserveCase) { + this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE); + } } private loadQueryState() { this._state.change({ matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase) }, false); } @@ -214,6 +219,11 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } + public togglePreserveCase(): void { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this.highlightFindOptions(); + } + public toggleSearchScope(): void { if (this._state.searchScope) { this._state.change({ searchScope: null }, true); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index b5b4102a821..bac233753a8 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -59,6 +59,7 @@ export const FIND_IDS = { ToggleWholeWordCommand: 'toggleFindWholeWord', ToggleRegexCommand: 'toggleFindRegex', ToggleSearchScopeCommand: 'toggleFindInSelection', + TogglePreserveCaseCommand: 'togglePreserveCase', ReplaceOneAction: 'editor.action.replaceOne', ReplaceAllAction: 'editor.action.replaceAll', SelectAllMatchesAction: 'editor.action.selectAllMatches' @@ -417,11 +418,11 @@ export class FindModelBoundToEditorModel { let replacePattern = this._getReplacePattern(); let selection = this._editor.getSelection(); - let nextMatch = this._getNextMatch(selection.getStartPosition(), replacePattern.hasReplacementPatterns, false); + let nextMatch = this._getNextMatch(selection.getStartPosition(), true, false); if (nextMatch) { if (selection.equalsRange(nextMatch.range)) { // selection sits on a find match => replace it! - let replaceString = replacePattern.buildReplaceString(nextMatch.matches); + let replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase); let command = new ReplaceCommand(selection, replaceString); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index 35ff1e4dbf5..6be950fbb53 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -18,6 +18,7 @@ export interface FindReplaceStateChangedEvent { isRegex: boolean; wholeWord: boolean; matchCase: boolean; + preserveCase: boolean; searchScope: boolean; matchesPosition: boolean; matchesCount: boolean; @@ -41,6 +42,8 @@ export interface INewFindReplaceState { wholeWordOverride?: FindOptionOverride; matchCase?: boolean; matchCaseOverride?: FindOptionOverride; + preserveCase?: boolean; + preserveCaseOverride?: FindOptionOverride; searchScope?: Range; } @@ -65,6 +68,8 @@ export class FindReplaceState implements IDisposable { private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; private _matchCaseOverride: FindOptionOverride; + private _preserveCase: boolean; + private _preserveCaseOverride: FindOptionOverride; private _searchScope: Range | null; private _matchesPosition: number; private _matchesCount: number; @@ -78,10 +83,12 @@ export class FindReplaceState implements IDisposable { public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } + public get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); } public get actualIsRegex(): boolean { return this._isRegex; } public get actualWholeWord(): boolean { return this._wholeWord; } public get actualMatchCase(): boolean { return this._matchCase; } + public get actualPreserveCase(): boolean { return this._preserveCase; } public get searchScope(): Range | null { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } @@ -100,6 +107,8 @@ export class FindReplaceState implements IDisposable { this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; this._matchCaseOverride = FindOptionOverride.NotSet; + this._preserveCase = false; + this._preserveCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; @@ -121,6 +130,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -170,6 +180,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -180,6 +191,7 @@ export class FindReplaceState implements IDisposable { const oldEffectiveIsRegex = this.isRegex; const oldEffectiveWholeWords = this.wholeWord; const oldEffectiveMatchCase = this.matchCase; + const oldEffectivePreserveCase = this.preserveCase; if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { @@ -218,6 +230,9 @@ export class FindReplaceState implements IDisposable { if (typeof newState.matchCase !== 'undefined') { this._matchCase = newState.matchCase; } + if (typeof newState.preserveCase !== 'undefined') { + this._preserveCase = newState.preserveCase; + } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { this._searchScope = newState.searchScope; @@ -230,6 +245,7 @@ export class FindReplaceState implements IDisposable { this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + this._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet); if (oldEffectiveIsRegex !== this.isRegex) { somethingChanged = true; @@ -244,6 +260,11 @@ export class FindReplaceState implements IDisposable { changeEvent.matchCase = true; } + if (oldEffectivePreserveCase !== this.preserveCase) { + somethingChanged = true; + changeEvent.preserveCase = true; + } + if (somethingChanged) { this._onFindReplaceStateChange.fire(changeEvent); } diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 7c39aedfbf9..bfb2a5cfdc1 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -868,11 +868,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._preserveCase = this._register(new Checkbox({ actionClassName: 'preserve-case', title: NLS_PRESERVE_CASE_LABEL, - isChecked: false + isChecked: false, })); this._preserveCase.checked = !!this._state.preserveCase; this._register(this._preserveCase.onChange(viaKeyboard => { if (!viaKeyboard) { + this._state.change({ preserveCase: !this._state.preserveCase }, false); this._replaceInputBox.focus(); } })); diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index 3bd09a78e2d..c881a4e0330 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { containsUppercaseCharacter } from 'vs/base/common/strings'; const enum ReplacePatternKind { StaticValue = 0, @@ -48,9 +49,21 @@ export class ReplacePattern { } } - public buildReplaceString(matches: string[] | null): string { + public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string { if (this._state.kind === ReplacePatternKind.StaticValue) { - return this._state.staticValue; + if (preserveCase && matches && matches[0]) { + if (matches[0].toUpperCase() === matches[0]) { + return this._state.staticValue.toUpperCase(); + } else if (matches[0].toLowerCase() === matches[0]) { + return this._state.staticValue.toLowerCase(); + } else if (containsUppercaseCharacter(matches[0][0])) { + return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1); + } else { + return this._state.staticValue[0].toLocaleLowerCase() + this._state.staticValue.substr(1); + } + } else { + return this._state.staticValue; + } } let result = ''; From 5d001b842b693d7dcb931f9b6518a9e5830f8eaf Mon Sep 17 00:00:00 2001 From: Dave Alongi Date: Fri, 15 Mar 2019 13:08:05 -0700 Subject: [PATCH 003/111] Extension URI Handlers: "Don't ask me again" checkbox when confirming --- .../inactiveExtensionUrlHandler.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts index 2713af6dad8..b44c3ddc468 100644 --- a/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts @@ -22,6 +22,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; +const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value); @@ -90,6 +91,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } + const confirmedExtensionIds = this.getConfirmedExtensionIds(); + confirmed = confirmed || confirmedExtensionIds.indexOf(ExtensionIdentifier.toKey(extensionId)) >= 0; + if (!confirmed) { let uriString = uri.toString(); @@ -99,6 +103,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + checkbox: { + label: localize('rememberConfirmUrl', "Don't ask again for this extension."), + }, detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' @@ -107,6 +114,14 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { if (!result.confirmed) { return true; } + + if (result.checkboxChecked) { + this.storageService.store( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + JSON.stringify([...confirmedExtensionIds, ExtensionIdentifier.toKey(extensionId)]), + StorageScope.GLOBAL, + ); + } } const handler = this.extensionHandlers.get(ExtensionIdentifier.toKey(extensionId)); @@ -153,6 +168,15 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.extensionHandlers.delete(ExtensionIdentifier.toKey(extensionId)); } + private getConfirmedExtensionIds(): Array { + const ignoredExtensions = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + try { + return JSON.parse(ignoredExtensions); + } catch (err) { + return []; + } + } + private async handleUnhandledURL(uri: URI, extensionIdentifier: IExtensionIdentifier): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(); const extension = installedExtensions.filter(e => areSameExtensions(e.identifier, extensionIdentifier))[0]; From 8d1eb98d69cad195b70c48d2d4a0b10829d36955 Mon Sep 17 00:00:00 2001 From: Dave Alongi Date: Wed, 20 Mar 2019 10:28:34 -0700 Subject: [PATCH 004/111] Additionally honor a configuration setting --- .../extensions.contribution.ts | 5 ++ .../common/inactiveExtensionUrlHandler.ts | 67 ++++++++++++++----- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 73d6f8953f0..19efc2fd429 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -240,6 +240,11 @@ Registry.as(ConfigurationExtensions.Configuration) type: 'boolean', description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."), default: false + }, + 'extensions.confirmedUriHandlerExtensionIds': { + type: 'array', + description: localize('handleUriConfirmedExtensions', "When extensions are listed here, a confirmation prompt will not be required before that extension can handle a URI."), + default: [] } } }); diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index ddb7f8e90e8..edba464569d 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { EnablementState, IExtensionEnablementService, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -22,6 +23,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; +const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds'; const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { @@ -62,7 +64,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS); const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE); @@ -92,7 +96,7 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } const confirmedExtensionIds = this.getConfirmedExtensionIds(); - confirmed = confirmed || confirmedExtensionIds.indexOf(ExtensionIdentifier.toKey(extensionId)) >= 0; + confirmed = confirmed || confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); if (!confirmed) { let uriString = uri.toString(); @@ -116,11 +120,7 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (result.checkboxChecked) { - this.storageService.store( - CONFIRMED_EXTENSIONS_STORAGE_KEY, - JSON.stringify([...confirmedExtensionIds, ExtensionIdentifier.toKey(extensionId)]), - StorageScope.GLOBAL, - ); + this.addConfirmedExtensionIdToStorage(extensionId); } } @@ -168,15 +168,6 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.extensionHandlers.delete(ExtensionIdentifier.toKey(extensionId)); } - private getConfirmedExtensionIds(): Array { - const ignoredExtensions = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); - try { - return JSON.parse(ignoredExtensions); - } catch (err) { - return []; - } - } - private async handleUnhandledURL(uri: URI, extensionIdentifier: IExtensionIdentifier): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(); const extension = installedExtensions.filter(e => areSameExtensions(e.identifier, extensionIdentifier))[0]; @@ -290,6 +281,50 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.uriBuffer = uriBuffer; } + private getConfirmedExtensionIds(): Set { + return new Set([ + ...this.getConfirmedExtensionIdsFromStorage(), + ...this.getConfirmedExtensionIdsFromConfiguration(), + ].map( + extensionId => ExtensionIdentifier.toKey(extensionId) + )); + } + + private getConfirmedExtensionIdsFromConfiguration(): Array { + const confirmedExtensionIds = this.configurationService.getValue>( + CONFIRMED_EXTENSIONS_CONFIGURATION_KEY + ); + if (!Array.isArray(confirmedExtensionIds)) { + return []; + } + + return confirmedExtensionIds; + } + + private getConfirmedExtensionIdsFromStorage(): Array { + const confirmedExtensionIdsJson = this.storageService.get( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + StorageScope.GLOBAL, + '[]', + ); + try { + return JSON.parse(confirmedExtensionIdsJson); + } catch (err) { + return []; + } + } + private addConfirmedExtensionIdToStorage(extensionId: string): void { + const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); + this.storageService.store( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + JSON.stringify([ + ...existingConfirmedExtensionIds, + ExtensionIdentifier.toKey(extensionId), + ]), + StorageScope.GLOBAL, + ); + } + dispose(): void { this.disposable.dispose(); this.extensionHandlers.clear(); From 6ae15bb89542dcce780536b4ab865445a93f1a06 Mon Sep 17 00:00:00 2001 From: Dave Alongi Date: Wed, 20 Mar 2019 10:40:20 -0700 Subject: [PATCH 005/111] Update extensions.contribution.ts Improve description of configuration --- .../extensions/electron-browser/extensions.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 19efc2fd429..dc59610c50c 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -243,7 +243,7 @@ Registry.as(ConfigurationExtensions.Configuration) }, 'extensions.confirmedUriHandlerExtensionIds': { type: 'array', - description: localize('handleUriConfirmedExtensions', "When extensions are listed here, a confirmation prompt will not be required before that extension can handle a URI."), + description: localize('handleUriConfirmedExtensions', "When an extension is listed here, a confirmation prompt will not be shown when that extension handles a URI."), default: [] } } From 474b58464c296086048ba6a9ce2e2bda94fe9f7d Mon Sep 17 00:00:00 2001 From: Dave Alongi Date: Wed, 17 Apr 2019 07:39:51 -0700 Subject: [PATCH 006/111] Fix formatting that was broken during github.com conflict resolution --- .../extensions/electron-browser/extensions.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 1a852603229..83a97292973 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -246,7 +246,7 @@ Registry.as(ConfigurationExtensions.Configuration) type: 'array', description: localize('handleUriConfirmedExtensions', "When an extension is listed here, a confirmation prompt will not be shown when that extension handles a URI."), default: [] - }, + }, 'extensions.extensionKind': { type: 'object', description: localize('extensions.extensionKind', "Configure ui or workspace extensions and allow them to enable locally or remotely in a remote window."), From e9dd4687435751144ca5c6139882f07dc3218ef3 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Mon, 22 Jul 2019 09:45:49 -0500 Subject: [PATCH 007/111] Add proposed DiagnosticTag.Deprecated enum member --- src/vs/vscode.proposed.d.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 5bca4d0d507..6a31141bb94 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1274,4 +1274,18 @@ declare module 'vscode' { } //#endregion + + //#region Deprecated support + + export enum DiagnosticTag { + /** + * Deprecated or obsolete code + * + * Can be used to style with strikeout or other "obsolete" styling. See: + * https://github.com/microsoft/vscode/issues/50972 + */ + Deprecated = 2, + } + + //#endregion } From f88f79b6e06040c45628551ea977f78269435228 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Mon, 22 Jul 2019 11:34:27 -0500 Subject: [PATCH 008/111] Add Deprecated enum member to extHostTypes --- src/vs/workbench/api/common/extHostTypes.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index b8aebf92b45..de8d3eec8b3 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -773,6 +773,7 @@ export class SnippetString { export enum DiagnosticTag { Unnecessary = 1, + Deprecated = 2 } export enum DiagnosticSeverity { From 6b3ae43691a3729e4a988d1182abe6b7aba2f045 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Mon, 22 Jul 2019 11:52:48 -0500 Subject: [PATCH 009/111] Add Deprecated to MarkerTag --- src/vs/editor/common/standalone/standaloneEnums.ts | 3 ++- src/vs/monaco.d.ts | 3 ++- src/vs/platform/markers/common/markers.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index df80861b2a8..46d295d2398 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,7 +7,8 @@ export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 945d10d7e14..982a16b87ef 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -27,7 +27,8 @@ declare namespace monaco { export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 9461b506c21..235c4b12f36 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -39,6 +39,7 @@ export interface IRelatedInformation { export const enum MarkerTag { Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { From 36c9106350a290fb0d128f6a3f24cedcbb9fcf63 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Mon, 22 Jul 2019 11:59:00 -0500 Subject: [PATCH 010/111] Add DiagnosticTag case for MarkerTag.Deprecated --- src/vs/workbench/api/common/extHostTypeConverters.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 80fef1bdda0..bc2951b6220 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -108,6 +108,8 @@ export namespace DiagnosticTag { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; + case types.DiagnosticTag.Deprecated: + return MarkerTag.Deprecated; } return undefined; } From f706130a5bfe3e4004c48198ca3db4800440356c Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Tue, 23 Jul 2019 09:08:56 -0500 Subject: [PATCH 011/111] Revert "Add DiagnosticTag case for MarkerTag.Deprecated" This reverts commit 36c9106350a290fb0d128f6a3f24cedcbb9fcf63. --- src/vs/workbench/api/common/extHostTypeConverters.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index bc2951b6220..80fef1bdda0 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -108,8 +108,6 @@ export namespace DiagnosticTag { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; - case types.DiagnosticTag.Deprecated: - return MarkerTag.Deprecated; } return undefined; } From 64982b604fc74d841abb737bd0e2f196aea51df4 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Tue, 23 Jul 2019 09:09:06 -0500 Subject: [PATCH 012/111] Revert "Add Deprecated to MarkerTag" This reverts commit 6b3ae43691a3729e4a988d1182abe6b7aba2f045. --- src/vs/editor/common/standalone/standaloneEnums.ts | 3 +-- src/vs/monaco.d.ts | 3 +-- src/vs/platform/markers/common/markers.ts | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 46d295d2398..df80861b2a8 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,8 +7,7 @@ export enum MarkerTag { - Unnecessary = 1, - Deprecated = 2 + Unnecessary = 1 } export enum MarkerSeverity { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 982a16b87ef..945d10d7e14 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -27,8 +27,7 @@ declare namespace monaco { export enum MarkerTag { - Unnecessary = 1, - Deprecated = 2 + Unnecessary = 1 } export enum MarkerSeverity { diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 235c4b12f36..9461b506c21 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -39,7 +39,6 @@ export interface IRelatedInformation { export const enum MarkerTag { Unnecessary = 1, - Deprecated = 2 } export enum MarkerSeverity { From b4edff8f5b01013600241d22536ba305100dfb1e Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Tue, 23 Jul 2019 10:23:46 -0500 Subject: [PATCH 013/111] Revert "Revert "Add Deprecated to MarkerTag"" This reverts commit 64982b604fc74d841abb737bd0e2f196aea51df4. --- src/vs/editor/common/standalone/standaloneEnums.ts | 3 ++- src/vs/monaco.d.ts | 3 ++- src/vs/platform/markers/common/markers.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index df80861b2a8..46d295d2398 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,7 +7,8 @@ export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 945d10d7e14..982a16b87ef 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -27,7 +27,8 @@ declare namespace monaco { export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 9461b506c21..235c4b12f36 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -39,6 +39,7 @@ export interface IRelatedInformation { export const enum MarkerTag { Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { From 1762f3f713a34e7ebc61e58188adc5917bb5d159 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Tue, 23 Jul 2019 10:24:00 -0500 Subject: [PATCH 014/111] Revert "Revert "Add DiagnosticTag case for MarkerTag.Deprecated"" This reverts commit f706130a5bfe3e4004c48198ca3db4800440356c. --- src/vs/workbench/api/common/extHostTypeConverters.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 80fef1bdda0..bc2951b6220 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -108,6 +108,8 @@ export namespace DiagnosticTag { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; + case types.DiagnosticTag.Deprecated: + return MarkerTag.Deprecated; } return undefined; } From 23c01b4ca5c6126aa459c0825fa38f4d73474c25 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 13:20:17 -0500 Subject: [PATCH 015/111] Add deprecated classname --- src/vs/editor/browser/widget/codeEditorWidget.ts | 2 ++ src/vs/editor/common/model/intervalTree.ts | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 0cd342d195c..20da2f1c223 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1851,4 +1851,6 @@ registerThemingParticipant((theme, collector) => { if (unnecessaryBorder) { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } + + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedDecoration} { text-decoration: strikethrough; }`); }); diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index 496e77b9ef4..b04d58b3101 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -17,7 +17,8 @@ export const enum ClassName { EditorWarningDecoration = 'squiggly-warning', EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', - EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary' + EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', + EditorDeprecatedDecoration = 'squiggly-deprecated' } export const enum NodeColor { From b71363ff77311f3d49fbdd5f693af70a99280db5 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 13:40:14 -0500 Subject: [PATCH 016/111] Use inline decoration --- src/vs/editor/browser/widget/codeEditorWidget.ts | 2 +- src/vs/editor/common/model/intervalTree.ts | 2 +- src/vs/editor/common/services/markerDecorationsServiceImpl.ts | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 20da2f1c223..54c35262a68 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1852,5 +1852,5 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } - collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedDecoration} { text-decoration: strikethrough; }`); + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: strikethrough; }`); }); diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index b04d58b3101..d400024e7c5 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -18,7 +18,7 @@ export const enum ClassName { EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', - EditorDeprecatedDecoration = 'squiggly-deprecated' + EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index a319e8004b6..3da62fed16f 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -221,6 +221,9 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) { inlineClassName = ClassName.EditorUnnecessaryInlineDecoration; } + if (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) { + inlineClassName = ClassName.EditorDeprecatedInlineDecoration; + } } return { From 895d6323b4a7686dbc9533c09bbc76fd741f195d Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 13:40:44 -0500 Subject: [PATCH 017/111] Add CompletionItem.deprecated property from LSP --- src/vs/editor/common/modes.ts | 4 ++++ src/vs/monaco.d.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index fa05b9b968c..dbeb3fb1956 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -396,6 +396,10 @@ export interface CompletionItem { * an icon is chosen by the editor. */ kind: CompletionItemKind; + /** + * Indicates if this item is deprecated. + */ + deprecated?: boolean; /** * A human-readable string with additional information * about this item, like type or symbol information. diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 982a16b87ef..75692fbcceb 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4790,6 +4790,10 @@ declare namespace monaco.languages { * an icon is chosen by the editor. */ kind: CompletionItemKind; + /** + * Indicates if this item is deprecated. + */ + deprecated?: boolean; /** * A human-readable string with additional information * about this item, like type or symbol information. From 87ae3a38d337ade925a009cf86d82f11d36fe476 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 14:46:50 -0500 Subject: [PATCH 018/111] Add deprecated support to SuggestDataDto --- src/vs/vscode.proposed.d.ts | 7 +++++++ src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts | 1 + src/vs/workbench/api/common/extHost.protocol.ts | 1 + src/vs/workbench/api/common/extHostLanguageFeatures.ts | 1 + 4 files changed, 10 insertions(+) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6a31141bb94..a495e65a268 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1277,6 +1277,13 @@ declare module 'vscode' { //#region Deprecated support + export interface CompletionItem { + /** + * Indicates if this item is deprecated. + */ + deprecated?: boolean; + } + export enum DiagnosticTag { /** * Deprecated or obsolete code diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 75af9eebf01..3541ba2eef0 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -341,6 +341,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha commitCharacters: data.k, additionalTextEdits: data.l, command: data.m, + deprecated: data.n, // not-standard _id: data.x, }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8fb612d3a7c..1e30b620dca 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -937,6 +937,7 @@ export interface SuggestDataDto { k/* commitCharacters */?: string[]; l/* additionalTextEdits */?: ISingleEditOperation[]; m/* command */?: modes.Command; + n/* deprecated */?: boolean; // not-standard x?: ChainedCacheId; } diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 884618cc457..6c7065f29f2 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -736,6 +736,7 @@ class SuggestAdapter { k: item.commitCharacters, l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), m: this._commands.toInternal(item.command, disposables), + n: item.deprecated }; // 'insertText'-logic From 3422bb0a26312c4139f3109a5dfefd75bbdb0c98 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 14:47:13 -0500 Subject: [PATCH 019/111] Fix css rule to line-through --- src/vs/editor/browser/widget/codeEditorWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 54c35262a68..68e1746f63d 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1852,5 +1852,5 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } - collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: strikethrough; }`); + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; }`); }); From 4a2b010e340412961bf64022eac3f68c70c52066 Mon Sep 17 00:00:00 2001 From: Kamran Ayub Date: Wed, 24 Jul 2019 15:10:18 -0500 Subject: [PATCH 020/111] Add inline deprecated styling to suggest widget --- src/vs/editor/common/model/intervalTree.ts | 2 +- src/vs/editor/contrib/suggest/media/suggest.css | 7 +++++++ src/vs/editor/contrib/suggest/suggestWidget.ts | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index d400024e7c5..1815f7ee86f 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -18,7 +18,7 @@ export const enum ClassName { EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', - EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' + EditorDeprecatedInlineDecoration = 'inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 09594abb493..2f740dfad64 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -97,6 +97,13 @@ font-weight: bold; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .inline-deprecated { + text-decoration: none; /* override normal inline behavior due to HTML structure */ +} +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .inline-deprecated span { + text-decoration: line-through; +} + /** Icon styles **/ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 9e02b37f673..9eb1398848d 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -9,6 +9,7 @@ import { createMatches } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { ClassName } from 'vs/editor/common/model/intervalTree'; import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; @@ -196,6 +197,10 @@ class Renderer implements IListRenderer ]; } + if (suggestion.label && suggestion.deprecated) { + labelOptions.extraClasses = (labelOptions.extraClasses || []).concat([ClassName.EditorDeprecatedInlineDecoration]); + } + data.iconLabel.setLabel(suggestion.label, undefined, labelOptions); data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); From 5bff4b527672eaf41c8031db033cb3a0688d4a2b Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 24 Jul 2019 16:49:51 -0700 Subject: [PATCH 021/111] Add test cases --- src/vs/editor/contrib/find/replacePattern.ts | 5 +++-- .../contrib/find/test/replacePattern.test.ts | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index c881a4e0330..50e90d7f3ea 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -51,7 +51,7 @@ export class ReplacePattern { public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string { if (this._state.kind === ReplacePatternKind.StaticValue) { - if (preserveCase && matches && matches[0]) { + if (preserveCase && matches && (matches[0] !== '')) { if (matches[0].toUpperCase() === matches[0]) { return this._state.staticValue.toUpperCase(); } else if (matches[0].toLowerCase() === matches[0]) { @@ -59,7 +59,8 @@ export class ReplacePattern { } else if (containsUppercaseCharacter(matches[0][0])) { return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1); } else { - return this._state.staticValue[0].toLocaleLowerCase() + this._state.staticValue.substr(1); + // we don't understand its pattern yet. + return this._state.staticValue; } } else { return this._state.staticValue; diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index b36a509e34d..d252ac74c6a 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -153,4 +153,26 @@ suite('Replace Pattern test', () => { let actual = replacePattern.buildReplaceString(matches); assert.equal(actual, 'a{}'); }); + + test('preserve case', () => { + let replacePattern = parseReplaceString('Def'); + let actual = replacePattern.buildReplaceString(['abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['abc', 'Abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc', 'abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC', 'abc'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['AbC'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['aBC'], true); + assert.equal(actual, 'Def'); + }); }); From 53f95f8d4217ad32cf1cf85f83cb43f66b0f445a Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 24 Jul 2019 16:56:16 -0700 Subject: [PATCH 022/111] Use monaco-case-sensitive icon --- src/vs/editor/contrib/find/findWidget.css | 14 -------------- src/vs/editor/contrib/find/findWidget.ts | 2 +- .../contrib/find/images/preserve-case-dark.svg | 1 - .../editor/contrib/find/images/preserve-case.svg | 1 - 4 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 src/vs/editor/contrib/find/images/preserve-case-dark.svg delete mode 100644 src/vs/editor/contrib/find/images/preserve-case.svg diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index e806c7bef36..d210cb1dd49 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -220,10 +220,6 @@ background-image: url('images/tree-collapsed-light.svg'); } -.monaco-editor .find-widget .preserve-case { - background: url('images/preserve-case.svg') center center no-repeat; -} - .monaco-editor .find-widget .replace { background-image: url('images/replace-light.svg'); } @@ -314,16 +310,6 @@ background-image: url('images/close-dark.svg'); } -.monaco-editor.hc-black .find-widget .preserve-case-dark, -.monaco-editor.vs-dark .find-widget .preserve-case-dark { - background-image: url('images/preserve-case-dark.svg'); -} - -.monaco-editor.hc-black .find-widget .preserve-case, -.monaco-editor.vs-dark .find-widget .preserve-case { - background: url('images/preserve-case-dark.svg') center center no-repeat; -} - .monaco-editor.hc-black .find-widget .replace, .monaco-editor.vs-dark .find-widget .replace { background-image: url('images/replace-dark.svg'); diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 76178fddbc8..e06de65d099 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -917,7 +917,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas })); this._preserveCase = this._register(new Checkbox({ - actionClassName: 'preserve-case', + actionClassName: 'monaco-case-sensitive', title: NLS_PRESERVE_CASE_LABEL, isChecked: false, })); diff --git a/src/vs/editor/contrib/find/images/preserve-case-dark.svg b/src/vs/editor/contrib/find/images/preserve-case-dark.svg deleted file mode 100644 index ae540172027..00000000000 --- a/src/vs/editor/contrib/find/images/preserve-case-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/preserve-case.svg b/src/vs/editor/contrib/find/images/preserve-case.svg deleted file mode 100644 index 1f3b1a2c57e..00000000000 --- a/src/vs/editor/contrib/find/images/preserve-case.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 049e4ca16d3a2d3b9116d79e3ed295910c0e2ed2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 24 Jul 2019 23:09:36 -0700 Subject: [PATCH 023/111] Mark `addMissingAwait` as a preferred fix --- extensions/typescript-language-features/src/features/quickFix.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/typescript-language-features/src/features/quickFix.ts b/extensions/typescript-language-features/src/features/quickFix.ts index 8972df52185..6ce9f199704 100644 --- a/extensions/typescript-language-features/src/features/quickFix.ts +++ b/extensions/typescript-language-features/src/features/quickFix.ts @@ -314,6 +314,7 @@ const preferredFixes = new Set([ 'forgottenThisPropertyAccess', 'spelling', 'unusedIdentifier', + 'addMissingAwait', ]); function isPreferredFix(tsAction: Proto.CodeFixAction): boolean { return preferredFixes.has(tsAction.fixName); From 8d752d880d7151efb7b52400df74028321af6a7d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 25 Jul 2019 09:50:17 +0200 Subject: [PATCH 024/111] update references viewlet to 0.0.29 --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index f044a0e5384..a3483f451e2 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.28", + "version": "0.0.29", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", From 67814cc6b11dad00ec264c1874f5e7b8bd4923b3 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 25 Jul 2019 10:10:15 +0200 Subject: [PATCH 025/111] Fixes #74369 --- .../wordOperations/test/wordOperations.test.ts | 16 ++++++++++++++++ .../contrib/wordOperations/wordOperations.ts | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts b/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts index 1cae3b38fe6..98c22c721ef 100644 --- a/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts +++ b/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts @@ -137,6 +137,22 @@ suite('WordOperations', () => { assert.deepEqual(actual, EXPECTED); }); + test('cursorWordLeftSelect - issue #74369: cursorWordLeft and cursorWordLeftSelect do not behave consistently', () => { + const EXPECTED = [ + '|this.|is.|a.|test', + ].join('\n'); + const [text,] = deserializePipePositions(EXPECTED); + const actualStops = testRepeatedActionAndExtractPositions( + text, + new Position(1, 15), + ed => cursorWordLeft(ed, true), + ed => ed.getPosition()!, + ed => ed.getPosition()!.equals(new Position(1, 1)) + ); + const actual = serializePipePositions(text, actualStops); + assert.deepEqual(actual, EXPECTED); + }); + test('cursorWordStartLeft', () => { // This is the behaviour observed in Visual Studio, please do not touch test const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n'); diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index 282a4e05ac1..dc4e111f962 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -163,7 +163,7 @@ export class CursorWordLeftSelect extends WordLeftCommand { constructor() { super({ inSelectionMode: true, - wordNavigationType: WordNavigationType.WordStart, + wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeftSelect', precondition: undefined }); From a4fd7f28ca43365a64146bf95dccbcabcb4d75a1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Jul 2019 10:32:59 +0200 Subject: [PATCH 026/111] team settings --- .vscode/settings.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fa04b1ee95..1a760bdda6b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,6 @@ "git.ignoreLimitWarning": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" - } -} + }, + "files.insertFinalNewline": true +} \ No newline at end of file From c8c23e39639d336cdc542d6193e98f64faee467a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Jul 2019 10:34:18 +0200 Subject: [PATCH 027/111] fixes #77918 --- tslint.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 3ff7147730b..155bd9a4115 100644 --- a/tslint.json +++ b/tslint.json @@ -515,6 +515,13 @@ "**/vs/**" ] }, + { + "target": "**/vs/workbench/contrib/extensions/browser/**", + "restrictions": [ + "semver-umd", + "**/vs/**" + ] + }, { "target": "**/vs/code/node/**", "restrictions": [ @@ -563,7 +570,11 @@ ] }, { - "target": "**/{node,electron-browser,electron-main,extensions}/**", + "target": "**/{node,electron-browser,electron-main}/**", + "restrictions": "**/*" + }, + { + "target": "**/extensions/**", "restrictions": "**/*" }, { From 18da64f949be4d291de23940b45a9ee33beb5fa1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Jul 2019 10:45:22 +0200 Subject: [PATCH 028/111] stop pushing master --- build/azure-pipelines/distro-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index 4057894f025..62ee67ad1c6 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -31,12 +31,12 @@ steps: git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" git fetch distro - # Push master branch into master and oss/master - git push distro origin/master:refs/heads/master origin/master:refs/heads/oss/master + # Push master branch into oss/master + git push distro origin/master:refs/heads/oss/master # Push every release branch into oss/release git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro git merge $(node -p "require('./package.json').distro") - displayName: Sync & Merge Distro \ No newline at end of file + displayName: Sync & Merge Distro From 5dfd889f8367d3d323db6ac9b988dc3cc9bef3c9 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 25 Jul 2019 11:27:36 +0200 Subject: [PATCH 029/111] Fixes #73437 --- src/vs/editor/browser/controller/mouseTarget.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 8d69b3dffbf..9a37d512035 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -407,7 +407,12 @@ class HitTestRequest extends BareHitTestRequest { } public fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget { - return new MouseTarget(this.target, type, this.mouseColumn, position, range, detail); + let mouseColumn = this.mouseColumn; + if (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) { + // Most likely, the line contains foreign decorations... + mouseColumn = position.column; + } + return new MouseTarget(this.target, type, mouseColumn, position, range, detail); } public withTarget(target: Element | null): HitTestRequest { From b35a0eea42b5d5b42cef8bf2244e19c5b5d3a735 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 25 Jul 2019 11:26:55 +0200 Subject: [PATCH 030/111] filter commands that start with an underscore, #1431 --- src/vs/workbench/api/common/extHostCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index f2456398c95..4cef83323b0 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -50,7 +50,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(), onLastListenerRemove: () => this._proxy.$unregisterCommandListener(), }); - this.onDidExecuteCommand = this._onDidExecuteCommand.event; + this.onDidExecuteCommand = Event.filter(this._onDidExecuteCommand.event, e => e.command[0] !== '_'); // filter 'private' commands this._logService = logService; this._converter = new CommandsConverter(this); this._argumentProcessors = [ From f8f0e03ea55b79aa62cbed940e234180ab8cdd1c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 25 Jul 2019 11:28:05 +0200 Subject: [PATCH 031/111] tweak name for internal delegation command --- src/vs/workbench/api/common/extHostCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index 4cef83323b0..19e4d5655f1 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -222,7 +222,7 @@ export class CommandsConverter { // --- conversion between internal and api commands constructor(commands: ExtHostCommands) { - this._delegatingCommandId = `_internal_command_delegation_${Date.now()}`; + this._delegatingCommandId = `_vscode_delegate_cmd_${Date.now().toString(36)}`; this._commands = commands; this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this); } From 808a11ae4360d60072f930e158ac5607040e8a8d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 25 Jul 2019 11:30:30 +0200 Subject: [PATCH 032/111] Sorry, the bot is never using the correct labels for me --- .github/classifier.yml | 159 ++++++++++++++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 33 deletions(-) diff --git a/.github/classifier.yml b/.github/classifier.yml index e7a79f7b64c..29f9fa41f52 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -18,40 +18,127 @@ assignees: [ weinand ], assignLabel: false }, - diff-editor: [], - dropdown: [], - editor: { + diff-editor: : { + assignees: [], + assignLabel: false + }, + dropdown: [], + editor: : { + assignees: [], + assignLabel: false + }, + editor-1000-limit: : { + assignees: [], + assignLabel: false + }, + editor-autoclosing: : { + assignees: [], + assignLabel: false + }, + editor-autoindent: : { + assignees: [], + assignLabel: false + }, + editor-brackets: : { + assignees: [], + assignLabel: false + }, + editor-clipboard: : { + assignees: [], + assignLabel: false + }, + editor-code-actions: : { + assignees: [], + assignLabel: false + }, + editor-code-lens: : { + assignees: [], + assignLabel: false + }, + editor-color-picker: : { + assignees: [], + assignLabel: false + }, + editor-colors: : { + assignees: [], + assignLabel: false + }, + editor-columnselect: : { + assignees: [], + assignLabel: false + }, + editor-commands: : { + assignees: [], + assignLabel: false + }, + editor-contrib: : { + assignees: [], + assignLabel: false + }, + editor-drag-and-drop: : { + assignees: [], + assignLabel: false + }, + editor-find: : { + assignees: [], + assignLabel: false + }, + editor-folding: : { + assignees: [], + assignLabel: false + }, + editor-hover: : { + assignees: [], + assignLabel: false + }, + editor-ime: : { + assignees: [], + assignLabel: false + }, + editor-input: : { + assignees: [], + assignLabel: false + }, + editor-ligatures: : { + assignees: [], + assignLabel: false + }, + editor-links: : { + assignees: [], + assignLabel: false + }, + editor-minimap: : { + assignees: [], + assignLabel: false + }, + editor-multicursor: : { + assignees: [], + assignLabel: false + }, + editor-parameter-hints: : { + assignees: [], + assignLabel: false + }, + editor-rendering: : { + assignees: [], + assignLabel: false + }, + editor-smooth: : { + assignees: [], + assignLabel: false + }, + editor-symbols: : { + assignees: [], + assignLabel: false + }, + editor-textbuffer: : { + assignees: [], + assignLabel: false + }, + editor-wrapping: : { assignees: [], assignLabel: false }, - editor-1000-limit: [], - editor-autoclosing: [], - editor-autoindent: [], - editor-brackets: [], - editor-clipboard: [], - editor-code-actions: [], - editor-code-lens: [], - editor-color-picker: [], - editor-colors: [], - editor-columnselect: [], - editor-commands: [], - editor-contrib: [], - editor-drag-and-drop: [], - editor-find: [], - editor-folding: [], - editor-hover: [], - editor-ime: [], - editor-input: [], - editor-ligatures: [], - editor-links: [], - editor-minimap: [], - editor-multicursor: [], - editor-parameter-hints: [], - editor-rendering: [], - editor-smooth: [], - editor-symbols: [], - editor-textbuffer: [], - editor-wrapping: [], emmet: [ octref ], error-list: [], explorer-custom: [], @@ -87,8 +174,14 @@ issue-reporter: [ RMacfarlane ], javascript: [ mjbvz ], json: [], - keyboard-layout: [], - keybindings: [], + keyboard-layout: : { + assignees: [], + assignLabel: false + }, + keybindings: : { + assignees: [], + assignLabel: false + }, keybindings-editor: [], lang-diagnostics: [], languages basic: [], From 30eaedc93ac1fdad81a6006c76cfed70a9884525 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Thu, 25 Jul 2019 14:47:35 +0200 Subject: [PATCH 033/111] add error message if input section is missing; fixes #76558 --- .../browser/configurationResolverService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index bcf4b31cef9..f406a3e0d63 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -227,6 +227,10 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR */ private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { + if (!inputInfos) { + return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); + } + // find info for the given input variable const info = inputInfos.filter(item => item.id === variable).pop(); if (info) { @@ -307,4 +311,4 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi } } -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); \ No newline at end of file +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); From 23d8322547e06f1beaea596c508a1de19e843a54 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Jul 2019 15:38:03 +0200 Subject: [PATCH 034/111] introduce git APIState fixes #77787 --- extensions/git/src/api/api1.ts | 10 ++++++++- extensions/git/src/api/git.d.ts | 4 ++++ extensions/git/src/model.ts | 39 +++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index 25742babc15..a4fd677db27 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -5,7 +5,7 @@ import { Model } from '../model'; import { Repository as BaseRepository, Resource } from '../repository'; -import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions } from './git'; +import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git'; import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode'; import { mapEvent } from '../util'; @@ -214,6 +214,14 @@ export class ApiImpl implements API { readonly git = new ApiGit(this._model); + get state(): APIState { + return this._model.state; + } + + get onDidChangeState(): Event { + return this._model.onDidChangeState; + } + get onDidOpenRepository(): Event { return mapEvent(this._model.onDidOpenRepository, r => new ApiRepository(r)); } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 9444ea1fada..21195974fc1 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -176,7 +176,11 @@ export interface Repository { log(options?: LogOptions): Promise; } +export type APIState = 'uninitialized' | 'initialized'; + export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; readonly git: Git; readonly repositories: Repository[]; readonly onDidOpenRepository: Event; diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index a04dc33c8be..c410dde86bd 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -12,7 +12,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as nls from 'vscode-nls'; import { fromGitUri } from './uri'; -import { GitErrorCodes } from './api/git'; +import { GitErrorCodes, APIState as State } from './api/git'; const localize = nls.loadMessageBundle(); @@ -63,15 +63,22 @@ export class Model { private possibleGitRepositoryPaths = new Set(); + private _onDidChangeState = new EventEmitter(); + readonly onDidChangeState = this._onDidChangeState.event; + + private _state: State = 'uninitialized'; + get state(): State { return this._state; } + + setState(state: State): void { + this._state = state; + this._onDidChangeState.fire(state); + } + private disposables: Disposable[] = []; constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); - this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); - window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); - this.onDidChangeVisibleTextEditors(window.visibleTextEditors); - workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); const fsWatcher = workspace.createFileSystemWatcher('**'); @@ -82,7 +89,15 @@ export class Model { const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); - this.scanWorkspaceFolders(); + this.doInitialScan().finally(() => this.setState('initialized')); + } + + private async doInitialScan(): Promise { + await Promise.all([ + this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }), + this.onDidChangeVisibleTextEditors(window.visibleTextEditors), + this.scanWorkspaceFolders() + ]); } /** @@ -157,8 +172,8 @@ export class Model { .filter(r => !activeRepositories.has(r!.repository)) .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; - possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); + await Promise.all(possibleRepositoryFolders.map(p => this.openRepository(p.uri.fsPath))); } private onDidChangeConfiguration(): void { @@ -175,7 +190,7 @@ export class Model { openRepositoriesToDispose.forEach(r => r.dispose()); } - private onDidChangeVisibleTextEditors(editors: TextEditor[]): void { + private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise { const config = workspace.getConfiguration('git'); const autoRepositoryDetection = config.get('autoRepositoryDetection'); @@ -183,7 +198,7 @@ export class Model { return; } - editors.forEach(editor => { + await Promise.all(editors.map(async editor => { const uri = editor.document.uri; if (uri.scheme !== 'file') { @@ -196,8 +211,8 @@ export class Model { return; } - this.openRepository(path.dirname(uri.fsPath)); - }); + await this.openRepository(path.dirname(uri.fsPath)); + })); } @sequentialize @@ -421,4 +436,4 @@ export class Model { this.possibleGitRepositoryPaths.clear(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} From c8e219f1a1bc770df87f9d9444b26979aec00e64 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 25 Jul 2019 15:47:20 +0200 Subject: [PATCH 035/111] up fuzzy score limit to 128, #74133 --- src/vs/base/common/filters.ts | 2 +- src/vs/base/test/common/filters.test.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 645937c3375..d01c32668ca 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -414,7 +414,7 @@ export function createMatches(score: undefined | FuzzyScore): IMatch[] { return res; } -const _maxLen = 53; +const _maxLen = 128; function initTable() { const table: number[][] = []; diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index b93e58cfc0a..25cc50d5780 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -470,4 +470,19 @@ suite('Filters', () => { test('List highlight filter: Not all characters from match are highlighterd #66923', () => { assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore); }); + + test('Autocompletion is matched against truncated filterText to 54 characters #74133', () => { + assertMatches( + 'foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', + fuzzyScore + ); + assertMatches( + 'foo', + 'Gffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + undefined, + fuzzyScore + ); + }); }); From a1ff90cfa2f1ceb482313922f24cdf25d41ff03c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 25 Jul 2019 15:52:17 +0200 Subject: [PATCH 036/111] Also add snippet to default config, #71208 --- src/vs/editor/common/config/commonEditorConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 889384a1748..5d1818712b0 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -696,7 +696,7 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.suggest.filteredTypes': { type: 'object', - default: { keyword: true }, + default: { keyword: true, snippet: true }, markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), properties: { method: { From c09ffefaf9537459fc4ed27f443f329271eed6b7 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 25 Jul 2019 08:55:19 -0700 Subject: [PATCH 037/111] Upgrade VS Code telemetry extractor (#77937) --- build/package.json | 2 +- build/yarn.lock | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build/package.json b/build/package.json index e292f7a7e41..daaef30be96 100644 --- a/build/package.json +++ b/build/package.json @@ -51,4 +51,4 @@ "postinstall": "npm run compile", "npmCheckJs": "tsc --noEmit" } -} \ No newline at end of file +} diff --git a/build/yarn.lock b/build/yarn.lock index 8f675d1fef0..bfc2633700a 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -1257,7 +1257,12 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= From 9702c08132b3545946f58cac93c53e43a0879864 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 25 Jul 2019 08:59:38 -0700 Subject: [PATCH 038/111] Upgrade telemetry extractor (#77938) * Upgrade VS Code telemetry extractor * Update telemetry extractor package --- build/package.json | 2 +- build/yarn.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/package.json b/build/package.json index daaef30be96..2a1c775c736 100644 --- a/build/package.json +++ b/build/package.json @@ -42,7 +42,7 @@ "tslint": "^5.9.1", "typescript": "3.5.2", "vsce": "1.48.0", - "vscode-telemetry-extractor": "1.4.3", + "vscode-telemetry-extractor": "^1.5.1", "xml2js": "^0.4.17" }, "scripts": { diff --git a/build/yarn.lock b/build/yarn.lock index bfc2633700a..7d00ac18872 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2124,7 +2124,7 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -ts-morph@^3.1.2: +ts-morph@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-3.1.3.tgz#bbfa1d14481ee23bdd1c030340ccf4a243cfc844" integrity sha512-CwjgyJTtd3f8vBi7Vr0IOgdOY6Wi/Tq0MhieXOE2B5ns5WWRD7BwMNHtv+ZufKI/S2U/lMrh+Q3bOauE4tsv2g== @@ -2313,19 +2313,19 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" -vscode-ripgrep@^1.4.0: +vscode-ripgrep@^1.5.5: version "1.5.5" resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== -vscode-telemetry-extractor@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.4.3.tgz#e4af380beb4e2a63d6e4fa819b25ba7ef6dc4a10" - integrity sha512-OFklPErZnUBjrKte3hg+irQXue5rzgz4qnvE8kdaOnW1E/wynHUEXW9t5vF5q0hu2lodpGMkybwLkSjONZVzvg== +vscode-telemetry-extractor@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.5.1.tgz#67249e4ca9c65a21800ca53880732f8cef98d0fa" + integrity sha512-B5SnEdRiDrI4o6NMG9iHmengoaW1rxUQmS/sCaripgnchm+P79JURmKxhfXr5eRo4Mr1QSenFT/SDNaEop7aoQ== dependencies: command-line-args "^5.1.1" - ts-morph "^3.1.2" - vscode-ripgrep "^1.4.0" + ts-morph "^3.1.3" + vscode-ripgrep "^1.5.5" vso-node-api@6.1.2-preview: version "6.1.2-preview" From 4f9575631bfa56834e8c3bca710fefd7486d39b7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 08:30:09 -0700 Subject: [PATCH 039/111] Make start and shutdown mandatory Part of #77160 --- src/vs/vscode.proposed.d.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index d86d071f6f4..430967c999e 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -925,7 +925,7 @@ declare module 'vscode' { //#endregion - //#region Terminal virtual process + //#region Terminal extension pty export namespace window { /** @@ -1021,6 +1021,19 @@ declare module 'vscode' { */ onDidExit?: Event; + /** + * Implement to handle when the terminal is ready to start firing events. + * + * @param initialDimensions The dimensions of the terminal, this will be undefined if the + * terminal panel has not been opened before this is called. + */ + start(initialDimensions: TerminalDimensions | undefined): void; + + /** + * Implement to handle when the terminal shuts down by an act of the user. + */ + shutdown(): void; + /** * Implement to handle keystrokes in the terminal or when an extension calls * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their @@ -1050,19 +1063,6 @@ declare module 'vscode' { * @param dimensions The new dimensions. */ setDimensions?(dimensions: TerminalDimensions): void; - - /** - * Implement to handle when the terminal shuts down by an act of the user. - */ - shutdown?(): void; - - /** - * Implement to handle when the terminal is ready to start firing events. - * - * @param initialDimensions The dimensions of the terminal, this will be undefined if the - * terminal panel has not been opened before this is called. - */ - start?(initialDimensions: TerminalDimensions | undefined): void; } //#endregion From 909ab9d1011b177ba4f3512cda4df69ffecbb9ee Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 09:07:18 -0700 Subject: [PATCH 040/111] Fix compile --- .../src/singlefolder-tests/terminal.test.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 13b9666dbfe..63e39fdd2e4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -265,7 +265,9 @@ suite('window namespace tests', () => { term.dispose(); }); const virtualProcess: TerminalVirtualProcess = { - onDidWrite: new EventEmitter().event + onDidWrite: new EventEmitter().event, + start: () => {}, + shutdown: () => {} }; window.createTerminal({ name: 'c', virtualProcess }); }); @@ -291,7 +293,8 @@ suite('window namespace tests', () => { const writeEmitter = new EventEmitter(); const virtualProcess: TerminalVirtualProcess = { onDidWrite: writeEmitter.event, - start: () => startResolve() + start: () => startResolve(), + shutdown: () => {} }; const terminal = window.createTerminal({ name: 'foo', virtualProcess }); }); @@ -311,7 +314,8 @@ suite('window namespace tests', () => { done(); }); terminal.dispose(); - } + }, + shutdown: () => {} }; const terminal = window.createTerminal({ name: 'foo', virtualProcess }); }); @@ -338,7 +342,9 @@ suite('window namespace tests', () => { const overrideDimensionsEmitter = new EventEmitter(); const virtualProcess: TerminalVirtualProcess = { onDidWrite: writeEmitter.event, - onDidOverrideDimensions: overrideDimensionsEmitter.event + onDidOverrideDimensions: overrideDimensionsEmitter.event, + start: () => {}, + shutdown: () => {} }; const terminal = window.createTerminal({ name: 'foo', virtualProcess }); }); From bdd49f042d63ce5636c60361bf3a5c40905137f6 Mon Sep 17 00:00:00 2001 From: Tomas Kovar Date: Thu, 25 Jul 2019 18:27:41 +0200 Subject: [PATCH 041/111] Add sk to locales than need region --- src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 7442639d505..da109a496f4 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -106,6 +106,7 @@ function _getLangEnvVariable(locale?: string) { ko: 'KR', pl: 'PL', ru: 'RU', + sk: 'SK', zh: 'CN' }; if (parts[0] in languageVariants) { From dba0ee0392a0a7480e5026e1da8bba21ab4476b4 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 25 Jul 2019 18:28:36 +0200 Subject: [PATCH 042/111] serialized grid should remember view visibility and cached sizes fixes #77884 --- src/vs/base/browser/ui/grid/grid.ts | 64 +++-- src/vs/base/browser/ui/grid/gridview.ts | 30 ++- src/vs/base/browser/ui/splitview/splitview.ts | 46 +++- src/vs/base/test/browser/ui/grid/grid.test.ts | 227 ++++++++++++++++++ 4 files changed, 339 insertions(+), 28 deletions(-) diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 0fc6d389e81..08090875642 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -9,6 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize } from './gridview'; import { Event } from 'vs/base/common/event'; +import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; export { Orientation, Sizing as GridViewSizing } from './gridview'; @@ -31,6 +32,7 @@ function oppositeDirection(direction: Direction): Direction { export interface GridLeafNode { readonly view: T; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -173,16 +175,23 @@ function getGridLocation(element: HTMLElement): number[] { return [...getGridLocation(ancestor), index]; } -export const enum Sizing { - Distribute = 'distribute', - Split = 'split' +export type DistributeSizing = { type: 'distribute' }; +export type SplitSizing = { type: 'split' }; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; + +export namespace Sizing { + export const Distribute: DistributeSizing = { type: 'distribute' }; + export const Split: SplitSizing = { type: 'split' }; + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export interface IGridStyles extends IGridViewStyles { } export interface IGridOptions { - styles?: IGridStyles; - proportionalLayout?: boolean; + readonly styles?: IGridStyles; + readonly proportionalLayout?: boolean; + readonly firstViewVisibleCachedSize?: number; } export class Grid extends Disposable { @@ -210,7 +219,11 @@ export class Grid extends Disposable { this._register(this.gridview.onDidSashReset(this.doResetViewSize, this)); - this._addView(view, 0, [0]); + const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' + ? GridViewSizing.Invisible(options.firstViewVisibleCachedSize) + : 0; + + this._addView(view, size, [0]); } style(styles: IGridStyles): void { @@ -241,10 +254,12 @@ export class Grid extends Disposable { let viewSize: number | GridViewSizing; - if (size === Sizing.Split) { + if (typeof size === 'number') { + viewSize = size; + } else if (size.type === 'split') { const [, index] = tail(referenceLocation); viewSize = GridViewSizing.Split(index); - } else if (size === Sizing.Distribute) { + } else if (size.type === 'distribute') { viewSize = GridViewSizing.Distribute; } else { viewSize = size; @@ -264,7 +279,7 @@ export class Grid extends Disposable { } const location = this.getViewLocation(view); - this.gridview.removeView(location, sizing === Sizing.Distribute ? GridViewSizing.Distribute : undefined); + this.gridview.removeView(location, (sizing && sizing.type === 'distribute') ? GridViewSizing.Distribute : undefined); this.views.delete(view); } @@ -379,6 +394,7 @@ export interface ISerializedLeafNode { type: 'leaf'; data: object | null; size: number; + visible?: boolean; } export interface ISerializedBranchNode { @@ -402,6 +418,10 @@ export class SerializableGrid extends Grid { const size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height; if (!isGridBranchNode(node)) { + if (typeof node.cachedVisibleSize === 'number') { + return { type: 'leaf', data: node.view.toJSON(), size: node.cachedVisibleSize, visible: false }; + } + return { type: 'leaf', data: node.view.toJSON(), size }; } @@ -426,25 +446,26 @@ export class SerializableGrid extends Grid { throw new Error('Invalid JSON: \'size\' property of node must be a number.'); } + const childSize = child.type === 'leaf' && child.visible === false ? 0 : child.size; const childBox: Box = orientation === Orientation.HORIZONTAL - ? { top: box.top, left: box.left + offset, width: child.size, height: box.height } - : { top: box.top + offset, left: box.left, width: box.width, height: child.size }; + ? { top: box.top, left: box.left + offset, width: childSize, height: box.height } + : { top: box.top + offset, left: box.left, width: box.width, height: childSize }; children.push(SerializableGrid.deserializeNode(child, orthogonal(orientation), childBox, deserializer)); - offset += child.size; + offset += childSize; } return { children, box }; } else if (json.type === 'leaf') { const view: T = deserializer.fromJSON(json.data); - return { view, box }; + return { view, box, cachedVisibleSize: json.visible === false ? json.size : undefined }; } throw new Error('Invalid JSON: \'type\' property must be either \'branch\' or \'leaf\'.'); } - private static getFirstLeaf(node: GridNode): GridLeafNode | undefined { + private static getFirstLeaf(node: GridNode): GridLeafNode { if (!isGridBranchNode(node)) { return node; } @@ -473,6 +494,10 @@ export class SerializableGrid extends Grid { throw new Error('Invalid serialized state, first leaf not found'); } + if (typeof firstLeaf.cachedVisibleSize === 'number') { + options = { ...options, firstViewVisibleCachedSize: firstLeaf.cachedVisibleSize }; + } + const result = new SerializableGrid(firstLeaf.view, options); result.orientation = orientation; result.restoreViews(firstLeaf.view, orientation, root); @@ -522,13 +547,16 @@ export class SerializableGrid extends Grid { const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c)); for (let i = 1; i < firstLeaves.length; i++) { - const size = orientation === Orientation.VERTICAL ? firstLeaves[i]!.box.height : firstLeaves[i]!.box.width; - this.addView(firstLeaves[i]!.view, size, referenceView, direction); - referenceView = firstLeaves[i]!.view; + const node = firstLeaves[i]; + const size: number | InvisibleSizing = typeof node.cachedVisibleSize === 'number' + ? GridViewSizing.Invisible(node.cachedVisibleSize) + : (orientation === Orientation.VERTICAL ? node.box.height : node.box.width); + this.addView(node.view, size, referenceView, direction); + referenceView = node.view; } for (let i = 0; i < node.children.length; i++) { - this.restoreViews(firstLeaves[i]!.view, orthogonal(orientation), node.children[i]); + this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]); } } diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index 8ce22799e56..3e05e4a9499 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -47,6 +47,7 @@ export interface Box { export interface GridLeafNode { readonly view: IView; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -343,6 +344,14 @@ class BranchNode implements ISplitView, IDisposable { this.splitview.setViewVisible(index, visible); } + getChildCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.getViewCachedVisibleSize(index); + } + private onDidChildrenChange(): void { const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); this.childrenChangeDisposable.dispose(); @@ -424,6 +433,9 @@ class LeafNode implements ISplitView, IDisposable { private _size: number = 0; get size(): number { return this._size; } + private _cachedVisibleSize: number | undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + private _orthogonalSize: number; get orthogonalSize(): number { return this._orthogonalSize; } @@ -528,6 +540,12 @@ class LeafNode implements ISplitView, IDisposable { } setVisible(visible: boolean): void { + if (visible) { + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this._size; + } + if (this.view.setVisible) { this.view.setVisible(visible); } @@ -658,6 +676,14 @@ export class GridView implements IDisposable { } else { const [, grandParent] = tail(pathToParent); const [, parentIndex] = tail(rest); + + let newSiblingSize: number | Sizing = 0; + + const newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex); + if (typeof newSiblingCachedVisibleSize === 'number') { + newSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize); + } + grandParent.removeChild(parentIndex); const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize); @@ -665,7 +691,7 @@ export class GridView implements IDisposable { newParent.orthogonalLayout(parent.orthogonalSize); const newSibling = new LeafNode(parent.view, grandParent.orientation, parent.size); - newParent.addChild(newSibling, 0, 0); + newParent.addChild(newSibling, newSiblingSize, 0); if (typeof size !== 'number' && size.type === 'split') { size = Sizing.Split(0); @@ -883,7 +909,7 @@ export class GridView implements IDisposable { private _getViews(node: Node, orientation: Orientation, box: Box): GridNode { if (node instanceof LeafNode) { - return { view: node.view, box }; + return { view: node.view, box, cachedVisibleSize: node.cachedVisibleSize }; } const children: GridNode[] = []; diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 7599cc6808d..171a44837c4 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -59,8 +59,11 @@ interface ISashEvent { alt: boolean; } +type ViewItemSize = number | { cachedVisibleSize: number }; + abstract class ViewItem { + private _size: number; set size(size: number) { this._size = size; } @@ -69,10 +72,11 @@ abstract class ViewItem { return this._size; } - private cachedSize: number | undefined = undefined; + private _cachedVisibleSize: number | undefined = undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } get visible(): boolean { - return typeof this.cachedSize === 'undefined'; + return typeof this._cachedVisibleSize === 'undefined'; } set visible(visible: boolean) { @@ -81,10 +85,10 @@ abstract class ViewItem { } if (visible) { - this.size = this.cachedSize!; - this.cachedSize = undefined; + this.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize); + this._cachedVisibleSize = undefined; } else { - this.cachedSize = this.size; + this._cachedVisibleSize = this.size; this.size = 0; } @@ -104,7 +108,20 @@ abstract class ViewItem { get priority(): LayoutPriority | undefined { return this.view.priority; } get snap(): boolean { return !!this.view.snap; } - constructor(protected container: HTMLElement, private view: IView, private _size: number, private disposable: IDisposable) { + constructor( + protected container: HTMLElement, + private view: IView, + size: ViewItemSize, + private disposable: IDisposable + ) { + if (typeof size === 'number') { + this._size = size; + this._cachedVisibleSize = undefined; + } else { + this._size = 0; + this._cachedVisibleSize = size.cachedVisibleSize; + } + dom.addClass(container, 'visible'); } @@ -166,11 +183,13 @@ enum State { export type DistributeSizing = { type: 'distribute' }; export type SplitSizing = { type: 'split', index: number }; -export type Sizing = DistributeSizing | SplitSizing; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; export namespace Sizing { export const Distribute: DistributeSizing = { type: 'distribute' }; export function Split(index: number): SplitSizing { return { type: 'split', index }; } + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export class SplitView extends Disposable { @@ -279,12 +298,14 @@ export class SplitView extends Disposable { const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container)); const disposable = combinedDisposable(onChangeDisposable, containerDisposable); - let viewSize: number; + let viewSize: ViewItemSize; if (typeof size === 'number') { viewSize = size; } else if (size.type === 'split') { viewSize = this.getViewSize(size.index) / 2; + } else if (size.type === 'invisible') { + viewSize = { cachedVisibleSize: size.cachedVisibleSize }; } else { viewSize = view.minimumSize; } @@ -420,6 +441,15 @@ export class SplitView extends Disposable { this.layoutViews(); } + getViewCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + return viewItem.cachedVisibleSize; + } + layout(size: number): void { const previousSize = Math.max(this.size, this.contentSize); this.size = size; diff --git a/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts index 7385b3ca4d6..092f3007082 100644 --- a/src/vs/base/test/browser/ui/grid/grid.test.ts +++ b/src/vs/base/test/browser/ui/grid/grid.test.ts @@ -8,6 +8,15 @@ import { Direction, getRelativeLocation, Orientation, SerializableGrid, ISeriali import { TestView, nodesToArrays } from './util'; import { deepClone } from 'vs/base/common/objects'; +// Simple example: +// +-----+---------------+ +// | 4 | 2 | +// +-----+---------+-----+ +// | 1 | | +// +---------------+ 3 | +// | 5 | | +// +---------------+-----+ + suite('Grid', function () { let container: HTMLElement; @@ -798,4 +807,222 @@ suite('SerializableGrid', function () { height: 1 }); }); + + test('serialize should store visibility and previous size', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view5, false); + + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 0]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200 }, + { type: 'leaf', data: { name: 'view2' }, size: 600 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 400 }, + { type: 'leaf', data: { name: 'view5' }, size: 100, visible: false } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 400]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 0]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), false); + + grid2.setViewVisible(view5Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); + + test('serialize should store visibility and previous size even for first leaf', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view4, false); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [0, 200]); + assert.deepEqual(view5.size, [600, 100]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200, visible: false }, + { type: 'leaf', data: { name: 'view2' }, size: 800 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 300 }, + { type: 'leaf', data: { name: 'view5' }, size: 100 } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [800, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [0, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), false); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + + grid2.setViewVisible(view4Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); }); From 8968c83198bad8bb045b5fa7591e4f1668f124f6 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 25 Jul 2019 17:36:56 +0200 Subject: [PATCH 043/111] remoteAuthority context key: set to disconnected to avoid matches --- .../contrib/remote/electron-browser/remote.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 7b6f13e67ef..9f861987bc4 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -119,7 +119,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc if (this.disconnected !== isDisconnected) { this.disconnected = isDisconnected; RemoteConnectionState.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected' : 'connected'); - Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? '' : this.remoteAuthority || ''); + Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? '' : this.remoteAuthority || `disconnected/${this.remoteAuthority}`); this.updateWindowIndicator(); } } From 89afd3fe5e5940dea589ad77856fb4e872d9766c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 25 Jul 2019 17:38:36 +0200 Subject: [PATCH 044/111] update html service. FIxes #77792 --- .../server/package.json | 6 ++--- .../server/src/utils/documentContext.ts | 7 ++++- .../html-language-features/server/yarn.lock | 27 ++++++++++--------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index e97a42ab0a6..087fbaec82b 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,12 +9,12 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.2", - "vscode-html-languageservice": "^3.0.0", + "vscode-css-languageservice": "^4.0.3-next.0", + "vscode-html-languageservice": "^3.0.3", "vscode-languageserver": "^5.3.0-next.8", "vscode-languageserver-types": "3.15.0-next.2", "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.1" + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", diff --git a/extensions/html-language-features/server/src/utils/documentContext.ts b/extensions/html-language-features/server/src/utils/documentContext.ts index bfd26d1aa8d..71f9a3591be 100644 --- a/extensions/html-language-features/server/src/utils/documentContext.ts +++ b/extensions/html-language-features/server/src/utils/documentContext.ts @@ -32,7 +32,12 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp } } } - return url.resolve(base, ref); + try { + return url.resolve(base, ref); + } catch { + return undefined; + } + }, }; } diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 8c532e3136f..c386ce0bbb9 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -229,22 +229,23 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2.tgz#7496e538b0c151feac16d5888cc0b1b104f4c736" - integrity sha512-pTnfXbsME3pl+yDfhUp/mtvPyIJk0Le4zqJxDn56s9GY9LqY0RmkSEh0oHH6D0HXR3Ni6wKosIaqu8a2G0+jdw== +vscode-css-languageservice@^4.0.3-next.0: + version "4.0.3-next.0" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.0.tgz#ba96894cf2a0c86c744a1274590f27e55ea60f58" + integrity sha512-ku58Y5jDFNfDicv2AAhgu1edgfGcRZPwlKu6EBK2ck/O/Vco7Zy64FDoClJghcYBhJiDs7sy2q/UtQD0IoGbRw== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" + vscode-uri "^2.0.3" -vscode-html-languageservice@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.0.tgz#b9649aa0713d68665d7546bd3772dd10e4dbe200" - integrity sha512-AgNyjaYrmgundh5gXP0bqCLeLdfUTyvNafF1moNwYdqeNh6DIpMG6RjwYwgtNChXSsVGXnaHiwGMtAUwMxkQUQ== +vscode-html-languageservice@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.3.tgz#0aeae18a59000e317447ea34965f72680a2140ef" + integrity sha512-U+upM3gHp3HaF3wXAnUduA6IDKcz6frWS/dTAju3cZVIyZwOLBBFElQVlLH0ycHyMzqUFrjvdv+kEyPAEWfQ/g== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" - vscode-uri "^2.0.1" + vscode-uri "^2.0.3" vscode-jsonrpc@^4.1.0-next.2: version "4.1.0-next.2" @@ -288,10 +289,10 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== -vscode-uri@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" - integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== wrappy@1: version "1.0.2" From 81380bb822effd42006764f81ffaabeff4745009 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 25 Jul 2019 18:32:56 +0200 Subject: [PATCH 045/111] register selectionRangeProviders --- extensions/css-language-features/server/src/cssServerMain.ts | 3 ++- extensions/html-language-features/server/src/htmlServerMain.ts | 3 ++- extensions/json-language-features/server/src/jsonServerMain.ts | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index 884306d299a..f762bde09c4 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -140,7 +140,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { codeActionProvider: true, renameProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index 6eb8fc298fe..7ca71d16760 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -135,7 +135,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { signatureHelpProvider: { triggerCharacters: ['('] }, referencesProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 699e73a9c91..27e29a96764 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -154,7 +154,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { documentSymbolProvider: true, documentRangeFormattingProvider: false, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; From 3b5ee24ca3e3eaf12d730a5ac9dd72f3669aa954 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 25 Jul 2019 18:33:12 +0200 Subject: [PATCH 046/111] [json] update vscode-uri --- extensions/json-language-features/server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 061cb69249a..68e6a005537 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -17,7 +17,7 @@ "vscode-json-languageservice": "^3.3.0", "vscode-languageserver": "^5.3.0-next.8", "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.1" + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", From 9d8d0841292544241827a51d44aa88fbbde85cf2 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Thu, 25 Jul 2019 19:05:39 +0200 Subject: [PATCH 047/111] properly use default terminal for debug; fixes #77110 --- .../api/browser/mainThreadDebugService.ts | 6 +-- .../workbench/api/common/extHost.protocol.ts | 4 +- .../workbench/api/node/extHostDebugService.ts | 13 ++++--- .../browser/debugConfigurationManager.ts | 6 +-- .../workbench/contrib/debug/common/debug.ts | 11 +----- .../contrib/debug/common/debugger.ts | 5 +-- .../workbench/contrib/debug/node/terminals.ts | 38 ++++++++++--------- 7 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index 7386b69e611..85039369466 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -5,7 +5,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI as uri } from 'vs/base/common/uri'; -import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto @@ -71,8 +71,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config)); } - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { - return Promise.resolve(this._proxy.$runInTerminal(args, config)); + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { + return Promise.resolve(this._proxy.$runInTerminal(args)); } // RPC methods (MainThreadDebugServiceShape) diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index ad32f5f43f1..f8d565df56c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -40,7 +40,7 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import * as tasks from 'vs/workbench/api/common/shared/tasks'; import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; +import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; @@ -1245,7 +1245,7 @@ export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID; export interface ExtHostDebugServiceShape { $substituteVariables(folder: UriComponents | undefined, config: IConfig): Promise; - $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; $startDASession(handle: number, session: IDebugSessionDto): Promise; $stopDASession(handle: number): Promise; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index e5b2a445ec3..d9172447d73 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -20,7 +20,7 @@ import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstract import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; @@ -318,7 +318,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { // RPC methods (ExtHostDebugServiceShape) - public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { if (args.kind === 'integrated') { @@ -350,9 +350,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { terminal.show(); - return this._integratedTerminalInstance.processId.then(shellProcessId => { + return this._integratedTerminalInstance.processId.then(async shellProcessId => { + + const configProvider = await this._configurationService.getConfigProvider(); + const shell = this._terminalService.getDefaultShell(configProvider); + const command = prepareCommand(args, shell, configProvider); - const command = prepareCommand(args, config); terminal.sendText(command, true); return shellProcessId; @@ -361,7 +364,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else if (args.kind === 'external') { - runInExternalTerminal(args, config); + runInExternalTerminal(args, await this._configurationService.getConfigProvider()); } return Promise.resolve(undefined); } diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index 82be95aef9b..df8a68cbc67 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -21,7 +21,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, ITerminalSettings, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { Debugger } from 'vs/workbench/contrib/debug/common/debugger'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -108,10 +108,10 @@ export class ConfigurationManager implements IConfigurationManager { return Promise.resolve(config); } - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise { let tl = this.debugAdapterFactories.get(debugType); if (tl) { - return tl.runInTerminal(args, config); + return tl.runInTerminal(args); } return Promise.resolve(void 0); } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 363f6eeb346..1ac7b96593d 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -24,9 +24,7 @@ import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExte import { Registry } from 'vs/platform/registry/common/platform'; import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExternalTerminalSettings } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; export const VIEWLET_ID = 'workbench.view.debug'; export const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID); @@ -573,12 +571,7 @@ export interface IDebugAdapterTrackerFactory { } export interface ITerminalLauncher { - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; -} - -export interface ITerminalSettings { - external: IExternalTerminalSettings; - integrated: ITerminalConfiguration; + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface IConfigurationManager { @@ -623,7 +616,7 @@ export interface IConfigurationManager { createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined; substituteVariables(debugType: string, folder: IWorkspaceFolder | undefined, config: IConfig): Promise; - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface ILaunch { diff --git a/src/vs/workbench/contrib/debug/common/debugger.ts b/src/vs/workbench/contrib/debug/common/debugger.ts index 4034a6c9596..8f317ccc138 100644 --- a/src/vs/workbench/contrib/debug/common/debugger.ts +++ b/src/vs/workbench/contrib/debug/common/debugger.ts @@ -9,7 +9,7 @@ import * as objects from 'vs/base/common/objects'; import { isObject } from 'vs/base/common/types'; import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, ITerminalSettings, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import * as ConfigurationResolverUtils from 'vs/workbench/services/configurationResolver/common/configurationResolverUtils'; @@ -108,8 +108,7 @@ export class Debugger implements IDebugger { } runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { - const config = this.configurationService.getValue('terminal'); - return this.configurationManager.runInTerminal(this.type, args, config); + return this.configurationManager.runInTerminal(this.type, args); } get label(): string { diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index 6f173a4864f..7813de75b26 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -5,15 +5,15 @@ import * as cp from 'child_process'; import * as env from 'vs/base/common/platform'; -import { ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal'; import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; +import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; let externalTerminalService: IExternalTerminalService | undefined = undefined; -export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): void { +export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): void { if (!externalTerminalService) { if (env.isWindows) { externalTerminalService = new WindowsExternalTerminalService(undefined); @@ -24,6 +24,7 @@ export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestAr } } if (externalTerminalService) { + const config = configProvider.getConfiguration('terminal'); externalTerminalService.runInTerminal(args.title!, args.cwd, args.args, args.env || {}, config.external || {}); } } @@ -60,24 +61,25 @@ export function hasChildProcesses(processId: number): boolean { const enum ShellType { cmd, powershell, bash } -export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): string { +export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, shell: string, configProvider: ExtHostConfigProvider): string { - let shellType: ShellType; + let shellType = env.isWindows ? ShellType.cmd : ShellType.bash; // pick a good default - // get the shell configuration for the current platform - let shell: string; - const shell_config = config.integrated.shell; - if (env.isWindows) { - shell = shell_config.windows || getSystemShell(env.Platform.Windows); - shellType = ShellType.cmd; - } else if (env.isLinux) { - shell = shell_config.linux || getSystemShell(env.Platform.Linux); - shellType = ShellType.bash; - } else if (env.isMacintosh) { - shell = shell_config.osx || getSystemShell(env.Platform.Mac); - shellType = ShellType.bash; - } else { - throw new Error('Unknown platform'); + if (shell) { + + const config = configProvider.getConfiguration('terminal'); + + // get the shell configuration for the current platform + const shell_config = config.integrated.shell; + if (env.isWindows) { + shell = shell_config.windows || getSystemShell(env.Platform.Windows); + } else if (env.isLinux) { + shell = shell_config.linux || getSystemShell(env.Platform.Linux); + } else if (env.isMacintosh) { + shell = shell_config.osx || getSystemShell(env.Platform.Mac); + } else { + throw new Error('Unknown platform'); + } } // try to determine the shell type From a8b0169f94b4a162ddc4065cdaec7ecd412fe29f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 11:02:15 -0700 Subject: [PATCH 048/111] xterm@3.15.0-beta88, xterm-addon-search@0.2.0-beta3 Diff: https://github.com/xtermjs/xterm.js/compare/52c562d...378982a Changes: - Cancel events when not in screeReaderMode - Search addon behavior change + tests Related #77891 Fixes #77945 --- package.json | 4 ++-- remote/package.json | 4 ++-- remote/yarn.lock | 16 ++++++++-------- yarn.lock | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index cf653c43d08..6ef1d2f25a7 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,8 @@ "vscode-ripgrep": "^1.5.5", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta87", - "xterm-addon-search": "0.2.0-beta2", + "xterm": "3.15.0-beta88", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3" diff --git a/remote/package.json b/remote/package.json index 081eb5c6076..ccb412ef358 100644 --- a/remote/package.json +++ b/remote/package.json @@ -20,8 +20,8 @@ "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.5", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta71", - "xterm-addon-search": "0.2.0-beta2", + "xterm": "3.15.0-beta88", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3" diff --git a/remote/yarn.lock b/remote/yarn.lock index 3ed8f02de3c..b5077ce87a4 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -1149,20 +1149,20 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta71: - version "3.15.0-beta71" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta71.tgz#2728c9800ca3b08423e835e9504bd1f4b5de6253" - integrity sha512-8M/cLaxZ+iDopRxLPdPfKuDGaNNyYTdCeytdxjMSH0N7dZzbx6fbaEygQdCrV5pO9cGnT92MefSjVPGRXRiBLA== +xterm@3.15.0-beta88: + version "3.15.0-beta88" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta88.tgz#9a1c8d8a869517a4a8f103426fe0a89473455aa4" + integrity sha512-4nWNf4AbeoTRyOrhmWah9tZTXRepNo4uxzXdGskBWC9dAtItjD6ShNgi5z+xuVB4NmKoDp1b8rWNNMJ1I6/TLA== yauzl@^2.9.2: version "2.10.0" diff --git a/yarn.lock b/yarn.lock index ce4535f34c8..700e0195f87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9862,20 +9862,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta87: - version "3.15.0-beta87" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta87.tgz#d04af8d89f1f2c6c1d1580960653c32b2cc344e9" - integrity sha512-9HdgqnWCoEErvhk2Q0flDSlpAOnd4o+qe4+GeN6EwzKWPVdm1aNYLwdmeaOKAjZZfE+wchGu+HaslSRwfyu5yg== +xterm@3.15.0-beta88: + version "3.15.0-beta88" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta88.tgz#9a1c8d8a869517a4a8f103426fe0a89473455aa4" + integrity sha512-4nWNf4AbeoTRyOrhmWah9tZTXRepNo4uxzXdGskBWC9dAtItjD6ShNgi5z+xuVB4NmKoDp1b8rWNNMJ1I6/TLA== y18n@^3.2.1: version "3.2.1" From ee1a5ab1458475a55b42b7e983c5c7f0e1554f51 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 11:25:53 -0700 Subject: [PATCH 049/111] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ef1d2f25a7..eee312cd134 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "13a988e218df227b97e810eb49a1a0982bfed00d", + "distro": "60ca9cac46049ff774e34d11e335d172587da608", "author": { "name": "Microsoft Corporation" }, From fb810784a67c8b673fc6f28195df91ddddb31fc8 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 11:27:39 -0700 Subject: [PATCH 050/111] revert #59193. --- src/vs/editor/contrib/clipboard/clipboard.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index 102f1b019dc..c0929f47d00 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -148,12 +148,6 @@ class ExecCommandCopyAction extends ExecCommandAction { if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; } - // Prevent copying an empty line by accident - if (editor.getSelections().length === 1 && editor.getSelection().isEmpty()) { - if (editor.getModel().getLineFirstNonWhitespaceColumn(editor.getSelection().positionLineNumber) === 0) { - return; - } - } super.run(accessor, editor); } From 79bf9fd27b977aef21616bc4b8b33df5582f8357 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 25 Jul 2019 11:47:57 -0700 Subject: [PATCH 051/111] Make sure we use a consistent name for portMappings field --- .../workbench/contrib/webview/browser/webviewEditorService.ts | 2 +- src/vs/workbench/contrib/webview/browser/webviewElement.ts | 2 +- src/vs/workbench/contrib/webview/common/webview.ts | 2 +- .../contrib/webview/electron-browser/webviewElement.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts index 49d8bcc11cd..e81418df66a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -90,7 +90,7 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn && a.retainContextWhenHidden === b.retainContextWhenHidden && a.tryRestoreScrollPosition === b.tryRestoreScrollPosition && (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString()))) - && (a.portMappings === b.portMappings || (Array.isArray(a.portMappings) && Array.isArray(b.portMappings) && equals(a.portMappings, b.portMappings, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); + && (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); } function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean { diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 5e5df2a02cf..aa4473313d4 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -53,7 +53,7 @@ export class IFrameWebview extends Disposable implements Webview { this._portMappingManager = this._register(new WebviewPortMappingManager( this._options.extension ? this._options.extension.location : undefined, - () => this.content.options.portMappings || [], + () => this.content.options.portMapping || [], tunnelService )); diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index 8d81b487a5a..d6a73ff5d61 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -55,7 +55,7 @@ export interface WebviewContentOptions { readonly allowScripts?: boolean; readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; readonly enableCommandUris?: boolean; } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index e42e1a4b401..3c030feb235 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -327,7 +327,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { this._register(new WebviewPortMappingProvider( session, _options.extension ? _options.extension.location : undefined, - () => (this.content.options.portMappings || []), + () => (this.content.options.portMapping || []), tunnelService, )); From 065aa24d3567740e078f53dfa9b01a3842f5e3dc Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 11:48:29 -0700 Subject: [PATCH 052/111] Update monaco build recipt. --- build/monaco/monaco.usage.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index 13290a7abb5..f1a74a25e30 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -30,7 +30,7 @@ import * as editorAPI from './vs/editor/editor.api'; a = (>b).type; a = (b).start; a = (b).end; - a = (>b).getProxyObject; // IWorkerClient + a = (>b).getProxyObject; // IWorkerClient a = create1; a = create2; a = (b).extensionId; From 076c45be1adeca25374d67fa32f9c2567aaa8f46 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 10:57:20 -0700 Subject: [PATCH 053/111] Update sytles for replace input boxes --- src/vs/editor/contrib/find/findModel.ts | 8 +++++--- src/vs/editor/contrib/find/findWidget.ts | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 56fa23cf1b0..1600655f6c3 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -483,12 +483,14 @@ export class FindModelBoundToEditorModel { const replacePattern = this._getReplacePattern(); let resultText: string; + const preserveCase = this._state.preserveCase; + if (replacePattern.hasReplacementPatterns) { resultText = modelText.replace(searchRegex, function () { - return replacePattern.buildReplaceString(arguments); + return replacePattern.buildReplaceString(arguments, preserveCase); }); } else { - resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null)); + resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase)); } let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection()); @@ -502,7 +504,7 @@ export class FindModelBoundToEditorModel { let replaceStrings: string[] = []; for (let i = 0, len = matches.length; i < len; i++) { - replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches); + replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase); } let command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings); diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index e06de65d099..3b667c3e2d2 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -593,6 +593,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas }; this._findInput.style(inputStyles); this._replaceInputBox.style(inputStyles); + this._preserveCase.style(inputStyles); } private _tryUpdateWidgetWidth() { From 6157007341589c334ce771cbbe453c18142c7bce Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 25 Jul 2019 22:24:02 +0200 Subject: [PATCH 054/111] Only overtype automatically inserted characters (fixes #37315) --- src/vs/base/browser/browser.ts | 2 +- src/vs/editor/browser/widget/media/editor.css | 6 +- src/vs/editor/common/controller/cursor.ts | 124 +++++++++++++++++- .../common/controller/cursorTypeOperations.ts | 44 ++++++- src/vs/editor/common/core/range.ts | 26 ++++ .../test/browser/controller/cursor.test.ts | 105 ++++++++++++++- src/vs/monaco.d.ts | 8 ++ 7 files changed, 302 insertions(+), 13 deletions(-) diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index b447e0b68ec..6d4436c23eb 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -122,7 +122,7 @@ export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); export const isIPad = (userAgent.indexOf('iPad') >= 0); export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0); -export const isStandalone = (window.matchMedia('(display-mode: standalone)').matches); +export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); export function hasClipboardSupport() { if (isIE) { diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index 3266ae96364..83c0859bd29 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -39,4 +39,8 @@ .monaco-editor .view-overlays { position: absolute; top: 0; -} \ No newline at end of file +} + +.monaco-editor .auto-closed-character { + opacity: 0.3; +} diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index add9f3444a9..789d3a97b02 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -10,15 +10,16 @@ import { CursorCollection } from 'vs/editor/common/controller/cursorCollection'; import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; -import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; +import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model'; import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { dispose } from 'vs/base/common/lifecycle'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -83,6 +84,64 @@ export class CursorModelState { } } +class AutoClosedAction { + + private readonly _model: ITextModel; + + private _autoClosedCharactersDecorations: string[]; + private _autoClosedEnclosingDecorations: string[]; + + constructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) { + this._model = model; + this._autoClosedCharactersDecorations = autoClosedCharactersDecorations; + this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations; + } + + public dispose(): void { + this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []); + this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []); + } + + public getAutoClosedCharactersRanges(): Range[] { + let result: Range[] = []; + for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]); + if (decorationRange) { + result.push(decorationRange); + } + } + return result; + } + + public isValid(selections: Range[]): boolean { + let enclosingRanges: Range[] = []; + for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]); + if (decorationRange) { + enclosingRanges.push(decorationRange); + if (decorationRange.startLineNumber !== decorationRange.endLineNumber) { + // Stop tracking if the range becomes multiline... + return false; + } + } + } + enclosingRanges.sort(Range.compareRangesUsingStarts); + + selections.sort(Range.compareRangesUsingStarts); + + for (let i = 0; i < selections.length; i++) { + if (i >= enclosingRanges.length) { + return false; + } + if (!enclosingRanges[i].strictContainsRange(selections[i])) { + return false; + } + } + + return true; + } +} + export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public static MAX_CURSOR_COUNT = 10000; @@ -106,6 +165,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData | null; + private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) { @@ -120,6 +180,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; this._register(this._model.onDidChangeRawContent((e) => { @@ -173,9 +234,24 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public dispose(): void { this._cursors.dispose(); + this._autoClosedActions = dispose(this._autoClosedActions); super.dispose(); } + private _validateAutoClosedActions(): void { + if (this._autoClosedActions.length > 0) { + let selections: Range[] = this._cursors.getSelections(); + for (let i = 0; i < this._autoClosedActions.length; i++) { + const autoClosedAction = this._autoClosedActions[i]; + if (!autoClosedAction.isValid(selections)) { + autoClosedAction.dispose(); + this._autoClosedActions.splice(i, 1); + i--; + } + } + } + } + // ------ some getters/setters public getPrimaryCursor(): CursorState { @@ -202,6 +278,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.normalize(); this._columnSelectData = null; + this._validateAutoClosedActions(); + this._emitStateChangedIfNecessary(source, reason, oldState); } @@ -296,7 +374,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // a model.setValue() was called this._cursors.dispose(); this._cursors = new CursorCollection(this.context); - + this._validateAutoClosedActions(); this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null); } else { const selectionsFromMarkers = this._cursors.readSelectionFromMarkers(); @@ -367,6 +445,35 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // The commands were applied correctly this._interpretCommandResult(result); + // Check for auto-closing closed characters + let autoClosedCharactersRanges: IModelDeltaDecoration[] = []; + let autoClosedEnclosingRanges: IModelDeltaDecoration[] = []; + + for (let i = 0; i < opResult.commands.length; i++) { + const command = opResult.commands[i]; + if (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) { + autoClosedCharactersRanges.push({ + range: command.closeCharacterRange, + options: { + inlineClassName: 'auto-closed-character', + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + autoClosedEnclosingRanges.push({ + range: command.enclosingRange, + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + } + } + + if (autoClosedCharactersRanges.length > 0) { + const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersRanges); + const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingRanges); + this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations)); + } + this._prevEditOperationType = opResult.type; } @@ -540,6 +647,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.startTrackingSelections(); } + this._validateAutoClosedActions(); + if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } @@ -566,8 +675,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { chr = text.charAt(i); } + let autoClosedCharacters: Range[] = []; + if (this._autoClosedActions.length > 0) { + for (let i = 0, len = this._autoClosedActions.length; i < len; i++) { + autoClosedCharacters = autoClosedCharacters.concat(this._autoClosedActions[i].getAutoClosedCharactersRanges()); + } + } + // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); } } else { diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index c18d081379d..73d984cfb62 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -13,7 +13,7 @@ import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationT import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { ICommand } from 'vs/editor/common/editorCommon'; +import { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { EnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; @@ -430,7 +430,7 @@ export class TypeOperations { return null; } - private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean { + private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean { const autoCloseConfig = isQuote(ch) ? config.autoClosingQuotes : config.autoClosingBrackets; if (autoCloseConfig === 'never' || !config.autoClosingPairsClose.hasOwnProperty(ch)) { @@ -461,6 +461,19 @@ export class TypeOperations { return false; } } + + // Must over-type a closing character typed by the editor + let found = false; + for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) { + const autoClosedCharacter = autoClosedCharacters[j]; + if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) { + found = true; + break; + } + } + if (!found) { + return false; + } } return true; @@ -573,7 +586,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; - commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); + commands[i] = new TypeWithAutoClosingCommand(selection, ch, closeCharacter); } return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, @@ -802,7 +815,7 @@ export class TypeOperations { }); } - public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; @@ -833,7 +846,7 @@ export class TypeOperations { } } - if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { + if (this._isAutoClosingCloseCharType(config, model, selections, autoClosedCharacters, ch)) { return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } @@ -923,3 +936,24 @@ export class TypeOperations { return commands; } } + +export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState { + + private _closeCharacter: string; + public closeCharacterRange: Range | null; + public enclosingRange: Range | null; + + constructor(selection: Selection, openCharacter: string, closeCharacter: string) { + super(selection, openCharacter + closeCharacter, 0, -closeCharacter.length); + this._closeCharacter = closeCharacter; + this.closeCharacterRange = null; + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + let inverseEditOperations = helper.getInverseEditOperations(); + let range = inverseEditOperations[0].range; + this.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn); + this.enclosingRange = range; + return super.computeCursorState(model, helper); + } +} diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index c84b5df9d8a..e212e757dce 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -126,6 +126,32 @@ export class Range { return true; } + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + public strictContainsRange(range: IRange): boolean { + return Range.strictContainsRange(this, range); + } + + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + public static strictContainsRange(range: IRange, otherRange: IRange): boolean { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { + return false; + } + return true; + } + /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index cf0905a08ea..c2a4e4a4560 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -4344,12 +4344,12 @@ suite('autoClosingPairs', () => { let autoClosePositions = [ 'var a |=| [|]|;|', 'var b |=| |`asd`|;|', - 'var c |=| |\'asd!\'|;|', + 'var c |=| |\'asd\'|;|', 'var d |=| |"asd"|;|', 'var e |=| /*3*/| 3;|', 'var f |=| /**| 3 */3;|', 'var g |=| (3+5)|;|', - 'var h |=| {| a:| |\'value!\'| |}|;|', + 'var h |=| {| a:| |\'value\'| |}|;|', ]; for (let i = 0, len = autoClosePositions.length; i < len; i++) { const lineNumber = i + 1; @@ -4494,6 +4494,107 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #37315 - overtypes only those characters that it inserted', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: 'asd' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // overtype! + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // do not overtype! + cursor.setSelections('test', [new Selection(2, 4, 2, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(2), 'y=());'); + + }); + mode.dispose(); + }); + + test('issue #37315 - stops overtyping once cursor leaves area', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 5, 1, 5)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it overtypes only once', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 4, 1, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it can remember multiple auto-closed instances', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: '(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + }); + mode.dispose(); + }); + test('issue #15825: accents on mac US intl keyboard', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5f0f52de148..e08ad368312 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -585,6 +585,14 @@ declare namespace monaco { * Test if `otherRange` is in `range`. If the ranges are equal, will return true. */ static containsRange(range: IRange, otherRange: IRange): boolean; + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + strictContainsRange(range: IRange): boolean; + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + static strictContainsRange(range: IRange, otherRange: IRange): boolean; /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. From b999cdbea4a5be8ac679a596e0af9bc9c9501447 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 25 Jul 2019 14:02:02 -0700 Subject: [PATCH 055/111] Change default search to find previous --- extensions/json-language-features/server/yarn.lock | 5 +++++ src/vs/editor/contrib/find/simpleFindWidget.ts | 6 +++--- .../contrib/terminal/browser/terminalFindWidget.ts | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 1bb198a5210..13ab8c59ab0 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -134,3 +134,8 @@ vscode-uri@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== + +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 54f256d48aa..e6e992dc4da 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -93,13 +93,13 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - this.find(false); + this.find(true); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(true); + this.find(false); e.preventDefault(); return; } @@ -295,4 +295,4 @@ registerThemingParticipant((theme, collector) => { if (widgetShadowColor) { collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index 75e51bcfa22..b214d4a7bcc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -50,7 +50,7 @@ export class TerminalFindWidget extends SimpleFindWidget { // Ignore input changes for now const instance = this._terminalService.getActiveInstance(); if (instance !== null) { - return instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); + return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); } return false; } @@ -78,4 +78,4 @@ export class TerminalFindWidget extends SimpleFindWidget { protected onFindInputFocusTrackerBlur() { this._findInputFocused.reset(); } -} \ No newline at end of file +} From 94702ffa04a201da20268a027dba597273522a97 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 14:30:12 -0700 Subject: [PATCH 056/111] Fix Microsoft/monaco-editor#1353. Use wheel event for modern browsers. --- src/vs/base/browser/mouseEvent.ts | 6 +++++- src/vs/base/browser/ui/scrollbar/scrollableElement.ts | 3 ++- src/vs/editor/browser/controller/mouseHandler.ts | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index dee572ce892..4c7295e3b9b 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -160,6 +160,8 @@ export class StandardWheelEvent { this.deltaY = e1.wheelDeltaY / 120; } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { this.deltaY = -e2.detail / 3; + } else { + this.deltaY = -e.deltaY / 40; } // horizontal delta scroll @@ -171,6 +173,8 @@ export class StandardWheelEvent { } } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { this.deltaX = -e.detail / 3; + } else { + this.deltaX = -e.deltaX / 40; } // Assume a vertical scroll if nothing else worked @@ -195,4 +199,4 @@ export class StandardWheelEvent { } } } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index fbf8d5dcd13..1c1ded9eb2c 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/scrollbars'; +import { isEdgeOrIE } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -312,7 +313,7 @@ export abstract class AbstractScrollableElement extends Widget { this._onMouseWheel(new StandardWheelEvent(browserEvent)); }; - this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, 'mousewheel', onMouseWheel)); + this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel)); } } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 4a2dc7661c9..06d4b2f5307 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -123,7 +123,7 @@ export class MouseHandler extends ViewEventHandler { e.stopPropagation(); } }; - this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, 'mousewheel', onMouseWheel, true)); + this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, true)); this._context.addEventHandler(this); } From 7f88351f58d111f23f4b709edc6fa4619338d429 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 15:02:29 -0700 Subject: [PATCH 057/111] Fix #76773. Hide Find Widget when editor content is hidden. --- src/vs/editor/contrib/find/findWidget.css | 5 +++++ src/vs/editor/contrib/find/findWidget.ts | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index d210cb1dd49..7e1140442ea 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -39,6 +39,11 @@ transition: top 200ms linear; padding: 0 4px; } + +.monaco-editor .find-widget.hiddenEditor { + display: none; +} + /* Find widget when replace is toggled on */ .monaco-editor .find-widget.replaceToggled { top: -74px; /* find input height + replace input height + shadow (10px) */ diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 3b667c3e2d2..9c9af950e6b 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -600,8 +600,19 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas if (!this._isVisible) { return; } - let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + + const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + + if (editorContentWidth <= 0) { + // for example, diff view original editor + dom.addClass(this._domNode, 'hiddenEditor'); + return; + } else if (dom.hasClass(this._domNode, 'hiddenEditor')) { + dom.removeClass(this._domNode, 'hiddenEditor'); + } + + const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; + const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; From 96cc6dc2aafab74d629f15aaf33ba76bc174f91c Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 25 Jul 2019 15:29:33 -0700 Subject: [PATCH 058/111] Fix comment actions not updating on when clause change, fixes #77012 --- .../contrib/comments/browser/commentNode.ts | 102 +++++++++--------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index d3ac220871e..f5a80eea68b 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -28,7 +28,7 @@ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; -import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuItemAction, SubmenuItemAction, IMenu } from 'vs/platform/actions/common/actions'; import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -54,7 +54,7 @@ export class CommentNode extends Disposable { private _commentContextValue: IContextKey; protected actionRunner?: IActionRunner; - protected toolbar: ToolBar; + protected toolbar: ToolBar | undefined; private _commentFormActions: CommentFormActions; private _onDidDelete = new Emitter(); @@ -134,9 +134,49 @@ export class CommentNode extends Disposable { this.createActionsToolbar(); } + private getToolbarActions(menu: IMenu): { primary: IAction[], secondary: IAction[] } { + const contributedActions = menu.getActions({ shouldForwardArgs: true }); + const primary: IAction[] = []; + const secondary: IAction[] = []; + const result = { primary, secondary }; + fillInActions(contributedActions, result, false, g => /^inline/.test(g)); + return result; + } + + private createToolbar() { + this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { + actionViewItemProvider: action => { + if (action.id === ToggleReactionsAction.ID) { + return new DropdownMenuActionViewItem( + action, + (action).menuActions, + this.contextMenuService, + action => { + return this.actionViewItemProvider(action as Action); + }, + this.actionRunner!, + undefined, + 'toolbar-toggle-pickReactions', + () => { return AnchorAlignment.RIGHT; } + ); + } + return this.actionViewItemProvider(action as Action); + }, + orientation: ActionsOrientation.HORIZONTAL + }); + + this.toolbar.context = { + thread: this.commentThread, + commentUniqueId: this.comment.uniqueIdInThread, + $mid: 9 + }; + + this.registerActionBarListeners(this._actionsToolbarContainer); + this._register(this.toolbar); + } + private createActionsToolbar() { const actions: IAction[] = []; - const secondaryActions: IAction[] = []; let hasReactionHandler = this.commentService.hasReactionHandler(this.owner); @@ -149,54 +189,20 @@ export class CommentNode extends Disposable { const menu = commentMenus.getCommentTitleActions(this.comment, this._contextKeyService); this._register(menu); this._register(menu.onDidChange(e => { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - this.toolbar.setActions(primary, secondary); + const { primary, secondary } = this.getToolbarActions(menu); + if (!this.toolbar && (primary.length || secondary.length)) { + this.createToolbar(); + } + + this.toolbar!.setActions(primary, secondary)(); })); - const contributedActions = menu.getActions({ shouldForwardArgs: true }); - { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - actions.push(...primary); - secondaryActions.push(...secondary); - } + const { primary, secondary } = this.getToolbarActions(menu); + actions.push(...primary); - if (actions.length || secondaryActions.length) { - this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { - actionViewItemProvider: action => { - if (action.id === ToggleReactionsAction.ID) { - return new DropdownMenuActionViewItem( - action, - (action).menuActions, - this.contextMenuService, - action => { - return this.actionViewItemProvider(action as Action); - }, - this.actionRunner!, - undefined, - 'toolbar-toggle-pickReactions', - () => { return AnchorAlignment.RIGHT; } - ); - } - return this.actionViewItemProvider(action as Action); - }, - orientation: ActionsOrientation.HORIZONTAL - }); - - this.toolbar.context = { - thread: this.commentThread, - commentUniqueId: this.comment.uniqueIdInThread, - $mid: 9 - }; - - this.registerActionBarListeners(this._actionsToolbarContainer); - this.toolbar.setActions(actions, secondaryActions)(); - this._register(this.toolbar); + if (actions.length || secondary.length) { + this.createToolbar(); + this.toolbar!.setActions(actions, secondary)(); } } From 3866deba3572efba0fefd9f26f04a441e87de410 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 16:00:41 -0700 Subject: [PATCH 059/111] Use pty naming instead of virtual process Part of #77160 --- .../src/singlefolder-tests/terminal.test.ts | 18 +-- .../workspace.tasks.test.ts | 4 +- src/vs/vscode.proposed.d.ts | 118 ++++++++++-------- .../api/browser/mainThreadTerminalService.ts | 10 +- .../workbench/api/common/extHost.protocol.ts | 4 +- src/vs/workbench/api/common/extHostTypes.ts | 8 +- src/vs/workbench/api/node/extHost.api.impl.ts | 6 +- src/vs/workbench/api/node/extHostTask.ts | 2 +- .../api/node/extHostTerminalService.ts | 60 ++++----- .../tasks/browser/terminalTaskSystem.ts | 2 +- .../browser/terminalProcessManager.ts | 10 +- .../contrib/terminal/common/terminal.ts | 12 +- .../common/terminalProcessExtHostProxy.ts | 7 +- .../terminal/common/terminalService.ts | 10 +- 14 files changed, 142 insertions(+), 129 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 63e39fdd2e4..ee5f7505d6c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, Terminal, TerminalVirtualProcess, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; +import { window, Terminal, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; import { doesNotThrow, equal, ok } from 'assert'; suite('window namespace tests', () => { @@ -264,12 +264,12 @@ suite('window namespace tests', () => { }); term.dispose(); }); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, start: () => {}, shutdown: () => {} }; - window.createTerminal({ name: 'c', virtualProcess }); + window.createTerminal({ name: 'c', pty }); }); test('should fire Terminal.onData on write', (done) => { @@ -291,12 +291,12 @@ suite('window namespace tests', () => { let startResolve: () => void; const startPromise: Promise = new Promise(r => startResolve = r); const writeEmitter = new EventEmitter(); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, start: () => startResolve(), shutdown: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + const terminal = window.createTerminal({ name: 'foo', pty }); }); test('should fire provide dimensions on start as the terminal has been shown', (done) => { @@ -304,7 +304,7 @@ suite('window namespace tests', () => { equal(terminal, term); reg1.dispose(); }); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, start: (dimensions) => { ok(dimensions!.columns > 0); @@ -317,7 +317,7 @@ suite('window namespace tests', () => { }, shutdown: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + const terminal = window.createTerminal({ name: 'foo', pty }); }); test('should respect dimension overrides', (done) => { @@ -340,13 +340,13 @@ suite('window namespace tests', () => { }); const writeEmitter = new EventEmitter(); const overrideDimensionsEmitter = new EventEmitter(); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, onDidOverrideDimensions: overrideDimensionsEmitter.event, start: () => {}, shutdown: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + const terminal = window.createTerminal({ name: 'foo', pty }); }); }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts index 43470d24e19..695ac4b0f59 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -35,8 +35,8 @@ suite.only('workspace-namespace', () => { customProp1: 'testing task one' }; const writeEmitter = new vscode.EventEmitter(); - const execution = new vscode.CustomExecution2((): Thenable => { - return Promise.resolve({ + const execution = new vscode.CustomExecution2((): Thenable => { + return Promise.resolve({ onDidWrite: writeEmitter.event, start: () => { writeEmitter.fire('testing\r\n'); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 430967c999e..d1bb0e8eb67 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -816,7 +816,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText) is triggered that will fire the * [TerminalRenderer.onDidAcceptInput](#TerminalRenderer.onDidAcceptInput) event. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Create a terminal renderer, show it and write hello world in red * ```typescript @@ -828,7 +828,7 @@ declare module 'vscode' { export interface TerminalRenderer { /** * The name of the terminal, this will appear in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ name: string; @@ -837,7 +837,7 @@ declare module 'vscode' { * a value smaller than the maximum value, if this is undefined the terminal will auto fit * to the maximum value [maximumDimensions](TerminalRenderer.maximumDimensions). * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Override the dimensions of a TerminalRenderer to 20 columns and 10 rows * ```typescript @@ -855,14 +855,14 @@ declare module 'vscode' { * Listen to [onDidChangeMaximumDimensions](TerminalRenderer.onDidChangeMaximumDimensions) * to get notified when this value changes. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly maximumDimensions: TerminalDimensions | undefined; /** * The corresponding [Terminal](#Terminal) for this TerminalRenderer. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly terminal: Terminal; @@ -871,7 +871,7 @@ declare module 'vscode' { * text to the underlying _process_, this will write the text to the terminal itself. * * @param text The text to write. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Write red text to the terminal * ```typescript @@ -890,7 +890,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their * corresponding VT sequence representation. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Simulate interaction with the terminal from an outside extension or a * workbench command such as `workbench.action.terminal.runSelectedText` @@ -908,7 +908,7 @@ declare module 'vscode' { * An event which fires when the [maximum dimensions](#TerminalRenderer.maximumDimensions) of * the terminal renderer change. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly onDidChangeMaximumDimensions: Event; } @@ -918,60 +918,60 @@ declare module 'vscode' { * Create a [TerminalRenderer](#TerminalRenderer). * * @param name The name of the terminal renderer, this shows up in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ export function createTerminalRenderer(name: string): TerminalRenderer; } //#endregion - //#region Terminal extension pty + //#region Extension terminals export namespace window { /** - * Creates a [Terminal](#Terminal) where an extension acts as the process. + * Creates a [Terminal](#Terminal) where an extension controls the teerminal. * - * @param options A [TerminalVirtualProcessOptions](#TerminalVirtualProcessOptions) object describing the - * characteristics of the new terminal. + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. * @return A new Terminal. */ - export function createTerminal(options: TerminalVirtualProcessOptions): Terminal; + export function createTerminal(options: ExtensionTerminalOptions): Terminal; } /** * Value-object describing what options a virtual process terminal should use. */ - export interface TerminalVirtualProcessOptions { + export interface ExtensionTerminalOptions { /** * A human-readable string which will be used to represent the terminal in the UI. */ name: string; /** - * An implementation of [TerminalVirtualProcess](#TerminalVirtualProcess) that allows an - * extension to act as a terminal's backing process. + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. */ - virtualProcess: TerminalVirtualProcess; + pty: Pseudoterminal; } /** - * Defines the interface of a terminal virtual process, enabling extensions to act as a process - * in the terminal. + * Defines the interface of a terminal pty, enabling extensions to control a terminal. */ - interface TerminalVirtualProcess { + interface Pseudoterminal { /** * An event that when fired will write data to the terminal. Unlike - * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_, - * this will write the text to the terminal itself. + * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ + * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). * * **Example:** Write red text to the terminal * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { - * onDidWrite: writeEmitter.event + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * start: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * shutdown: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * writeEmitter.fire('\x1b[31mHello world\x1b[0m'); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` * * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk @@ -985,44 +985,50 @@ declare module 'vscode' { * An event that when fired allows overriding the [dimensions](#Terminal.dimensions) of the * terminal. Note that when set the overridden dimensions will only take effect when they * are lower than the actual dimensions of the terminal (ie. there will never be a scroll - * bar). Set to `undefined` for the terminal to go back to the regular dimensions. + * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to + * the size of the panel). * * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows * ```typescript * const dimensionsEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * onDidOverrideDimensions: dimensionsEmitter.event + * onDidOverrideDimensions: dimensionsEmitter.event, + * start: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * shutdown: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * dimensionsEmitter.fire({ - * columns: 20, - * rows: 10 - * }); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` */ onDidOverrideDimensions?: Event; /** * An event that when fired will exit the process with an exit code, this will behave the - * same for a virtual process as when a regular process exits with an exit code. Note that - * exit codes must be positive numbers, when negative the exit code will be forced to `1`. + * same for an extension treminal as when a regular process exits with an exit code. Note + * that exit codes must be positive numbers, when negative the exit code will be forced to + * `1`. * * **Example:** Exit with an exit code of `0` if the y key is pressed, otherwise `1`. * ```typescript * const writeEmitter = new vscode.EventEmitter(); * const exitEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * input: data => exitEmitter.fire(data === 'y' ? 0 : 1) + * start: () => writeEmitter.fire('Press y to exit successfully'), + * shutdown: () => {} + * handleInput: data => exitEmitter.fire(data === 'y' ? 0 : 1) * }; - * vscode.window.createTerminal({ name: 'Exit example', virtualProcess }); - * writeEmitter.fire('Press y to exit successfully'); + * vscode.window.createTerminal({ name: 'Exit example', pty }); */ onDidExit?: Event; /** - * Implement to handle when the terminal is ready to start firing events. + * Implement to handle when the pty is ready to start firing events. * * @param initialDimensions The dimensions of the terminal, this will be undefined if the * terminal panel has not been opened before this is called. @@ -1035,21 +1041,23 @@ declare module 'vscode' { shutdown(): void; /** - * Implement to handle keystrokes in the terminal or when an extension calls - * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their - * corresponding VT sequence representation. + * Implement to handle incoming keystrokes in the terminal or when an extension calls + * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * their corresponding VT sequence representation. * - * @param data The sent data. + * @param data The incoming data. * * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to * CRLF to go to a new line and move the cursor to the start of the line. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, + * start: () => {}, + * shutdown: () => {}, * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) * }; - * vscode.window.createTerminal({ name: 'Local echo', virtualProcess }); + * vscode.window.createTerminal({ name: 'Local echo', pty }); * ``` */ handleInput?(data: string): void; @@ -1145,6 +1153,7 @@ declare module 'vscode' { } //#endregion + //#region CustomExecution /** * Class used to execute an extension callback as a task. */ @@ -1168,16 +1177,18 @@ declare module 'vscode' { */ export class CustomExecution2 { /** - * @param process The [TerminalVirtualProcess](#TerminalVirtualProcess) to be used by the task to display output. + * @param process The [Pseudotrminal](#Pseudoterminal) to be used by the task to display output. * @param callback The callback that will be called when the task is started by a user. */ - constructor(callback: (thisArg?: any) => Thenable); + constructor(callback: (thisArg?: any) => Thenable); /** - * The callback used to execute the task. Cancellation should be handled using the shutdown method of [TerminalVirtualProcess](#TerminalVirtualProcess). - * When the task is complete, onDidExit should be fired on the TerminalVirtualProcess with the exit code with '0' for success and a non-zero value for failure. + * The callback used to execute the task. Cancellation should be handled using + * [Pseudoterminal.shutdown](#Pseudoterminal.shutdown). When the task is complete, + * [Pseudoterminal.onDidExit](#Pseudoterminal.onDidExit) should be fired with the exit code + * with '0' for success and a non-zero value for failure. */ - callback: (thisArg?: any) => Thenable; + callback: (thisArg?: any) => Thenable; } /** @@ -1203,6 +1214,7 @@ declare module 'vscode' { */ execution2?: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2; } + //#endregion //#region Tasks export interface TaskPresentationOptions { diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 13f4fad4663..2d3dd6d0035 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; @@ -48,7 +48,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); - this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(e => this._onTerminalRequestVirtualProcess(e))); + this._toDispose.add(_terminalService.onInstanceRequestExtensionTerminal(e => this._onTerminalRequestExtensionTerminal(e))); this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed))); @@ -90,7 +90,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape env: launchConfig.env, strictEnv: launchConfig.strictEnv, hideFromUser: launchConfig.hideFromUser, - isVirtualProcess: launchConfig.isVirtualProcess + isExtensionTerminal: launchConfig.isExtensionTerminal }; const terminal = this._terminalService.createTerminal(shellLaunchConfig); this._terminalProcesses.set(terminal.id, new Promise(r => this._terminalProcessesReady.set(terminal.id, r))); @@ -270,7 +270,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId)); } - private _onTerminalRequestVirtualProcess(request: ITerminalVirtualProcessRequest): void { + private _onTerminalRequestExtensionTerminal(request: IExtensionTerminalRequest): void { const proxy = request.proxy; const ready = this._terminalProcessesReady.get(proxy.terminalId); if (!ready) { @@ -286,7 +286,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape columns: request.cols, rows: request.rows } : undefined; - this._proxy.$startVirtualProcess(proxy.terminalId, initialDimensions); + this._proxy.$startExtensionTerminal(proxy.terminalId, initialDimensions); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId)); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index f8d565df56c..6a76d4e86b4 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -390,7 +390,7 @@ export interface TerminalLaunchConfig { waitOnExit?: boolean; strictEnv?: boolean; hideFromUser?: boolean; - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; } export interface MainThreadTerminalServiceShape extends IDisposable { @@ -1162,7 +1162,7 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; + $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; $acceptProcessShutdown(id: number, immediate: boolean): void; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index b8aebf92b45..20d60dddd30 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1773,19 +1773,19 @@ export class CustomExecution implements vscode.CustomExecution { } export class CustomExecution2 implements vscode.CustomExecution2 { - private _callback: () => Thenable; - constructor(callback: () => Thenable) { + private _callback: () => Thenable; + constructor(callback: () => Thenable) { this._callback = callback; } public computeId(): string { return 'customExecution' + generateUuid(); } - public set callback(value: () => Thenable) { + public set callback(value: () => Thenable) { this._callback = value; } - public get callback(): (() => Thenable) { + public get callback(): (() => Thenable) { return this._callback; } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 27fb09b2abd..f4df88c11ba 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -528,10 +528,10 @@ export function createApiFactory( checkProposedApiEnabled(extension); return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension); }, - createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.TerminalVirtualProcessOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { + createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { if (typeof nameOrOptions === 'object') { - if ('virtualProcess' in nameOrOptions) { - return extHostTerminalService.createVirtualProcessTerminal(nameOrOptions); + if ('pty' in nameOrOptions) { + return extHostTerminalService.createExtensionTerminal(nameOrOptions); } else { nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi); return extHostTerminalService.createTerminalFromOptions(nameOrOptions); diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 0e7f5f9dd7a..9191b53aa47 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -588,7 +588,7 @@ export class ExtHostTask implements ExtHostTaskShape { // Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task. this._activeCustomExecutions2.set(execution.id, execution2); - await this._terminalService.attachVirtualProcessToTerminal(terminalId, await execution2.callback()); + await this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback()); } // Once a terminal is spun up for the custom execution task this event will be fired. diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 4aa39f91127..604008252d5 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -124,8 +124,8 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi this._runQueuedRequests(terminal.id); } - public async createVirtualProcess(): Promise { - const terminal = await this._proxy.$createTerminal({ name: this._name, isVirtualProcess: true }); + public async createExtensionTerminal(): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true }); this._name = terminal.name; this._runQueuedRequests(terminal.id); } @@ -329,20 +329,20 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return terminal; } - public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal { + public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, options.name); - const p = new ExtHostVirtualProcess(options.virtualProcess); - terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p)); + const p = new ExtHostPseudoterminal(options.pty); + terminal.createExtensionTerminal().then(() => this._setupExtHostProcessListeners(terminal._id, p)); this._terminals.push(terminal); return terminal; } - public async attachVirtualProcessToTerminal(id: number, virtualProcess: vscode.TerminalVirtualProcess): Promise { + public async attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): Promise { const terminal = this._getTerminalByIdEventually(id); if (!terminal) { throw new Error(`Cannot resolve terminal with id ${id} for virtual process`); } - const p = new ExtHostVirtualProcess(virtualProcess); + const p = new ExtHostPseudoterminal(pty); this._setupExtHostProcessListeners(id, p); } @@ -619,9 +619,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService)); } - public async $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { + public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call - // TerminalVirtualProcess.start + // Pseudoterminal.start await this._getTerminalByIdEventually(id); // Processes should be initialized here for normal virtual process terminals, however for @@ -630,7 +630,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { let retries = 5; while (retries-- > 0) { if (this._terminalProcesses[id]) { - (this._terminalProcesses[id] as ExtHostVirtualProcess).startSendingEvents(initialDimensions); + (this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions); return; } await timeout(50); @@ -773,7 +773,7 @@ class ApiRequest { } } -class ExtHostVirtualProcess implements ITerminalChildProcess { +class ExtHostPseudoterminal implements ITerminalChildProcess { private _queuedEvents: (IQueuedEvent | IQueuedEvent | IQueuedEvent<{ pid: number, cwd: string }> | IQueuedEvent)[] = []; private _queueDisposables: IDisposable[] | undefined; @@ -789,33 +789,33 @@ class ExtHostVirtualProcess implements ITerminalChildProcess { public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } constructor( - private readonly _virtualProcess: vscode.TerminalVirtualProcess + private readonly _pty: vscode.Pseudoterminal ) { this._queueDisposables = []; - this._queueDisposables.push(this._virtualProcess.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); - if (this._virtualProcess.onDidExit) { - this._queueDisposables.push(this._virtualProcess.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e }))); + this._queueDisposables.push(this._pty.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); + if (this._pty.onDidExit) { + this._queueDisposables.push(this._pty.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e }))); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._queueDisposables.push(this._virtualProcess.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); + if (this._pty.onDidOverrideDimensions) { + this._queueDisposables.push(this._pty.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); } } shutdown(): void { - if (this._virtualProcess.shutdown) { - this._virtualProcess.shutdown(); + if (this._pty.shutdown) { + this._pty.shutdown(); } } input(data: string): void { - if (this._virtualProcess.handleInput) { - this._virtualProcess.handleInput(data); + if (this._pty.handleInput) { + this._pty.handleInput(data); } } resize(cols: number, rows: number): void { - if (this._virtualProcess.setDimensions) { - this._virtualProcess.setDimensions({ columns: cols, rows }); + if (this._pty.setDimensions) { + this._pty.setDimensions({ columns: cols, rows }); } } @@ -838,19 +838,19 @@ class ExtHostVirtualProcess implements ITerminalChildProcess { this._queueDisposables = undefined; // Attach the real listeners - this._virtualProcess.onDidWrite(e => this._onProcessData.fire(e)); - if (this._virtualProcess.onDidExit) { - this._virtualProcess.onDidExit(e => { + this._pty.onDidWrite(e => this._onProcessData.fire(e)); + if (this._pty.onDidExit) { + this._pty.onDidExit(e => { // Ensure only positive exit codes are returned this._onProcessExit.fire(e >= 0 ? e : 1); }); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._virtualProcess.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); + if (this._pty.onDidOverrideDimensions) { + this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); } - if (this._virtualProcess.start) { - this._virtualProcess.start(initialDimensions); + if (this._pty.start) { + this._pty.start(initialDimensions); } } } diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 21491081db7..efef7a28135 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -926,7 +926,7 @@ export class TerminalTaskSystem implements ITaskSystem { }; } else if (task.command.runtime === RuntimeType.CustomExecution2) { this.currentTask.shellLaunchConfig = launchConfigs = { - isVirtualProcess: true, + isExtensionTerminal: true, waitOnExit, name: this.createTerminalName(task, workspaceFolder), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index a391164f1f2..348b93e3307 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -31,7 +31,7 @@ const LATENCY_MEASURING_INTERVAL = 1000; enum ProcessType { Process, - VirtualProcess + ExtensionTerminal } /** @@ -113,8 +113,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { rows: number, isScreenReaderModeEnabled: boolean ): Promise { - if (shellLaunchConfig.isVirtualProcess) { - this._processType = ProcessType.VirtualProcess; + if (shellLaunchConfig.isExtensionTerminal) { + this._processType = ProcessType.ExtensionTerminal; this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, undefined, cols, rows, this._configHelper); } else { const forceExtHostProcess = (this._configHelper.config as any).extHostProcess; @@ -239,7 +239,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } public write(data: string): void { - if (this.shellProcessId || this._processType === ProcessType.VirtualProcess) { + if (this.shellProcessId || this._processType === ProcessType.ExtensionTerminal) { if (this._process) { // Send data if the pty is ready this._process.input(data); @@ -292,4 +292,4 @@ export class TerminalProcessManager implements ITerminalProcessManager { this._onProcessExit.fire(exitCode); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index f427fd3ef0e..2774d70a82c 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -188,14 +188,14 @@ export interface IShellLaunchConfig { initialText?: string; /** - * @deprecated use `isVirtualProcess` + * @deprecated use `isExtensionTerminal` */ isRendererOnly?: boolean; /** - * When true an extension is acting as the terminal's process. + * Whether an extension is controlling the terminal via a `vscode.Pseudoterminal`. */ - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; /** * Whether the terminal process environment should be exactly as provided in @@ -232,7 +232,7 @@ export interface ITerminalService { onInstanceDimensionsChanged: Event; onInstanceMaximumDimensionsChanged: Event; onInstanceRequestExtHostProcess: Event; - onInstanceRequestVirtualProcess: Event; + onInstanceRequestExtensionTerminal: Event; onInstancesChanged: Event; onInstanceTitleChanged: Event; onActiveInstanceChanged: Event; @@ -300,7 +300,7 @@ export interface ITerminalService { extHostReady(remoteAuthority: string): void; requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; + requestExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } /** @@ -769,7 +769,7 @@ export interface ITerminalProcessExtHostRequest { isWorkspaceShellAllowed: boolean; } -export interface ITerminalVirtualProcessRequest { +export interface IExtensionTerminalRequest { proxy: ITerminalProcessExtHostProxy; cols: number; rows: number; diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index e611bce74a6..7093d6aa7f6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -58,8 +58,9 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal // Request a process if needed, if this is a virtual process this step can be skipped as // there is no real "process" and we know it's ready on the ext host already. - if (shellLaunchConfig.isVirtualProcess) { - this._terminalService.requestVirtualProcess(this, cols, rows); + if (shellLaunchConfig.isExtensionTerminal) { + // TODO: This name should be improved + this._terminalService.requestExtensionTerminal(this, cols, rows); } else { remoteAgentService.getEnvironment().then(env => { if (!env) { @@ -149,4 +150,4 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._pendingLatencyRequests.push(resolve); }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 558be1e44ea..36cbc613dba 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; @@ -55,8 +55,8 @@ export abstract class TerminalService implements ITerminalService { public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.event; } protected readonly _onInstanceRequestExtHostProcess = new Emitter(); public get onInstanceRequestExtHostProcess(): Event { return this._onInstanceRequestExtHostProcess.event; } - protected readonly _onInstanceRequestVirtualProcess = new Emitter(); - public get onInstanceRequestVirtualProcess(): Event { return this._onInstanceRequestVirtualProcess.event; } + protected readonly _onInstanceRequestExtensionTerminal = new Emitter(); + public get onInstanceRequestExtensionTerminal(): Event { return this._onInstanceRequestExtensionTerminal.event; } protected readonly _onInstanceDimensionsChanged = new Emitter(); public get onInstanceDimensionsChanged(): Event { return this._onInstanceDimensionsChanged.event; } protected readonly _onInstanceMaximumDimensionsChanged = new Emitter(); @@ -144,8 +144,8 @@ export abstract class TerminalService implements ITerminalService { }); } - public requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { - this._onInstanceRequestVirtualProcess.fire({ proxy, cols, rows }); + public requestExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { + this._onInstanceRequestExtensionTerminal.fire({ proxy, cols, rows }); } public extHostReady(remoteAuthority: string): void { From a16e432670428ce4d26b845c88bbfbb47ba2a790 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 25 Jul 2019 16:02:40 -0700 Subject: [PATCH 060/111] Invert default direction --- src/vs/editor/contrib/find/simpleFindWidget.ts | 12 ++++++++---- .../contrib/terminal/browser/terminalFindWidget.ts | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index e6e992dc4da..27a89a40b67 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -26,7 +26,7 @@ const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next mat const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); export abstract class SimpleFindWidget extends Widget { - private readonly _findInput: FindInput; + protected readonly _findInput: FindInput; private readonly _domNode: HTMLElement; private readonly _innerDomNode: HTMLElement; private _isVisible: boolean = false; @@ -36,15 +36,18 @@ export abstract class SimpleFindWidget extends Widget { private prevBtn: SimpleButton; private nextBtn: SimpleButton; private foundMatch: boolean; + private readonly _invertDefaultDirection: boolean | undefined; constructor( @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, private readonly _state: FindReplaceState = new FindReplaceState(), - showOptionButtons?: boolean + showOptionButtons?: boolean, + invertDefaultDirection?: boolean ) { super(); + this._invertDefaultDirection = invertDefaultDirection; this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewService, { label: NLS_FIND_INPUT_LABEL, placeholder: NLS_FIND_INPUT_PLACEHOLDER, @@ -93,13 +96,14 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - this.find(true); + // Flip the direction search goes in the terminal case so it matches other terminals + this.find(this._invertDefaultDirection ? true : false); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(false); + this.find(this._invertDefaultDirection ? false : true); e.preventDefault(); return; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index b214d4a7bcc..f8035e70b4f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -8,7 +8,6 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; - export class TerminalFindWidget extends SimpleFindWidget { protected _findInputFocused: IContextKey; protected _findWidgetFocused: IContextKey; @@ -19,7 +18,7 @@ export class TerminalFindWidget extends SimpleFindWidget { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @ITerminalService private readonly _terminalService: ITerminalService ) { - super(_contextViewService, _contextKeyService, findState, true); + super(_contextViewService, _contextKeyService, findState, true, true); this._register(findState.onFindReplaceStateChange(() => { this.show(); })); From a62dd35412237761e04e207f43b3e6d92fda9639 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 25 Jul 2019 16:03:20 -0700 Subject: [PATCH 061/111] Make findInput private again --- src/vs/editor/contrib/find/simpleFindWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 27a89a40b67..02b522158d6 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -26,7 +26,7 @@ const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next mat const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); export abstract class SimpleFindWidget extends Widget { - protected readonly _findInput: FindInput; + private readonly _findInput: FindInput; private readonly _domNode: HTMLElement; private readonly _innerDomNode: HTMLElement; private _isVisible: boolean = false; From 9b60caf9e0527fe278c4f919325111e83e8b2fb2 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 16:09:03 -0700 Subject: [PATCH 062/111] Improve naming of start/spawn request calls --- .../api/browser/mainThreadTerminalService.ts | 12 ++++++------ .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/node/extHostTerminalService.ts | 2 +- .../contrib/terminal/common/terminal.ts | 12 ++++++------ .../common/terminalProcessExtHostProxy.ts | 5 ++--- .../contrib/terminal/common/terminalService.ts | 18 +++++++++--------- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 2d3dd6d0035..f23b625d140 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; @@ -47,8 +47,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); - this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); - this._toDispose.add(_terminalService.onInstanceRequestExtensionTerminal(e => this._onTerminalRequestExtensionTerminal(e))); + this._toDispose.add(_terminalService.onInstanceRequestSpawnExtHostProcess(request => this._onRequestSpawnExtHostProcess(request))); + this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e))); this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed))); @@ -240,7 +240,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$acceptTerminalMaximumDimensions(instance.id, instance.maxCols, instance.maxRows); } - private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void { + private _onRequestSpawnExtHostProcess(request: ISpawnExtHostProcessRequest): void { // Only allow processes on remote ext hosts if (!this._remoteAuthority) { return; @@ -261,7 +261,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape cwd: request.shellLaunchConfig.cwd, env: request.shellLaunchConfig.env }; - this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); + this._proxy.$spawnExtHostProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); @@ -270,7 +270,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId)); } - private _onTerminalRequestExtensionTerminal(request: IExtensionTerminalRequest): void { + private _onRequestStartExtensionTerminal(request: IStartExtensionTerminalRequest): void { const proxy = request.proxy; const ready = this._terminalProcessesReady.get(proxy.terminalId); if (!ready) { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 6a76d4e86b4..e224dcc9c5d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1161,7 +1161,7 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; - $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $spawnExtHostProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 604008252d5..7b5df64321c 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -550,7 +550,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); } - public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { const shellLaunchConfig: IShellLaunchConfig = { name: shellLaunchConfigDto.name, executable: shellLaunchConfigDto.executable, diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 2774d70a82c..f6413d9857e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -231,8 +231,8 @@ export interface ITerminalService { onInstanceProcessIdReady: Event; onInstanceDimensionsChanged: Event; onInstanceMaximumDimensionsChanged: Event; - onInstanceRequestExtHostProcess: Event; - onInstanceRequestExtensionTerminal: Event; + onInstanceRequestSpawnExtHostProcess: Event; + onInstanceRequestStartExtensionTerminal: Event; onInstancesChanged: Event; onInstanceTitleChanged: Event; onActiveInstanceChanged: Event; @@ -299,8 +299,8 @@ export interface ITerminalService { preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; extHostReady(remoteAuthority: string): void; - requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - requestExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } /** @@ -760,7 +760,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { onRequestLatency: Event; } -export interface ITerminalProcessExtHostRequest { +export interface ISpawnExtHostProcessRequest { proxy: ITerminalProcessExtHostProxy; shellLaunchConfig: IShellLaunchConfig; activeWorkspaceRootUri: URI; @@ -769,7 +769,7 @@ export interface ITerminalProcessExtHostRequest { isWorkspaceShellAllowed: boolean; } -export interface IExtensionTerminalRequest { +export interface IStartExtensionTerminalRequest { proxy: ITerminalProcessExtHostProxy; cols: number; rows: number; diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index 7093d6aa7f6..80923d84486 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -59,14 +59,13 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal // Request a process if needed, if this is a virtual process this step can be skipped as // there is no real "process" and we know it's ready on the ext host already. if (shellLaunchConfig.isExtensionTerminal) { - // TODO: This name should be improved - this._terminalService.requestExtensionTerminal(this, cols, rows); + this._terminalService.requestStartExtensionTerminal(this, cols, rows); } else { remoteAgentService.getEnvironment().then(env => { if (!env) { throw new Error('Could not fetch environment'); } - this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); + this._terminalService.requestSpawnExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); }); if (!hasReceivedResponse) { setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0); diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 36cbc613dba..1bb31239d69 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; @@ -53,10 +53,10 @@ export abstract class TerminalService implements ITerminalService { public get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } protected readonly _onInstanceProcessIdReady = new Emitter(); public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.event; } - protected readonly _onInstanceRequestExtHostProcess = new Emitter(); - public get onInstanceRequestExtHostProcess(): Event { return this._onInstanceRequestExtHostProcess.event; } - protected readonly _onInstanceRequestExtensionTerminal = new Emitter(); - public get onInstanceRequestExtensionTerminal(): Event { return this._onInstanceRequestExtensionTerminal.event; } + protected readonly _onInstanceRequestSpawnExtHostProcess = new Emitter(); + public get onInstanceRequestSpawnExtHostProcess(): Event { return this._onInstanceRequestSpawnExtHostProcess.event; } + protected readonly _onInstanceRequestStartExtensionTerminal = new Emitter(); + public get onInstanceRequestStartExtensionTerminal(): Event { return this._onInstanceRequestStartExtensionTerminal.event; } protected readonly _onInstanceDimensionsChanged = new Emitter(); public get onInstanceDimensionsChanged(): Event { return this._onInstanceDimensionsChanged.event; } protected readonly _onInstanceMaximumDimensionsChanged = new Emitter(); @@ -131,7 +131,7 @@ export abstract class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); } - public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { + public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { // Wait for the remoteAuthority to be ready (and listening for events) before proceeding const conn = this._remoteAgentService.getConnection(); @@ -140,12 +140,12 @@ export abstract class TerminalService implements ITerminalService { while (!this._extHostsReady[remoteAuthority] && ++retries < 50) { await timeout(100); } - this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); + this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); }); } - public requestExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { - this._onInstanceRequestExtensionTerminal.fire({ proxy, cols, rows }); + public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { + this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); } public extHostReady(remoteAuthority: string): void { From ae86d9415f1889973f650fbad9740f4c1ad7ae19 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 16:24:04 -0700 Subject: [PATCH 063/111] Remove suite.only --- .../src/singlefolder-tests/workspace.tasks.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts index 695ac4b0f59..56559d6aacc 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -suite.only('workspace-namespace', () => { +suite('workspace-namespace', () => { suite('Tasks', () => { From d471d1c7f918ff567e71026671896f17f388a784 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 16:24:04 -0700 Subject: [PATCH 064/111] Remove suite.only --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 2 +- .../src/singlefolder-tests/workspace.tasks.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 63e39fdd2e4..8c78cf68ead 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -11,7 +11,7 @@ suite('window namespace tests', () => { // Disable conpty in integration tests because of https://github.com/microsoft/vscode/issues/76548 await workspace.getConfiguration('terminal.integrated').update('windowsEnableConpty', false, ConfigurationTarget.Global); }); - suite('Terminal', () => { + suite.skip('Terminal', () => { test('sendText immediately after createTerminal should not throw', (done) => { const reg1 = window.onDidOpenTerminal(term => { equal(terminal, term); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts index 43470d24e19..c839127a255 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -suite.only('workspace-namespace', () => { +suite('workspace-namespace', () => { suite('Tasks', () => { From 33dd83585571c33fb26cf1edad6b60a69bd908d5 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 16:35:55 -0700 Subject: [PATCH 065/111] Update yarn.lock This change happens on a clear run of yarn --- extensions/json-language-features/server/yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 1bb198a5210..13ab8c59ab0 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -134,3 +134,8 @@ vscode-uri@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== + +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== From 3a2423174cb205c5dde964c7a75b2372cb848d55 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 17:02:04 -0700 Subject: [PATCH 066/111] xterm@3.15.0-beta89 Diff: https://github.com/xtermjs/xterm.js/compare/378982a...689fb6b Changes: - Fix NPE when disposing detached terminals Fixes microsoft/vscode-remote-release#1033 --- .../src/singlefolder-tests/terminal.test.ts | 2 +- package.json | 2 +- remote/package.json | 2 +- remote/yarn.lock | 8 ++++---- yarn.lock | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 8c78cf68ead..63e39fdd2e4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -11,7 +11,7 @@ suite('window namespace tests', () => { // Disable conpty in integration tests because of https://github.com/microsoft/vscode/issues/76548 await workspace.getConfiguration('terminal.integrated').update('windowsEnableConpty', false, ConfigurationTarget.Global); }); - suite.skip('Terminal', () => { + suite('Terminal', () => { test('sendText immediately after createTerminal should not throw', (done) => { const reg1 = window.onDidOpenTerminal(term => { equal(terminal, term); diff --git a/package.json b/package.json index eee312cd134..f59a80c947f 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "vscode-ripgrep": "^1.5.5", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta88", + "xterm": "3.15.0-beta89", "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", diff --git a/remote/package.json b/remote/package.json index ccb412ef358..34ffee1a4be 100644 --- a/remote/package.json +++ b/remote/package.json @@ -20,7 +20,7 @@ "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.5", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta88", + "xterm": "3.15.0-beta89", "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", diff --git a/remote/yarn.lock b/remote/yarn.lock index b5077ce87a4..1c4e700f495 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -1159,10 +1159,10 @@ xterm-addon-web-links@0.1.0-beta10: resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta88: - version "3.15.0-beta88" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta88.tgz#9a1c8d8a869517a4a8f103426fe0a89473455aa4" - integrity sha512-4nWNf4AbeoTRyOrhmWah9tZTXRepNo4uxzXdGskBWC9dAtItjD6ShNgi5z+xuVB4NmKoDp1b8rWNNMJ1I6/TLA== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== yauzl@^2.9.2: version "2.10.0" diff --git a/yarn.lock b/yarn.lock index 700e0195f87..6c206d6fa00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9872,10 +9872,10 @@ xterm-addon-web-links@0.1.0-beta10: resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta88: - version "3.15.0-beta88" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta88.tgz#9a1c8d8a869517a4a8f103426fe0a89473455aa4" - integrity sha512-4nWNf4AbeoTRyOrhmWah9tZTXRepNo4uxzXdGskBWC9dAtItjD6ShNgi5z+xuVB4NmKoDp1b8rWNNMJ1I6/TLA== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== y18n@^3.2.1: version "3.2.1" From ce731779831c9a4f285730361f852d5c5b5dc2cc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 25 Jul 2019 17:27:15 -0700 Subject: [PATCH 067/111] Minimize diff --- src/vs/editor/contrib/find/simpleFindWidget.ts | 9 +++------ .../contrib/terminal/browser/terminalFindWidget.ts | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 02b522158d6..e3723366157 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -36,18 +36,16 @@ export abstract class SimpleFindWidget extends Widget { private prevBtn: SimpleButton; private nextBtn: SimpleButton; private foundMatch: boolean; - private readonly _invertDefaultDirection: boolean | undefined; constructor( @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, private readonly _state: FindReplaceState = new FindReplaceState(), showOptionButtons?: boolean, - invertDefaultDirection?: boolean + private readonly _invertDefaultDirection: boolean = false ) { super(); - this._invertDefaultDirection = invertDefaultDirection; this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewService, { label: NLS_FIND_INPUT_LABEL, placeholder: NLS_FIND_INPUT_PLACEHOLDER, @@ -96,14 +94,13 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - // Flip the direction search goes in the terminal case so it matches other terminals - this.find(this._invertDefaultDirection ? true : false); + this.find(this._invertDefaultDirection); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(this._invertDefaultDirection ? false : true); + this.find(!this._invertDefaultDirection); e.preventDefault(); return; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index f8035e70b4f..1ab97705568 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -8,6 +8,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; + export class TerminalFindWidget extends SimpleFindWidget { protected _findInputFocused: IContextKey; protected _findWidgetFocused: IContextKey; From 62a102ec0c863be7c7775ec9acb924bc7a217312 Mon Sep 17 00:00:00 2001 From: Sana Ajani Date: Thu, 25 Jul 2019 17:31:02 -0700 Subject: [PATCH 068/111] add office and sharepoint packages --- .../electron-browser/workspaceStatsService.ts | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index 5041cb4be1e..ff776387035 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -47,7 +47,22 @@ const ModulesToLookFor = [ 'azure-storage', 'firebase', '@google-cloud/common', - 'heroku-cli' + 'heroku-cli', + //Office and Sharepoint packages + '@microsoft/office-js', + '@microsoft/office-js-helpers', + '@types/office-js', + '@types/office-runtime', + 'office-ui-fabric-react', + '@uifabric/icons', + '@uifabric/merge-styles', + '@uifabric/styling', + '@uifabric/experiments', + '@uifabric/utilities', + '@microsoft/rush', + 'lerna', + 'just-task', + 'beachball' ]; const PyModulesToLookFor = [ 'azure', @@ -143,6 +158,20 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js-helpers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-runtime" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.office-ui-fabric-react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/icons" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/merge-styles" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/styling" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/experiments" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/utilities" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/rush" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.lerna" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.just-task" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.beachball" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, @@ -187,7 +216,8 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + } */ From e7070d00e6fed745adccccc79ee5a36f78a0eda2 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 19:11:33 -0700 Subject: [PATCH 069/111] Fix #74715. --- src/vs/editor/common/model/textModelSearch.ts | 6 ++++++ .../test/common/model/textModelSearch.test.ts | 19 +++++++++++++++++++ test/electron/renderer.html | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index 1b63ef93f9f..ec2bb71ec30 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -545,6 +545,12 @@ export class Searcher { const matchStartIndex = m.index; const matchLength = m[0].length; if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) { + if (matchLength === 0) { + // the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here + // we attempt to recover from that by advancing by one + this._searchRegex.lastIndex += 1; + continue; + } // Exit early if the regex matches the same range twice return null; } diff --git a/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index 1dc5e82b52c..6476015cb5d 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -733,4 +733,23 @@ suite('TextModelSearch', () => { assert(isMultilineRegexSource('\\n')); assert(isMultilineRegexSource('foo\\W')); }); + + test('issue #74715. \\d* finds empty string and stops searching.', () => { + let model = TextModel.createFromString('10.243.30.10'); + + let searchParams = new SearchParams('\\d*', true, false, null); + + let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100); + assert.deepEqual(actual, [ + new FindMatch(new Range(1, 1, 1, 3), ['10']), + new FindMatch(new Range(1, 3, 1, 3), ['']), + new FindMatch(new Range(1, 4, 1, 7), ['243']), + new FindMatch(new Range(1, 7, 1, 7), ['']), + new FindMatch(new Range(1, 8, 1, 10), ['30']), + new FindMatch(new Range(1, 10, 1, 10), ['']), + new FindMatch(new Range(1, 11, 1, 13), ['10']) + ]); + + model.dispose(); + }); }); diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 1eb67318bfa..10ddaaf3341 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -15,8 +15,8 @@ ui: 'tdd', timeout: 5000 }); - require('./renderer'); + require('/Users/penlv/code/vscode/test/electron/renderer'); - \ No newline at end of file + From f0f7220eed1ce0c2c967a9c5340c805e5db7f070 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 20:32:04 -0700 Subject: [PATCH 070/111] bump distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f59a80c947f..0bdff88bdee 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "60ca9cac46049ff774e34d11e335d172587da608", + "distro": "ecf90e8c66d243c7ac15e30c24b3cc437d0700dc", "author": { "name": "Microsoft Corporation" }, From 6d82826e990407364d5c829b73602a19ecdf7d00 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 25 Jul 2019 20:42:36 -0700 Subject: [PATCH 071/111] Revert test require renderer --- test/electron/renderer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 10ddaaf3341..72454389597 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -15,7 +15,7 @@ ui: 'tdd', timeout: 5000 }); - require('/Users/penlv/code/vscode/test/electron/renderer'); + require('./renderer'); From 9ead7b9775dd7375f5272e60c747764eeeb9d672 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 26 Jul 2019 09:58:15 +0200 Subject: [PATCH 072/111] RemoteConnectionState not disconnected when initialization fails (for microsoft/vscode-remote-release#1029) --- .../electron-browser/remote.contribution.ts | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 9f861987bc4..04975876713 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -49,7 +49,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc private windowCommandMenu: IMenu; private hasWindowActions: boolean = false; private remoteAuthority: string | undefined; - private disconnected: boolean = true; + private connectionState: 'initializing' | 'connected' | 'disconnected' | undefined = undefined; constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, @@ -76,7 +76,8 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc if (this.remoteAuthority) { // Pending entry until extensions are ready this.renderWindowIndicator(nls.localize('host.open', "$(sync~spin) Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID); - RemoteConnectionState.bindTo(this.contextKeyService).set('initializing'); + this.connectionState = 'initializing'; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', @@ -86,6 +87,23 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc }, order: 3.5 }); + + const connection = remoteAgentService.getConnection(); + if (connection) { + this._register(connection.onDidStateChange((e) => { + switch (e.type) { + case PersistentConnectionEventType.ConnectionLost: + case PersistentConnectionEventType.ReconnectionPermanentFailure: + case PersistentConnectionEventType.ReconnectionRunning: + case PersistentConnectionEventType.ReconnectionWait: + this.setDisconnected(true); + break; + case PersistentConnectionEventType.ConnectionGain: + this.setDisconnected(false); + break; + } + })); + } } extensionService.whenInstalledExtensionsRegistered().then(_ => { @@ -96,30 +114,14 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc this._register(this.windowCommandMenu.onDidChange(e => this.updateWindowActions())); this.updateWindowIndicator(); }); - - const connection = remoteAgentService.getConnection(); - if (connection) { - this._register(connection.onDidStateChange((e) => { - switch (e.type) { - case PersistentConnectionEventType.ConnectionLost: - case PersistentConnectionEventType.ReconnectionPermanentFailure: - case PersistentConnectionEventType.ReconnectionRunning: - case PersistentConnectionEventType.ReconnectionWait: - this.setDisconnected(true); - break; - case PersistentConnectionEventType.ConnectionGain: - this.setDisconnected(false); - break; - } - })); - } } private setDisconnected(isDisconnected: boolean): void { - if (this.disconnected !== isDisconnected) { - this.disconnected = isDisconnected; - RemoteConnectionState.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected' : 'connected'); - Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? '' : this.remoteAuthority || `disconnected/${this.remoteAuthority}`); + const newState = isDisconnected ? 'disconnected' : 'connected'; + if (this.connectionState !== newState) { + this.connectionState = newState; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); + Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected/${this.remoteAuthority!}' : this.remoteAuthority!); this.updateWindowIndicator(); } } @@ -128,7 +130,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc const windowActionCommand = (this.remoteAuthority || this.windowCommandMenu.getActions().length) ? WINDOW_ACTIONS_COMMAND_ID : undefined; if (this.remoteAuthority) { const hostLabel = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.remoteAuthority) || this.remoteAuthority; - if (!this.disconnected) { + if (this.connectionState !== 'disconnected') { this.renderWindowIndicator(`$(remote) ${hostLabel}`, nls.localize('host.tooltip', "Editing on {0}", hostLabel), windowActionCommand); } else { this.renderWindowIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from")} ${hostLabel}`, nls.localize('host.tooltipDisconnected', "Disconnected from {0}", hostLabel), windowActionCommand); @@ -468,4 +470,4 @@ Registry.as(ConfigurationExtensions.Configuration) } } } - }); \ No newline at end of file + }); From 3e9cac9b85d68766a4f3b45f17484bb979917a69 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 11:30:06 +0200 Subject: [PATCH 073/111] properly cancel suggestion details requests, #77926 --- src/vs/editor/contrib/suggest/suggestWidget.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 9fa0cc0a87b..9d020eaf89c 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -672,7 +672,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.list.length < index) { + if (index >= this.list.length || item !== this.list.element(index)) { return; } @@ -689,11 +689,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.focusedItem === item) { - this.currentSuggestionDetails = null; - } - }); + }).catch(onUnexpectedError); } // emit an event From 0911c90ac4e7fbd8b46d339aa84ebb83a41c63a5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 11:44:04 +0200 Subject: [PATCH 074/111] suggest - keep commit character when item isn't changing --- src/vs/editor/contrib/suggest/suggestCommitCharacters.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index 8a6fca72612..20a7656532a 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -36,10 +36,17 @@ export class CommitCharacterController { private _onItem(selected: ISelectedSuggestion | undefined): void { if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) { + // no item or no commit characters this.reset(); return; } + if (this._active && this._active.item.item === selected.item) { + // still the same item + return; + } + + // keep item and its commit characters const acceptCharacters = new CharacterSet(); for (const ch of selected.item.completion.commitCharacters) { if (ch.length > 0) { From a7122371aaa76237b155cd38c57e9d66a5f47637 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 11:56:20 +0200 Subject: [PATCH 075/111] dispo - add some more DisposableStore usage --- .../editor/contrib/suggest/suggestWidget.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 9d020eaf89c..e6ac05dab25 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -50,7 +50,7 @@ interface ISuggestionTemplateData { iconLabel: IconLabel; typeLabel: HTMLElement; readMore: HTMLElement; - disposables: IDisposable[]; + disposables: DisposableStore; } /** @@ -106,8 +106,7 @@ class Renderer implements IListRenderer renderTemplate(container: HTMLElement): ISuggestionTemplateData { const data = Object.create(null); - const disposables = new DisposableStore(); - data.disposables = [disposables]; + data.disposables = new DisposableStore(); data.root = container; addClass(data.root, 'show-file-icons'); @@ -119,7 +118,7 @@ class Renderer implements IListRenderer const main = append(text, $('.main')); data.iconLabel = new IconLabel(main, { supportHighlights: true }); - disposables.add(data.iconLabel); + data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); @@ -147,7 +146,7 @@ class Renderer implements IListRenderer configureFont(); - disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo || e.contribInfo) .on(configureFont, null)); @@ -218,7 +217,7 @@ class Renderer implements IListRenderer } disposeTemplate(templateData: ISuggestionTemplateData): void { - templateData.disposables = dispose(templateData.disposables); + templateData.disposables.dispose(); } } @@ -253,7 +252,7 @@ class SuggestionDetails { private type: HTMLElement; private docs: HTMLElement; private ariaLabel: string | null; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore; private renderDisposeable: IDisposable; private borderWidth: number = 1; @@ -264,16 +263,16 @@ class SuggestionDetails { private readonly markdownRenderer: MarkdownRenderer, private readonly triggerKeybindingLabel: string, ) { - this.disposables = []; + this.disposables = new DisposableStore(); this.el = append(container, $('.details')); - this.disposables.push(toDisposable(() => container.removeChild(this.el))); + this.disposables.add(toDisposable(() => container.removeChild(this.el))); this.body = $('.body'); this.scrollbar = new DomScrollableElement(this.body, {}); append(this.el, this.scrollbar.getDomNode()); - this.disposables.push(this.scrollbar); + this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); @@ -414,7 +413,7 @@ class SuggestionDetails { } dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); this.renderDisposeable = dispose(this.renderDisposeable); } } From 98fc1148c923e7fae1d9e4b7993965dd238be495 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 14:18:57 +0200 Subject: [PATCH 076/111] :lipstick: --- .../common/inactiveExtensionUrlHandler.ts | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index bf7bb20ec81..7330ceedefb 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -96,8 +96,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } - const confirmedExtensionIds = this.getConfirmedExtensionIds(); - confirmed = confirmed || confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + if (!confirmed) { + const confirmedExtensionIds = this.getConfirmedExtensionIds(); + confirmed = confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + } if (!confirmed) { let uriString = uri.toString(); @@ -283,18 +285,17 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } private getConfirmedExtensionIds(): Set { - return new Set([ + const ids = [ ...this.getConfirmedExtensionIdsFromStorage(), ...this.getConfirmedExtensionIdsFromConfiguration(), - ].map( - extensionId => ExtensionIdentifier.toKey(extensionId) - )); + ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + + return new Set(ids); } private getConfirmedExtensionIdsFromConfiguration(): Array { - const confirmedExtensionIds = this.configurationService.getValue>( - CONFIRMED_EXTENSIONS_CONFIGURATION_KEY - ); + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + if (!Array.isArray(confirmedExtensionIds)) { return []; } @@ -303,17 +304,15 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } private getConfirmedExtensionIdsFromStorage(): Array { - const confirmedExtensionIdsJson = this.storageService.get( - CONFIRMED_EXTENSIONS_STORAGE_KEY, - StorageScope.GLOBAL, - '[]', - ); + const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + try { return JSON.parse(confirmedExtensionIdsJson); } catch (err) { return []; } } + private addConfirmedExtensionIdToStorage(extensionId: string): void { const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); this.storageService.store( From 8213baf0769d63d6bc65db25b93fc5fb91432173 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 14:37:33 +0200 Subject: [PATCH 077/111] extract first repository.status call related to https://github.com/microsoft/vscode/issues/77787#issuecomment-515207062 --- extensions/git/src/model.ts | 1 + extensions/git/src/repository.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index c410dde86bd..da6a940428e 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -251,6 +251,7 @@ export class Model { const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState, this.outputChannel); this.open(repository); + await repository.status(); } catch (err) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { return; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index a581f9f5fd4..36366ad7d09 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -713,7 +713,6 @@ export class Repository implements Disposable { this.disposables.push(progressManager); this.updateCommitTemplate(); - this.status(); } validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined { From be873f71699b8617e088c8f5ecd57f56e6ad140f Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Fri, 26 Jul 2019 15:16:12 +0200 Subject: [PATCH 078/111] pass env and cwd to createTerminal; fixes #77111 --- .../workbench/api/node/extHostDebugService.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index d9172447d73..be353ca5bde 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -341,19 +341,29 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else { resolve(true); } - }).then(needNewTerminal => { + }).then(async needNewTerminal => { + + const configProvider = await this._configurationService.getConfigProvider(); + const shell = this._terminalService.getDefaultShell(configProvider); if (needNewTerminal || !this._integratedTerminalInstance) { - this._integratedTerminalInstance = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee")); + const options: vscode.TerminalOptions = { + shellPath: shell, + // shellArgs: this._terminalService._getDefaultShellArgs(configProvider), + cwd: args.cwd, + name: args.title || nls.localize('debug.terminal.title', "debuggee"), + env: args.env + }; + delete args.cwd; + delete args.env; + this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options); } const terminal: vscode.Terminal = this._integratedTerminalInstance; terminal.show(); - return this._integratedTerminalInstance.processId.then(async shellProcessId => { + return this._integratedTerminalInstance.processId.then(shellProcessId => { - const configProvider = await this._configurationService.getConfigProvider(); - const shell = this._terminalService.getDefaultShell(configProvider); const command = prepareCommand(args, shell, configProvider); terminal.sendText(command, true); From 4882ae5b9e5e5c21faaf95e28cd5f31dfe38892f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 15:24:11 +0200 Subject: [PATCH 079/111] Revert "Add inline deprecated styling to suggest widget" This reverts commit 4a2b010e340412961bf64022eac3f68c70c52066. --- src/vs/editor/common/model/intervalTree.ts | 2 +- src/vs/editor/contrib/suggest/media/suggest.css | 7 ------- src/vs/editor/contrib/suggest/suggestWidget.ts | 5 ----- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index 1815f7ee86f..d400024e7c5 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -18,7 +18,7 @@ export const enum ClassName { EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', - EditorDeprecatedInlineDecoration = 'inline-deprecated' + EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 2f740dfad64..09594abb493 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -97,13 +97,6 @@ font-weight: bold; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .inline-deprecated { - text-decoration: none; /* override normal inline behavior due to HTML structure */ -} -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .inline-deprecated span { - text-decoration: line-through; -} - /** Icon styles **/ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 9eb1398848d..9e02b37f673 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -9,7 +9,6 @@ import { createMatches } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { ClassName } from 'vs/editor/common/model/intervalTree'; import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; @@ -197,10 +196,6 @@ class Renderer implements IListRenderer ]; } - if (suggestion.label && suggestion.deprecated) { - labelOptions.extraClasses = (labelOptions.extraClasses || []).concat([ClassName.EditorDeprecatedInlineDecoration]); - } - data.iconLabel.setLabel(suggestion.label, undefined, labelOptions); data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); From 53006c0af48632dd79268bab6534abd8f13b7e3b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 15:24:21 +0200 Subject: [PATCH 080/111] Revert "Add deprecated support to SuggestDataDto" This reverts commit 87ae3a38d337ade925a009cf86d82f11d36fe476. --- src/vs/vscode.proposed.d.ts | 7 ------- src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts | 1 - src/vs/workbench/api/common/extHost.protocol.ts | 1 - src/vs/workbench/api/common/extHostLanguageFeatures.ts | 1 - 4 files changed, 10 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index a495e65a268..6a31141bb94 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1277,13 +1277,6 @@ declare module 'vscode' { //#region Deprecated support - export interface CompletionItem { - /** - * Indicates if this item is deprecated. - */ - deprecated?: boolean; - } - export enum DiagnosticTag { /** * Deprecated or obsolete code diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 3541ba2eef0..75af9eebf01 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -341,7 +341,6 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha commitCharacters: data.k, additionalTextEdits: data.l, command: data.m, - deprecated: data.n, // not-standard _id: data.x, }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 1e30b620dca..8fb612d3a7c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -937,7 +937,6 @@ export interface SuggestDataDto { k/* commitCharacters */?: string[]; l/* additionalTextEdits */?: ISingleEditOperation[]; m/* command */?: modes.Command; - n/* deprecated */?: boolean; // not-standard x?: ChainedCacheId; } diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 6c7065f29f2..884618cc457 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -736,7 +736,6 @@ class SuggestAdapter { k: item.commitCharacters, l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), m: this._commands.toInternal(item.command, disposables), - n: item.deprecated }; // 'insertText'-logic From 29f6ec0b34516474babf46710770a735887a2c85 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 15:24:30 +0200 Subject: [PATCH 081/111] Revert "Add CompletionItem.deprecated property from LSP" This reverts commit 895d6323b4a7686dbc9533c09bbc76fd741f195d. --- src/vs/editor/common/modes.ts | 4 ---- src/vs/monaco.d.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index dbeb3fb1956..fa05b9b968c 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -396,10 +396,6 @@ export interface CompletionItem { * an icon is chosen by the editor. */ kind: CompletionItemKind; - /** - * Indicates if this item is deprecated. - */ - deprecated?: boolean; /** * A human-readable string with additional information * about this item, like type or symbol information. diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 75692fbcceb..982a16b87ef 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4790,10 +4790,6 @@ declare namespace monaco.languages { * an icon is chosen by the editor. */ kind: CompletionItemKind; - /** - * Indicates if this item is deprecated. - */ - deprecated?: boolean; /** * A human-readable string with additional information * about this item, like type or symbol information. From a154f8f45185fc4d87b5d159c9a6e6678623d190 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 15:33:27 +0200 Subject: [PATCH 082/111] fixes #77345 --- extensions/git/src/repository.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 36366ad7d09..196a1bddade 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -519,8 +519,8 @@ class DotGitWatcher implements IFileWatcher { this.transientDisposables.push(upstreamWatcher); upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables); } catch (err) { - if (env.logLevel <= LogLevel.Info) { - this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}'. Ref is most likely packed.`); + if (env.logLevel <= LogLevel.Error) { + this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}', is most likely packed.\n${err.stack || err}`); } } } @@ -651,19 +651,30 @@ export class Repository implements Disposable { const onWorkspaceRepositoryFileChange = filterEvent(onWorkspaceFileChange, uri => isDescendant(repository.root, uri.fsPath)); const onWorkspaceWorkingTreeFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => !/\/\.git($|\/)/.test(uri.path)); - const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); - this.disposables.push(dotGitFileWatcher); + let onDotGitFileChange: Event; + + try { + const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); + onDotGitFileChange = dotGitFileWatcher.event; + this.disposables.push(dotGitFileWatcher); + } catch (err) { + if (env.logLevel <= LogLevel.Error) { + outputChannel.appendLine(`Failed to watch '${this.dotGit}', reverting to legacy API file watched. Some events might be lost.\n${err.stack || err}`); + } + + onDotGitFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => /\/\.git($|\/)/.test(uri.path)); + } // FS changes should trigger `git status`: // - any change inside the repository working tree // - any change whithin the first level of the `.git` folder, except the folder itself and `index.lock` - const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event); + const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, onDotGitFileChange); onFileChange(this.onFileChange, this, this.disposables); // Relevate repository changes should trigger virtual document change events - dotGitFileWatcher.event(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); + onDotGitFileChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); - this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event, outputChannel)); + this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, onDotGitFileChange, outputChannel)); const root = Uri.file(repository.root); this._sourceControl = scm.createSourceControl('git', 'Git', root); From c96cf5d4d9cf0bcab5d10a6511dbe57d41f4245a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 16:08:27 +0200 Subject: [PATCH 083/111] fixes #76508 --- build/gulpfile.reh.js | 2 +- build/lib/extensions.js | 2 +- build/lib/extensions.ts | 2 +- build/lib/typings/gulp-remote-src.d.ts | 4 +-- package.json | 2 +- yarn.lock | 39 ++++++++++++++++++++------ 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 8784602db3e..7085c4f8f50 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -17,7 +17,7 @@ const gunzip = require('gulp-gunzip'); const untar = require('gulp-untar'); const File = require('vinyl'); const fs = require('fs'); -const remote = require('gulp-remote-src'); +const remote = require('gulp-remote-retry-src'); const rename = require('gulp-rename'); const filter = require('gulp-filter'); const cp = require('child_process'); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index a73f8cf5864..73d2c7acef3 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -13,7 +13,7 @@ const File = require("vinyl"); const vsce = require("vsce"); const stats_1 = require("./stats"); const util2 = require("./util"); -const remote = require("gulp-remote-src"); +const remote = require("gulp-remote-retry-src"); const vzip = require('gulp-vinyl-zip'); const filter = require("gulp-filter"); const rename = require("gulp-rename"); diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 94bc81c15df..4b185aff681 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -13,7 +13,7 @@ import * as File from 'vinyl'; import * as vsce from 'vsce'; import { createStatsStream } from './stats'; import * as util2 from './util'; -import remote = require('gulp-remote-src'); +import remote = require('gulp-remote-retry-src'); const vzip = require('gulp-vinyl-zip'); import filter = require('gulp-filter'); import rename = require('gulp-rename'); diff --git a/build/lib/typings/gulp-remote-src.d.ts b/build/lib/typings/gulp-remote-src.d.ts index 6ea57f84fe5..ff9026b79bb 100644 --- a/build/lib/typings/gulp-remote-src.d.ts +++ b/build/lib/typings/gulp-remote-src.d.ts @@ -1,4 +1,4 @@ -declare module 'gulp-remote-src' { +declare module 'gulp-remote-retry-src' { import stream = require("stream"); @@ -20,4 +20,4 @@ declare module 'gulp-remote-src' { } export = remote; -} \ No newline at end of file +} diff --git a/package.json b/package.json index 0bdff88bdee..f973590748b 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "gulp-gunzip": "^1.0.0", "gulp-json-editor": "^2.5.0", "gulp-plumber": "^1.2.0", - "gulp-remote-src": "^0.4.4", + "gulp-remote-retry-src": "^0.6.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", diff --git a/yarn.lock b/yarn.lock index 6c206d6fa00..f1c162556e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3907,14 +3907,15 @@ gulp-plumber@^1.2.0: plugin-error "^0.1.2" through2 "^2.0.3" -gulp-remote-src@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz#4a4d18fac0ffedde94a7855953de90db00a1d1b1" - integrity sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA== +gulp-remote-retry-src@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/gulp-remote-retry-src/-/gulp-remote-retry-src-0.6.0.tgz#fdcb5d5c9e67c31ae378a2a886ddad3d47913bb1" + integrity sha512-lFxpwwbM/GEIdYiNumxiUcPHZUROFJaF1zTBne1H8b3Pwx6Te6O9uEYp++JZPP62jdheOWcHUTBREiMkpdbm4Q== dependencies: event-stream "3.3.4" node.extend "~1.1.2" request "^2.88.0" + requestretry "^4.0.0" through2 "~2.0.3" vinyl "~2.0.1" @@ -4161,6 +4162,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -6088,11 +6096,12 @@ node-pty@0.9.0-beta19: nan "^2.13.2" node.extend@~1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" - integrity sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y= + version "1.1.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" + integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== dependencies: - is "^3.1.0" + has "^1.0.3" + is "^3.2.1" noop-logger@^0.1.1: version "0.1.1" @@ -7737,6 +7746,15 @@ request@^2.86.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +requestretry@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.0.0.tgz#4e9e7280a7d8561bf33e9925264cf026e2be3e89" + integrity sha512-ST8m0+5FQH2FA+gbzUQyOQjUwHf22kbPQnd6TexveR0p+2UV1YYBg+Roe7BnKQ1Bb/+LtJwwm0QzxK2NA20Cug== + dependencies: + extend "^3.0.2" + lodash "^4.17.10" + when "^3.7.7" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -9684,6 +9702,11 @@ webpack@^4.16.5, webpack@^4.7.0: watchpack "^1.5.0" webpack-sources "^1.0.1" +when@^3.7.7: + version "3.7.8" + resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" + integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" From e788b154d1d95e99b5dd01eca2eae365cfdeb729 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 26 Jul 2019 11:25:05 +0200 Subject: [PATCH 084/111] Fix usage of context keys --- src/vs/platform/browser/contextScopedHistoryWidget.ts | 6 +++--- src/vs/workbench/contrib/scm/browser/scm.contribution.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/browser/contextScopedHistoryWidget.ts b/src/vs/platform/browser/contextScopedHistoryWidget.ts index 94d4de658b5..5e5e8603683 100644 --- a/src/vs/platform/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/browser/contextScopedHistoryWidget.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox'; import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; @@ -66,7 +66,7 @@ export class ContextScopedFindInput extends FindInput { KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showPrevious', weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow], handler: (accessor, arg2) => { @@ -81,7 +81,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showNext', weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyAndExpr([new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)]), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow], handler: (accessor, arg2) => { diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index db9568a6eb4..beef3cdc9fb 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -18,7 +18,7 @@ import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ContextKeyDefinedExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -115,7 +115,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'scm.acceptInput', description: { description: localize('scm accept', "SCM: Accept Input"), args: [] }, weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyDefinedExpr('scmRepository'), + when: ContextKeyExpr.has('scmRepository'), primary: KeyMod.CtrlCmd | KeyCode.Enter, handler: accessor => { const contextKeyService = accessor.get(IContextKeyService); @@ -134,4 +134,4 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -registerSingleton(ISCMService, SCMService); \ No newline at end of file +registerSingleton(ISCMService, SCMService); From 893635042ccd4dbdf919a4493a062330aec2cbc7 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 26 Jul 2019 16:35:45 +0200 Subject: [PATCH 085/111] Fixes #22778: Add `or` for when clause contexts --- .../standalone/browser/simpleServices.ts | 2 +- .../platform/contextkey/common/contextkey.ts | 394 ++++++++++++++---- .../contextkey/test/common/contextkey.test.ts | 31 +- .../keybinding/common/keybindingResolver.ts | 40 +- .../test/common/keybindingResolver.test.ts | 83 ++-- .../parts/editor/editor.contribution.ts | 2 +- .../debug/browser/debug.contribution.ts | 2 +- .../files/browser/fileActions.contribution.ts | 2 +- .../keybinding/browser/keybindingService.ts | 4 +- 9 files changed, 387 insertions(+), 173 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 576092c9865..d333ce03746 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -356,7 +356,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 289ba8668ce..8c01c1452d8 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -13,7 +13,9 @@ export const enum ContextKeyExprType { Equals = 3, NotEquals = 4, And = 5, - Regex = 6 + Regex = 6, + NotRegex = 7, + Or = 8 } export interface IContextKeyExprMapper { @@ -27,27 +29,31 @@ export interface IContextKeyExprMapper { export abstract class ContextKeyExpr { public static has(key: string): ContextKeyExpr { - return new ContextKeyDefinedExpr(key); + return ContextKeyDefinedExpr.create(key); } public static equals(key: string, value: any): ContextKeyExpr { - return new ContextKeyEqualsExpr(key, value); + return ContextKeyEqualsExpr.create(key, value); } public static notEquals(key: string, value: any): ContextKeyExpr { - return new ContextKeyNotEqualsExpr(key, value); + return ContextKeyNotEqualsExpr.create(key, value); } public static regex(key: string, value: RegExp): ContextKeyExpr { - return new ContextKeyRegexExpr(key, value); + return ContextKeyRegexExpr.create(key, value); } public static not(key: string): ContextKeyExpr { - return new ContextKeyNotExpr(key); + return ContextKeyNotExpr.create(key); } - public static and(...expr: Array): ContextKeyExpr { - return new ContextKeyAndExpr(expr); + public static and(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyAndExpr.create(expr); + } + + public static or(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyOrExpr.create(expr); } public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | undefined { @@ -55,9 +61,17 @@ export abstract class ContextKeyExpr { return undefined; } + return this._deserializeOrExpression(serialized, strict); + } + + private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { + let pieces = serialized.split('||'); + return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict))); + } + + private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { let pieces = serialized.split('&&'); - let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict))); - return result.normalize(); + return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict))); } private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr { @@ -65,24 +79,24 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf('!=') >= 0) { let pieces = serializedOne.split('!='); - return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('==') >= 0) { let pieces = serializedOne.split('=='); - return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); - return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); + return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); } if (/^\!\s*/.test(serializedOne)) { - return new ContextKeyNotExpr(serializedOne.substr(1).trim()); + return ContextKeyNotExpr.create(serializedOne.substr(1).trim()); } - return new ContextKeyDefinedExpr(serializedOne); + return ContextKeyDefinedExpr.create(serializedOne); } private static _deserializeValue(serializedValue: string, strict: boolean): any { @@ -143,10 +157,10 @@ export abstract class ContextKeyExpr { public abstract getType(): ContextKeyExprType; public abstract equals(other: ContextKeyExpr): boolean; public abstract evaluate(context: IContext): boolean; - public abstract normalize(): ContextKeyExpr | undefined; public abstract serialize(): string; public abstract keys(): string[]; public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr; + public abstract negate(): ContextKeyExpr; } function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { @@ -166,13 +180,21 @@ function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { return (a).cmp(b); case ContextKeyExprType.Regex: return (a).cmp(b); + case ContextKeyExprType.NotRegex: + return (a).cmp(b); + case ContextKeyExprType.And: + return (a).cmp(b); default: throw new Error('Unknown ContextKeyExpr!'); } } export class ContextKeyDefinedExpr implements ContextKeyExpr { - constructor(protected key: string) { + public static create(key: string): ContextKeyExpr { + return new ContextKeyDefinedExpr(key); + } + + protected constructor(protected key: string) { } public getType(): ContextKeyExprType { @@ -200,10 +222,6 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { return (!!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return this.key; } @@ -215,10 +233,25 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapDefined(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyNotExpr.create(this.key); + } } export class ContextKeyEqualsExpr implements ContextKeyExpr { - constructor(private readonly key: string, private readonly value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyDefinedExpr.create(key); + } + return ContextKeyNotExpr.create(key); + } + return new ContextKeyEqualsExpr(key, value); + } + + private constructor(private readonly key: string, private readonly value: any) { } public getType(): ContextKeyExprType { @@ -255,21 +288,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyDefinedExpr(this.key); - } - return new ContextKeyNotExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' == \'' + this.value + '\''; } @@ -280,10 +299,25 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyNotEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotEqualsExpr implements ContextKeyExpr { - constructor(private key: string, private value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyNotExpr.create(key); + } + return ContextKeyDefinedExpr.create(key); + } + return new ContextKeyNotEqualsExpr(key, value); + } + + private constructor(private key: string, private value: any) { } public getType(): ContextKeyExprType { @@ -320,21 +354,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyNotExpr(this.key); - } - return new ContextKeyDefinedExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' != \'' + this.value + '\''; } @@ -345,10 +365,19 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNotEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotExpr implements ContextKeyExpr { - constructor(private key: string) { + + public static create(key: string): ContextKeyExpr { + return new ContextKeyNotExpr(key); + } + + private constructor(private key: string) { } public getType(): ContextKeyExprType { @@ -376,10 +405,6 @@ export class ContextKeyNotExpr implements ContextKeyExpr { return (!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return '!' + this.key; } @@ -391,11 +416,19 @@ export class ContextKeyNotExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNot(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyDefinedExpr.create(this.key); + } } export class ContextKeyRegexExpr implements ContextKeyExpr { - constructor(private key: string, private regexp: RegExp | null) { + public static create(key: string, regexp: RegExp | null): ContextKeyExpr { + return new ContextKeyRegexExpr(key, regexp); + } + + private constructor(private key: string, private regexp: RegExp | null) { // } @@ -435,10 +468,6 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return this.regexp ? this.regexp.test(value) : false; } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { const value = this.regexp ? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}` @@ -450,22 +479,99 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr { return mapFnc.mapRegex(this.key, this.regexp); } + + public negate(): ContextKeyExpr { + return ContextKeyNotRegexExpr.create(this); + } +} + +export class ContextKeyNotRegexExpr implements ContextKeyExpr { + + public static create(actual: ContextKeyRegexExpr): ContextKeyExpr { + return new ContextKeyNotRegexExpr(actual); + } + + private constructor(private readonly _actual: ContextKeyRegexExpr) { + // + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.NotRegex; + } + + public cmp(other: ContextKeyNotRegexExpr): number { + return this._actual.cmp(other._actual); + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyNotRegexExpr) { + return this._actual.equals(other._actual); + } + return false; + } + + public evaluate(context: IContext): boolean { + return !this._actual.evaluate(context); + } + + public serialize(): string { + throw new Error('Method not implemented.'); + } + + public keys(): string[] { + return this._actual.keys(); + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyNotRegexExpr(this._actual.map(mapFnc)); + } + + public negate(): ContextKeyExpr { + return this._actual; + } } export class ContextKeyAndExpr implements ContextKeyExpr { - public readonly expr: ContextKeyExpr[]; - constructor(expr: Array) { - this.expr = ContextKeyAndExpr._normalizeArr(expr); + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyAndExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyAndExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { } public getType(): ContextKeyExprType { return ContextKeyExprType.And; } + public cmp(other: ContextKeyAndExpr): number { + if (this.expr.length < other.expr.length) { + return -1; + } + if (this.expr.length > other.expr.length) { + return 1; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + const r = cmp(this.expr[i], other.expr[i]); + if (r !== 0) { + return r; + } + } + return 0; + } + public equals(other: ContextKeyExpr): boolean { if (other instanceof ContextKeyAndExpr) { if (this.expr.length !== other.expr.length) { @@ -500,16 +606,16 @@ export class ContextKeyAndExpr implements ContextKeyExpr { continue; } - e = e.normalize(); - if (!e) { - continue; - } - if (e instanceof ContextKeyAndExpr) { expr = expr.concat(e.expr); continue; } + if (e instanceof ContextKeyOrExpr) { + // Not allowed, because we don't have parens! + throw new Error(`It is not allowed to have an or expression here due to lack of parens!`); + } + expr.push(e); } @@ -519,29 +625,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return expr; } - public normalize(): ContextKeyExpr | undefined { - if (this.expr.length === 0) { - return undefined; - } - - if (this.expr.length === 1) { - return this.expr[0]; - } - - return this; - } - public serialize(): string { - if (this.expr.length === 0) { - return ''; - } - if (this.expr.length === 1) { - const normalized = this.normalize(); - if (!normalized) { - return ''; - } - return normalized.serialize(); - } return this.expr.map(e => e.serialize()).join(' && '); } @@ -556,6 +640,132 @@ export class ContextKeyAndExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc))); } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + return ContextKeyOrExpr.create(result)!; + } +} + +export class ContextKeyOrExpr implements ContextKeyExpr { + + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyOrExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyOrExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.Or; + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyOrExpr) { + if (this.expr.length !== other.expr.length) { + return false; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + if (!this.expr[i].equals(other.expr[i])) { + return false; + } + } + return true; + } + return false; + } + + public evaluate(context: IContext): boolean { + for (let i = 0, len = this.expr.length; i < len; i++) { + if (this.expr[i].evaluate(context)) { + return true; + } + } + return false; + } + + private static _normalizeArr(arr: Array): ContextKeyExpr[] { + let expr: ContextKeyExpr[] = []; + + if (arr) { + for (let i = 0, len = arr.length; i < len; i++) { + let e: ContextKeyExpr | null | undefined = arr[i]; + if (!e) { + continue; + } + + if (e instanceof ContextKeyOrExpr) { + expr = expr.concat(e.expr); + continue; + } + + expr.push(e); + } + + expr.sort(cmp); + } + + return expr; + } + + public serialize(): string { + return this.expr.map(e => e.serialize()).join(' || '); + } + + public keys(): string[] { + const result: string[] = []; + for (let expr of this.expr) { + result.push(...expr.keys()); + } + return result; + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc))); + } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; + } + return [node]; + }; + + // We don't support parens, so here we distribute the AND over the OR terminals + // We always take the first 2 AND pairs and distribute them + while (result.length > 1) { + const LEFT = result.shift()!; + const RIGHT = result.shift()!; + + const all: ContextKeyExpr[] = []; + for (const left of terminals(LEFT)) { + for (const right of terminals(RIGHT)) { + all.push(ContextKeyExpr.and(left, right)!); + } + } + result.unshift(ContextKeyExpr.or(...all)!); + } + + return result[0]; + } } export class RawContextKey extends ContextKeyDefinedExpr { diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index cb12470e3c2..9db3782da31 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -27,7 +27,7 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.not('d1'), ContextKeyExpr.not('d2') - ); + )!; let b = ContextKeyExpr.and( ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), @@ -40,7 +40,7 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)), ContextKeyExpr.not('d2') - ); + )!; assert(a.equals(b), 'expressions should be equal'); }); @@ -50,10 +50,10 @@ suite('ContextKeyExpr', () => { let key1IsFalse = ContextKeyExpr.equals('key1', false); let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - assert.ok(key1IsTrue.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsNotFalse.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsFalse.normalize()!.equals(ContextKeyExpr.not('key1'))); - assert.ok(key1IsNotTrue.normalize()!.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsTrue.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsNotFalse.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsFalse.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsNotTrue.equals(ContextKeyExpr.not('key1'))); }); test('evaluate', () => { @@ -93,5 +93,24 @@ suite('ContextKeyExpr', () => { testExpression('a && !b && c == 5', true && !false && '5' == '5'); testExpression('d =~ /e.*/', false); /* tslint:enable:triple-equals */ + + // precedence test: false && true || true === true because && is evaluated first + testExpression('b && a || a', true); + + testExpression('a || b', true); + testExpression('b || b', false); + testExpression('b && a || a && b', false); + }); + + test('negate', () => { + function testNegate(expr: string, expected: string): void { + const actual = ContextKeyExpr.deserialize(expr)!.negate().serialize(); + assert.strictEqual(actual, expected); + } + testNegate('a', '!a'); + testNegate('a && b || c', '!a && !c || !b && !c'); + testNegate('a && b || c || d', '!a && !c && !d || !b && !c && !d'); + testNegate('!a && !b || !c && !d', 'a && c || a && d || b && c || b && d'); + testNegate('!a && !b || !c && !d || !e && !f', 'a && c && e || a && c && f || a && d && e || a && d && f || b && c && e || b && c && f || b && d && e || b && d && f'); }); }); diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 1436cfa6604..29d559eab4d 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, ContextKeyOrExpr } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { keys } from 'vs/base/common/map'; @@ -171,7 +171,6 @@ export class KeybindingResolver { /** * Returns true if it is provable `a` implies `b`. - * **Precondition**: Assumes `a` and `b` are normalized! */ public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean { if (!b) { @@ -181,26 +180,35 @@ export class KeybindingResolver { return false; } - const aExpressions: ContextKeyExpr[] = ((a instanceof ContextKeyAndExpr) ? a.expr : [a]); - const bExpressions: ContextKeyExpr[] = ((b instanceof ContextKeyAndExpr) ? b.expr : [b]); + return this._implies(a, b); + } - let aIndex = 0; - for (const bExpr of bExpressions) { - let bExprMatched = false; - while (!bExprMatched && aIndex < aExpressions.length) { - let aExpr = aExpressions[aIndex]; - if (aExpr.equals(bExpr)) { - bExprMatched = true; - } - aIndex++; + /** + * Returns true if it is provable `p` implies `q`. + */ + private static _implies(p: ContextKeyExpr, q: ContextKeyExpr): boolean { + const notP = p.negate(); + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; } + return [node]; + }; - if (!bExprMatched) { - return false; + let expr = terminals(notP).concat(terminals(q)); + for (let i = 0; i < expr.length; i++) { + const a = expr[i]; + const notA = a.negate(); + for (let j = i + 1; j < expr.length; j++) { + const b = expr[j]; + if (notA.equals(b)) { + return true; + } } } - return true; + return false; } public getDefaultBoundCommands(): Map { diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index a4488cffb17..c85003be1ac 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -20,13 +20,13 @@ function createContext(ctx: any) { suite('KeybindingResolver', () => { - function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem { + function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean): ResolvedKeybindingItem { const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); return new ResolvedKeybindingItem( resolvedKeybinding, command, commandArgs, - when ? when.normalize() : undefined, + when, isDefault ); } @@ -191,64 +191,41 @@ suite('KeybindingResolver', () => { }); test('contextIsEntirelyIncluded', () => { - let assertIsIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), true); + const assertIsIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), true); }; - let assertIsNotIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), false); + const assertIsNotIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), false); }; - let key1IsTrue = ContextKeyExpr.equals('key1', true); - let key1IsNotFalse = ContextKeyExpr.notEquals('key1', false); - let key1IsFalse = ContextKeyExpr.equals('key1', false); - let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - let key2IsTrue = ContextKeyExpr.equals('key2', true); - let key2IsNotFalse = ContextKeyExpr.notEquals('key2', false); - let key3IsTrue = ContextKeyExpr.equals('key3', true); - let key4IsTrue = ContextKeyExpr.equals('key4', true); - assertIsIncluded([key1IsTrue], null!); - assertIsIncluded([key1IsTrue], []); - assertIsIncluded([key1IsTrue], [key1IsTrue]); - assertIsIncluded([key1IsTrue], [key1IsNotFalse]); + assertIsIncluded('key1', null); + assertIsIncluded('key1', ''); + assertIsIncluded('key1', 'key1'); + assertIsIncluded('!key1', ''); + assertIsIncluded('!key1', '!key1'); + assertIsIncluded('key2', ''); + assertIsIncluded('key2', 'key2'); + assertIsIncluded('key1 && key1 && key2 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key1'); + assertIsIncluded('key1 && key2', ''); + assertIsIncluded('key1', 'key1 || key2'); + assertIsIncluded('key1 || !key1', 'key2 || !key2'); + assertIsIncluded('key1', 'key1 || key2 && key3'); - assertIsIncluded([key1IsFalse], []); - assertIsIncluded([key1IsFalse], [key1IsFalse]); - assertIsIncluded([key1IsFalse], [key1IsNotTrue]); - - assertIsIncluded([key2IsNotFalse], []); - assertIsIncluded([key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key2IsNotFalse], [key2IsTrue]); - - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], []); - - assertIsNotIncluded([key1IsTrue], [key1IsFalse]); - assertIsNotIncluded([key1IsTrue], [key1IsNotTrue]); - assertIsNotIncluded([key1IsNotFalse], [key1IsFalse]); - assertIsNotIncluded([key1IsNotFalse], [key1IsNotTrue]); - - assertIsNotIncluded([key1IsFalse], [key1IsTrue]); - assertIsNotIncluded([key1IsFalse], [key1IsNotFalse]); - assertIsNotIncluded([key1IsNotTrue], [key1IsTrue]); - assertIsNotIncluded([key1IsNotTrue], [key1IsNotFalse]); - - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key3IsTrue]); - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key4IsTrue]); - assertIsNotIncluded([key1IsTrue], [key2IsTrue]); - assertIsNotIncluded([], [key2IsTrue]); - assertIsNotIncluded(null!, [key2IsTrue]); + assertIsNotIncluded('key1', '!key1'); + assertIsNotIncluded('!key1', 'key1'); + assertIsNotIncluded('key1 && key2', 'key3'); + assertIsNotIncluded('key1 && key2', 'key4'); + assertIsNotIncluded('key1', 'key2'); + assertIsNotIncluded('key1 || key2', 'key2'); + assertIsNotIncluded('', 'key2'); + assertIsNotIncluded(null, 'key2'); }); test('resolve command', function () { - function _kbItem(keybinding: number, command: string, when: ContextKeyExpr): ResolvedKeybindingItem { + function _kbItem(keybinding: number, command: string, when: ContextKeyExpr | undefined): ResolvedKeybindingItem { return kbItem(keybinding, command, null, when, true); } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 53629222ca3..354ef330025 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -448,7 +448,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; } -function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr, order: number, alternative?: IEditorToolItem): void { +function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void { const item: IMenuItem = { command: { id: primary.id, diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 84afaa1d2f1..9a1431da67e 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -534,7 +534,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr, icon: string) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 044c0db7733..8b29304e715 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -203,7 +203,7 @@ appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, Re appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.isEqualTo(Schemas.userData))); appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource); -function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr, group?: string): void { +function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { // Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 4e64ebdc0c6..dec59cfca2c 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -300,7 +300,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { // This might be a removal keybinding item in user settings => accept it @@ -323,7 +323,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveUserKeybindingItems(items: IUserKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const parts = item.parts; if (parts.length === 0) { // This might be a removal keybinding item in user settings => accept it From 141617c5b5793b2f7313e8295581afdf88480014 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 26 Jul 2019 16:37:31 +0200 Subject: [PATCH 086/111] Remove dimmed auto closed character --- src/vs/editor/browser/widget/media/editor.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index 83c0859bd29..fb9e5f5e8b8 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -41,6 +41,8 @@ top: 0; } +/* .monaco-editor .auto-closed-character { opacity: 0.3; } +*/ From f9be8224e709c60d94d50eeb2086ccc41909749d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 26 Jul 2019 16:51:22 +0200 Subject: [PATCH 087/111] tweak jsdoc, #56694 --- src/vs/vscode.proposed.d.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index d410fcedffd..fc19f4d513a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1295,10 +1295,9 @@ declare module 'vscode' { export enum DiagnosticTag { /** - * Deprecated or obsolete code + * Deprecated or obsolete code. * - * Can be used to style with strikeout or other "obsolete" styling. See: - * https://github.com/microsoft/vscode/issues/50972 + * Diagnostics with this tag are rendered with a strike through. */ Deprecated = 2, } From 55c8530ec421e0766f1032830576965169083275 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Fri, 26 Jul 2019 17:11:58 +0200 Subject: [PATCH 088/111] properly pass non-key/value cli arguments; fixes #76989 --- src/vs/workbench/contrib/debug/browser/rawDebugSession.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index b67785c3d98..a0f2120b920 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -587,7 +587,13 @@ export class RawDebugSession { } } else { - args._.push(a2); + const match = /^--(.+)$/.exec(a2); + if (match && match.length === 2) { + const key = match[1]; + (args)[key] = true; + } else { + args._.push(a2); + } } } } From 1c6047158b540dd5e38e75bf9793bc9527d26e4b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 17:16:04 +0200 Subject: [PATCH 089/111] distro --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f973590748b..709608cbc69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "ecf90e8c66d243c7ac15e30c24b3cc437d0700dc", + "distro": "7a8caddf61783ec1867857444d613a317aca500a", "author": { "name": "Microsoft Corporation" }, @@ -158,4 +158,4 @@ "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} +} \ No newline at end of file From 1545b1bb59c8cd266365011b2204b2a98deb8163 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 23 Jul 2019 12:54:45 +0200 Subject: [PATCH 090/111] allow extension tips based on location --- src/vs/platform/product/common/product.ts | 2 +- .../electron-browser/extensionTipsService.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 45c31ca0f3d..b5451aea32c 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -72,7 +72,7 @@ export interface IProductConfiguration { readonly recommendationsUrl: string; }; extensionTips: { [id: string]: string; }; - extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; + extensionImportantTips: { [id: string]: { name: string; pattern: string; isLocationPattern?: boolean, isExtensionPack?: boolean }; }; readonly exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: readonly string[] }; }; readonly extensionKeywords: { [extension: string]: readonly string[]; }; readonly extensionAllowedBadgeProviders: readonly string[]; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index f4af7a1c9b6..1b08aea0f93 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -597,7 +597,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe const now = Date.now(); forEach(this._availableRecommendations, entry => { let { key: pattern, value: ids } = entry; - if (match(pattern, model.uri.path)) { + if (match(pattern, model.uri.toString())) { for (let id of ids) { if (caseInsensitiveGet(product.extensionImportantTips, id)) { recommendationsToSuggest.push(id); @@ -670,12 +670,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (!entry) { return false; } - const name = entry['name']; - + const name = entry.name; let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); - // Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364 - if (id === 'vscjava.vscode-java-pack') { + if (entry.isExtensionPack) { message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); + } else if (entry.isLocationPattern) { + message = localize('reallyRecommendedLocationPattern', "The '{0}' extension is recommended for files at this location.", name); } const setIgnoreRecommendationsConfig = (configVal: boolean) => { From 5cc02113634f9ab8ae9ba4adb00d29dcff14a2c2 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 26 Jul 2019 18:02:52 +0200 Subject: [PATCH 091/111] recommend important exe extensions --- src/vs/platform/product/common/product.ts | 12 +- .../extensions/browser/extensionsActions.ts | 2 +- .../electron-browser/extensionTipsService.ts | 219 +++++++++++++----- 3 files changed, 175 insertions(+), 58 deletions(-) diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index b5451aea32c..d39dd65c08f 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -72,8 +72,8 @@ export interface IProductConfiguration { readonly recommendationsUrl: string; }; extensionTips: { [id: string]: string; }; - extensionImportantTips: { [id: string]: { name: string; pattern: string; isLocationPattern?: boolean, isExtensionPack?: boolean }; }; - readonly exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: readonly string[] }; }; + extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; }; + readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; }; readonly extensionKeywords: { [extension: string]: readonly string[]; }; readonly extensionAllowedBadgeProviders: readonly string[]; readonly extensionAllowedProposedApi: readonly string[]; @@ -120,6 +120,14 @@ export interface IProductConfiguration { readonly uiExtensions?: readonly string[]; } +export interface IExeBasedExtensionTip { + friendlyName: string; + windowsPath?: string; + recommendations: readonly string[]; + important?: boolean; + exeFriendlyName?: string; +} + export interface ISurveyData { surveyId: string; surveyUrl: string; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index df4be0957a3..fdb0056d228 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -1694,7 +1694,7 @@ export class InstallRecommendedExtensionAction extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended '); + viewlet.search(`@id:${this.extensionId}`); viewlet.focus(); return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None) .then(pager => { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index 1b08aea0f93..b64e6d66977 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { join } from 'vs/base/common/path'; +import { join, basename } from 'vs/base/common/path'; import { forEach } from 'vs/base/common/collections'; import { Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; @@ -43,6 +43,8 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { extname } from 'vs/base/common/resources'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IExeBasedExtensionTip } from 'vs/platform/product/common/product'; +import { timeout } from 'vs/base/common/async'; const milliSecondsInADay = 1000 * 60 * 60 * 24; const choiceNever = localize('neverShowAgain', "Don't Show Again"); @@ -71,7 +73,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe _serviceBrand: any; private _fileBasedRecommendations: { [id: string]: { recommendedTime: number, sources: ExtensionRecommendationSource[] }; } = Object.create(null); - private _exeBasedRecommendations: { [id: string]: string; } = Object.create(null); + private _exeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); + private _importantExeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); private _availableRecommendations: { [pattern: string]: string[] } = Object.create(null); private _allWorkspaceRecommendedExtensions: IExtensionRecommendation[] = []; private _dynamicWorkspaceRecommendations: string[] = []; @@ -187,7 +190,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe forEach(this._exeBasedRecommendations, entry => output[entry.key.toLowerCase()] = { reasonId: ExtensionRecommendationReason.Executable, - reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value) + reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value.friendlyName) }); forEach(this._fileBasedRecommendations, entry => output[entry.key.toLowerCase()] = { @@ -496,6 +499,100 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe //#endregion + //#region important exe based extension + + private async promptForImportantExeBasedExtension(): Promise { + + const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + const config = this.configurationService.getValue(ConfigurationKey); + + if (config.ignoreRecommendations + || config.showRecommendationsOnlyOnDemand + || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { + return false; + } + + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); + let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + if (recommendationsToSuggest.length === 0) { + return false; + } + + const id = recommendationsToSuggest[0]; + const tip = this._importantExeBasedRecommendations[id]; + const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!)); + + this.notificationService.prompt(Severity.Info, message, + [{ + label: localize('install', 'Install'), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run(); + } + }, { + label: localize('showRecommendations', "Show Recommendations"), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'show', extensionId: name }); + + const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + recommendationsAction.run(); + recommendationsAction.dispose(); + } + }, { + label: choiceNever, + isSecondary: true, + run: () => { + this.addToImportantRecommendationsIgnore(id); + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); + this.notificationService.prompt( + Severity.Info, + localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), + [{ + label: localize('ignoreAll', "Yes, Ignore All"), + run: () => this.setIgnoreRecommendationsConfig(true) + }, { + label: localize('no', "No"), + run: () => this.setIgnoreRecommendationsConfig(false) + }] + ); + } + }], + { + sticky: true, + onCancel: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); + } + } + ); + + return true; + } + //#region fileBasedRecommendations getFileBasedRecommendations(): IExtensionRecommendation[] { @@ -646,21 +743,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private async promptRecommendedExtensionForFileType(recommendationsToSuggest: string[], installed: ILocalExtension[]): Promise { - const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); - recommendationsToSuggest = recommendationsToSuggest.filter(id => { - if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { - return false; - } - if (!this.isExtensionAllowedToBeRecommended(id)) { - return false; - } - if (installedExtensionsIds.has(id.toLowerCase())) { - return false; - } - return true; - }); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); if (recommendationsToSuggest.length === 0) { return false; } @@ -674,18 +758,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); if (entry.isExtensionPack) { message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); - } else if (entry.isLocationPattern) { - message = localize('reallyRecommendedLocationPattern', "The '{0}' extension is recommended for files at this location.", name); } - const setIgnoreRecommendationsConfig = (configVal: boolean) => { - this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); - if (configVal) { - const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; - this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); - } - }; - this.notificationService.prompt(Severity.Info, message, [{ label: localize('install', 'Install'), @@ -718,12 +792,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe label: choiceNever, isSecondary: true, run: () => { - importantRecommendationsIgnoreList.push(id); - this.storageService.store( - 'extensionsAssistant/importantRecommendationsIgnore', - JSON.stringify(importantRecommendationsIgnoreList), - StorageScope.GLOBAL - ); + this.addToImportantRecommendationsIgnore(id); /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -736,10 +805,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), [{ label: localize('ignoreAll', "Yes, Ignore All"), - run: () => setIgnoreRecommendationsConfig(true) + run: () => this.setIgnoreRecommendationsConfig(true) }, { label: localize('no', "No"), - run: () => setIgnoreRecommendationsConfig(false) + run: () => this.setIgnoreRecommendationsConfig(false) }] ); } @@ -831,6 +900,42 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ); } + private filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] { + + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); + return recommendationsToSuggest.filter(id => { + if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { + return false; + } + if (!this.isExtensionAllowedToBeRecommended(id)) { + return false; + } + if (installedExtensionsIds.has(id.toLowerCase())) { + return false; + } + return true; + }); + } + + private addToImportantRecommendationsIgnore(id: string) { + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + importantRecommendationsIgnoreList.push(id); + this.storageService.store( + 'extensionsAssistant/importantRecommendationsIgnore', + JSON.stringify(importantRecommendationsIgnoreList), + StorageScope.GLOBAL + ); + } + + private setIgnoreRecommendationsConfig(configVal: boolean) { + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); + if (configVal) { + const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); + } + } + //#endregion //#region otherRecommendations @@ -857,18 +962,18 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private fetchProactiveRecommendations(calledDuringStartup?: boolean): Promise { - let fetchPromise = Promise.resolve(undefined); + let fetchPromise = Promise.resolve(undefined); if (!this.proactiveRecommendationsFetched) { this.proactiveRecommendationsFetched = true; - // Executable based recommendations carry out a lot of file stats, so run them after 10 secs - // So that the startup is not affected + // Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected + // 10 sec for regular extensions + // 3 secs for important - fetchPromise = new Promise((c, e) => { - setTimeout(() => { - Promise.all([this.fetchExecutableRecommendations(), this.fetchDynamicWorkspaceRecommendations()]).then(() => c(undefined)); - }, calledDuringStartup ? 10000 : 0); - }); + const importantExeBasedRecommendations = timeout(calledDuringStartup ? 3000 : 0).then(_ => this.fetchExecutableRecommendations(true)); + importantExeBasedRecommendations.then(_ => this.promptForImportantExeBasedExtension()); + + fetchPromise = timeout(calledDuringStartup ? 10000 : 0).then(_ => Promise.all([this.fetchDynamicWorkspaceRecommendations(), this.fetchExecutableRecommendations(false), importantExeBasedRecommendations])); } return fetchPromise; @@ -877,20 +982,22 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe /** * If user has any of the tools listed in product.exeBasedExtensionTips, fetch corresponding recommendations */ - private fetchExecutableRecommendations(): Promise { + private fetchExecutableRecommendations(important: boolean): Promise { const homeDir = os.homedir(); let foundExecutables: Set = new Set(); - let findExecutable = (exeName: string, path: string) => { + let findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => { return pfs.fileExists(path).then(exists => { if (exists && !foundExecutables.has(exeName)) { foundExecutables.add(exeName); - (product.exeBasedExtensionTips[exeName]['recommendations'] || []) - .forEach(extensionId => { - if (product.exeBasedExtensionTips[exeName]['friendlyName']) { - this._exeBasedRecommendations[extensionId.toLowerCase()] = product.exeBasedExtensionTips[exeName]['friendlyName']; + (tip['recommendations'] || []).forEach(extensionId => { + if (tip.friendlyName) { + if (important) { + this._importantExeBasedRecommendations[extensionId.toLowerCase()] = tip; } - }); + this._exeBasedRecommendations[extensionId.toLowerCase()] = tip; + } + }); } }); }; @@ -901,8 +1008,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { return; } - - let exeName = entry.key; + if (important !== !!entry.value.important) { + return; + } + const exeName = entry.key; if (process.platform === 'win32') { let windowsPath = entry.value['windowsPath']; if (!windowsPath || typeof windowsPath !== 'string') { @@ -913,10 +1022,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe .replace('%ProgramFiles%', process.env['ProgramFiles']!) .replace('%APPDATA%', process.env['APPDATA']!) .replace('%WINDIR%', process.env['WINDIR']!); - promises.push(findExecutable(exeName, windowsPath)); + promises.push(findExecutable(exeName, entry.value, windowsPath)); } else { - promises.push(findExecutable(exeName, join('/usr/local/bin', exeName))); - promises.push(findExecutable(exeName, join(homeDir, exeName))); + promises.push(findExecutable(exeName, entry.value, join('/usr/local/bin', exeName))); + promises.push(findExecutable(exeName, entry.value, join(homeDir, exeName))); } }); From 916287fdd467e3b4a1bf431ac80aa36eddf4bbdb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 16:26:58 +0200 Subject: [PATCH 092/111] remove EditorPart._preferredSize related to #67367 --- .../browser/parts/editor/editorPart.ts | 34 ------------------- .../test/browser/editorGroupsService.test.ts | 11 ------ 2 files changed, 45 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index a42cf0aed2f..53611687ce5 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -112,13 +112,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); } - private readonly _onDidPreferredSizeChange: Emitter = this._register(new Emitter()); - readonly onDidPreferredSizeChange: Event = this._onDidPreferredSizeChange.event; - //#endregion - private _preferredSize: Dimension | undefined; - private readonly workspaceMemento: MementoObject; private readonly globalMemento: MementoObject; @@ -366,9 +361,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const newOrientation = (orientation === GroupOrientation.HORIZONTAL) ? Orientation.HORIZONTAL : Orientation.VERTICAL; if (this.gridWidget.orientation !== newOrientation) { this.gridWidget.orientation = newOrientation; - - // Mark preferred size as changed - this.resetPreferredSize(); } } @@ -423,9 +415,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Events for groups that got added this.getGroups(GroupsOrder.GRID_APPEARANCE).forEach(groupView => { if (currentGroupViews.indexOf(groupView) === -1) { @@ -490,9 +479,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidAddGroup.fire(newGroupView); @@ -661,9 +647,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidRemoveGroup.fire(groupView); } @@ -764,23 +747,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro get onDidChange(): Event { return this.centeredLayoutWidget.onDidChange; } readonly priority: LayoutPriority = LayoutPriority.High; - get preferredSize(): Dimension { - if (!this._preferredSize) { - this._preferredSize = new Dimension(this.gridWidget.minimumWidth, this.gridWidget.minimumHeight); - } - - return this._preferredSize; - } - - private resetPreferredSize(): void { - - // Reset (will be computed upon next access) - this._preferredSize = undefined; - - // Event - this._onDidPreferredSizeChange.fire(); - } - private get gridSeparatorBorder(): Color { return this.theme.getColor(EDITOR_GROUP_BORDER) || this.theme.getColor(contrastBorder) || Color.transparent; } diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index b577d40f181..477fdfc5bc7 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -118,11 +118,6 @@ suite('EditorGroupsService', () => { groupMovedCounter++; }); - let preferredSizeChangeCounter = 0; - const preferredSizeChangeListener = part.onDidPreferredSizeChange(() => { - preferredSizeChangeCounter++; - }); - // always a root group const rootGroup = part.groups[0]; assert.equal(part.groups.length, 1); @@ -141,7 +136,6 @@ suite('EditorGroupsService', () => { assert.equal(part.groups.length, 2); assert.equal(part.count, 2); assert.ok(part.activeGroup === rootGroup); - assert.equal(preferredSizeChangeCounter, 1); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); @@ -189,7 +183,6 @@ suite('EditorGroupsService', () => { assert.equal(part.groups.length, 3); assert.ok(part.activeGroup === rightGroup); assert.ok(!downGroup.activeControl); - assert.equal(preferredSizeChangeCounter, 2); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); assert.equal(downGroup.label, 'Group 3'); @@ -208,13 +201,11 @@ suite('EditorGroupsService', () => { part.moveGroup(downGroup, rightGroup, GroupDirection.DOWN); assert.equal(groupMovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 2); part.removeGroup(downGroup); assert.ok(!part.getGroup(downGroup.id)); assert.equal(didDispose, true); assert.equal(groupRemovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 3); assert.equal(part.groups.length, 2); assert.ok(part.activeGroup === rightGroup); assert.equal(rootGroup.label, 'Group 1'); @@ -254,13 +245,11 @@ suite('EditorGroupsService', () => { assert.ok(part.activeGroup === rootGroup); part.setGroupOrientation(part.orientation === GroupOrientation.HORIZONTAL ? GroupOrientation.VERTICAL : GroupOrientation.HORIZONTAL); - assert.equal(preferredSizeChangeCounter, 5); activeGroupChangeListener.dispose(); groupAddedListener.dispose(); groupRemovedListener.dispose(); groupMovedListener.dispose(); - preferredSizeChangeListener.dispose(); part.dispose(); }); From dcdab4125be3ed7b121078b7a5efe1ebe0be9946 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 16:53:59 +0200 Subject: [PATCH 093/111] hide away gridview types --- .../base/browser/ui/centered/centeredViewLayout.ts | 2 +- src/vs/base/browser/ui/grid/grid.ts | 12 ++++++++---- src/vs/base/test/browser/ui/grid/util.ts | 5 +++-- src/vs/workbench/browser/part.ts | 5 ++--- src/vs/workbench/browser/parts/editor/editorPart.ts | 5 ++--- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index b40384018f1..299b6534873 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -6,7 +6,7 @@ import { SplitView, Orientation, ISplitViewStyles, IView as ISplitViewView } from 'vs/base/browser/ui/splitview/splitview'; import { $ } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; -import { IView, IViewSize } from 'vs/base/browser/ui/grid/gridview'; +import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 08090875642..7b38753725d 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -7,11 +7,11 @@ import 'vs/css!./gridview'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; -import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize } from './gridview'; +import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize } from './gridview'; import { Event } from 'vs/base/common/event'; import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; -export { Orientation, Sizing as GridViewSizing } from './gridview'; +export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview'; export const enum Direction { Up, @@ -29,6 +29,10 @@ function oppositeDirection(direction: Direction): Direction { } } +export interface IView extends IGridViewView { + readonly preferredSize?: number; +} + export interface GridLeafNode { readonly view: T; readonly box: Box; @@ -217,7 +221,7 @@ export class Grid extends Disposable { this.gridview = new GridView(options); this._register(this.gridview); - this._register(this.gridview.onDidSashReset(this.doResetViewSize, this)); + this._register(this.gridview.onDidSashReset(this.onDidSashReset, this)); const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' ? GridViewSizing.Invisible(options.firstViewVisibleCachedSize) @@ -370,7 +374,7 @@ export class Grid extends Disposable { return getGridLocation(element); } - private doResetViewSize(location: number[]): void { + private onDidSashReset(location: number[]): void { const [parentLocation,] = tail(location); this.gridview.distributeViewSizes(parentLocation); } diff --git a/src/vs/base/test/browser/ui/grid/util.ts b/src/vs/base/test/browser/ui/grid/util.ts index 0efdc44851a..39a35736ddd 100644 --- a/src/vs/base/test/browser/ui/grid/util.ts +++ b/src/vs/base/test/browser/ui/grid/util.ts @@ -5,7 +5,8 @@ import * as assert from 'assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { IView, GridNode, isGridBranchNode, } from 'vs/base/browser/ui/grid/gridview'; +import { GridNode, isGridBranchNode } from 'vs/base/browser/ui/grid/gridview'; +import { IView } from 'vs/base/browser/ui/grid/grid'; export class TestView implements IView { @@ -78,4 +79,4 @@ export function nodesToArrays(node: GridNode): any { } else { return node.view; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index f80e4545957..f5281df2802 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -9,10 +9,9 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Dimension, size } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; -import { ISerializableView, Orientation } from 'vs/base/browser/ui/grid/grid'; +import { ISerializableView, Orientation, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { IViewSize } from 'vs/base/browser/ui/grid/gridview'; export interface IPartOptions { hasTitle?: boolean; @@ -164,4 +163,4 @@ class PartLayout { return { titleSize, contentSize }; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 53611687ce5..84b899658bc 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -11,7 +11,7 @@ import { Event, Emitter, Relay } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; +import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions } from 'vs/workbench/common/editor'; import { values } from 'vs/base/common/map'; import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; @@ -27,7 +27,6 @@ import { EditorDropTarget } from 'vs/workbench/browser/parts/editor/editorDropTa import { localize } from 'vs/nls'; import { Color } from 'vs/base/common/color'; import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout'; -import { IView, orthogonal, LayoutPriority, IViewSize } from 'vs/base/browser/ui/grid/gridview'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -994,4 +993,4 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } } -registerSingleton(IEditorGroupsService, EditorPart); \ No newline at end of file +registerSingleton(IEditorGroupsService, EditorPart); From 6cfe0672e7f981a066a0ecaf09eef690e52153af Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 17:28:06 +0200 Subject: [PATCH 094/111] splitview: improve sash reset and distributeViewSizes behavior --- src/vs/base/browser/ui/splitview/splitview.ts | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 171a44837c4..6f031dac570 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -336,7 +336,24 @@ export class SplitView extends Disposable { const onChangeDisposable = onChange(this.onSashChange, this); const onEnd = Event.map(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash)); const onEndDisposable = onEnd(this.onSashEnd, this); - const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); + + const onDidResetDisposable = sash.onDidReset(() => { + const index = firstIndex(this.sashItems, item => item.sash === sash); + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + return; + } + + if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + return; + } + + this._onDidSashReset.fire(index); + }); const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); const sashItem: ISashItem = { sash, disposable }; @@ -630,10 +647,19 @@ export class SplitView extends Disposable { } distributeViewSizes(): void { - const size = Math.floor(this.size / this.viewItems.length); + const flexibleViewItems: ViewItem[] = []; + let flexibleSize = 0; - for (let i = 0; i < this.viewItems.length; i++) { - const item = this.viewItems[i]; + for (const item of this.viewItems) { + if (item.maximumSize - item.minimumSize > 0) { + flexibleViewItems.push(item); + flexibleSize += item.size; + } + } + + const size = Math.floor(flexibleSize / flexibleViewItems.length); + + for (const item of flexibleViewItems) { item.size = clamp(size, item.minimumSize, item.maximumSize); } From 5d228fb849a1cc0eefc071079334050f79cef41e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 17:28:40 +0200 Subject: [PATCH 095/111] grid: onDidSashReset with preferred width/height --- src/vs/base/browser/ui/grid/grid.ts | 36 +++++++++++++++++-- src/vs/base/browser/ui/grid/gridview.ts | 7 ++-- .../test/browser/ui/grid/gridview.test.ts | 22 ++++++------ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 7b38753725d..386503317c4 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -30,7 +30,8 @@ function oppositeDirection(direction: Direction): Direction { } export interface IView extends IGridViewView { - readonly preferredSize?: number; + readonly preferredHeight?: number; + readonly preferredWidth?: number; } export interface GridLeafNode { @@ -339,7 +340,7 @@ export class Grid extends Disposable { } getViews(): GridBranchNode { - return this.gridview.getViews() as GridBranchNode; + return this.gridview.getView() as GridBranchNode; } getNeighborViews(view: T, direction: Direction, wrap: boolean = false): T[] { @@ -375,7 +376,36 @@ export class Grid extends Disposable { } private onDidSashReset(location: number[]): void { - const [parentLocation,] = tail(location); + const resizeToPreferredSize = (node: GridNode): boolean => { + if (isGridBranchNode(node)) { + return false; + } + + const direction = getLocationOrientation(this.orientation, location); + const size = direction === Orientation.HORIZONTAL ? node.view.preferredWidth : node.view.preferredHeight; + + if (typeof size !== 'number') { + return false; + } + + const viewSize = Orientation.HORIZONTAL ? { width: size } : { height: size }; + this.gridview.resizeView(location, viewSize); + return true; + }; + + let node = this.gridview.getView(location) as GridNode; + + if (resizeToPreferredSize(node)) { + return; + } + + const [parentLocation, index] = tail(location); + node = this.gridview.getView([...parentLocation, index + 1]) as GridNode; + + if (resizeToPreferredSize(node)) { + return; + } + this.gridview.distributeViewSizes(parentLocation); } } diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index 3e05e4a9499..f6e65de3a14 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -903,8 +903,11 @@ export class GridView implements IDisposable { parent.setChildVisible(index, visible); } - getViews(): GridBranchNode { - return this._getViews(this.root, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }) as GridBranchNode; + getView(): GridBranchNode; + getView(location?: number[]): GridNode; + getView(location?: number[]): GridNode { + const node = location ? this.getNode(location)[1] : this._root; + return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }); } private _getViews(node: Node, orientation: Orientation, box: Box): GridNode { diff --git a/src/vs/base/test/browser/ui/grid/gridview.test.ts b/src/vs/base/test/browser/ui/grid/gridview.test.ts index 20b7626b184..78cc44cc76a 100644 --- a/src/vs/base/test/browser/ui/grid/gridview.test.ts +++ b/src/vs/base/test/browser/ui/grid/gridview.test.ts @@ -22,7 +22,7 @@ suite('Gridview', function () { }); test('empty gridview is empty', function () { - assert.deepEqual(nodesToArrays(gridview.getViews()), []); + assert.deepEqual(nodesToArrays(gridview.getView()), []); gridview.dispose(); }); @@ -43,7 +43,7 @@ suite('Gridview', function () { gridview.addView(views[1], 200, [1]); gridview.addView(views[2], 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -62,7 +62,7 @@ suite('Gridview', function () { gridview.addView((views[1] as TestView[])[0] as IView, 200, [1]); gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -71,35 +71,35 @@ suite('Gridview', function () { const view1 = new TestView(20, 20, 20, 20); gridview.addView(view1 as IView, 200, [0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1]); const view2 = new TestView(20, 20, 20, 20); gridview.addView(view2 as IView, 200, [1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, view2]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, view2]); const view3 = new TestView(20, 20, 20, 20); gridview.addView(view3 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view3, view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]); const view4 = new TestView(20, 20, 20, 20); gridview.addView(view4 as IView, 200, [1, 0, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [[view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]); const view5 = new TestView(20, 20, 20, 20); gridview.addView(view5 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]); const view6 = new TestView(20, 20, 20, 20); gridview.addView(view6 as IView, 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]); const view7 = new TestView(20, 20, 20, 20); gridview.addView(view7 as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, view7, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]); const view8 = new TestView(20, 20, 20, 20); gridview.addView(view8 as IView, 200, [1, 1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); gridview.dispose(); }); From b8bb655858966a417e5051f307435325b8e0a6b8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 17:38:17 +0200 Subject: [PATCH 096/111] grid: fix preferred size usage --- src/vs/base/browser/ui/grid/grid.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 386503317c4..d2cc4ee6ff5 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -376,7 +376,9 @@ export class Grid extends Disposable { } private onDidSashReset(location: number[]): void { - const resizeToPreferredSize = (node: GridNode): boolean => { + const resizeToPreferredSize = (location: number[]): boolean => { + const node = this.gridview.getView(location) as GridNode; + if (isGridBranchNode(node)) { return false; } @@ -388,21 +390,18 @@ export class Grid extends Disposable { return false; } - const viewSize = Orientation.HORIZONTAL ? { width: size } : { height: size }; + const viewSize = direction === Orientation.HORIZONTAL ? { width: Math.round(size) } : { height: Math.round(size) }; this.gridview.resizeView(location, viewSize); return true; }; - let node = this.gridview.getView(location) as GridNode; - - if (resizeToPreferredSize(node)) { + if (resizeToPreferredSize(location)) { return; } const [parentLocation, index] = tail(location); - node = this.gridview.getView([...parentLocation, index + 1]) as GridNode; - if (resizeToPreferredSize(node)) { + if (resizeToPreferredSize([...parentLocation, index + 1])) { return; } From 1fd0d4533f2fa19b0eaa83bb9414455da8f9cd33 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 18:06:26 +0200 Subject: [PATCH 097/111] rename contentDimension --- src/vs/workbench/browser/parts/editor/editorPart.ts | 10 +++++----- .../workbench/contrib/watermark/browser/watermark.ts | 4 ++-- .../services/editor/common/editorGroupsService.ts | 2 +- src/vs/workbench/test/workbenchTestServices.ts | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 84b899658bc..14ea050a1b9 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -199,8 +199,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region IEditorGroupsService - private _dimension: Dimension; - get dimension(): Dimension { return this._dimension; } + private _contentDimension: Dimension; + get contentDimension(): Dimension { return this._contentDimension; } get activeGroup(): IEditorGroupView { return this._activeGroup; @@ -409,7 +409,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro this.doCreateGridControlWithState(gridDescriptor, activeGroup.id, currentGroupViews); // Layout - this.doLayout(this._dimension); + this.doLayout(this._contentDimension); // Update container this.updateContainer(); @@ -933,10 +933,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } private doLayout(dimension: Dimension): void { - this._dimension = dimension; + this._contentDimension = dimension; // Layout Grid - this.centeredLayoutWidget.layout(this._dimension.width, this._dimension.height); + this.centeredLayoutWidget.layout(this._contentDimension.width, this._contentDimension.height); // Event this._onDidLayout.fire(dimension); diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 7788f6e36a0..54c9b8620f5 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -173,7 +173,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr dom.prepend(container.firstElementChild as HTMLElement, this.watermark); this._register(this.keybindingService.onDidUpdateKeybindings(update)); this._register(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension))); - this.handleEditorPartSize(container, this.editorGroupsService.dimension); + this.handleEditorPartSize(container, this.editorGroupsService.contentDimension); } private handleEditorPartSize(container: HTMLElement, dimension: IDimension): void { @@ -214,4 +214,4 @@ Registry.as(ConfigurationExtensions.Configuration) 'description': nls.localize('tips.enabled', "When enabled, will show the watermark tips when no editor is open.") }, } - }); \ No newline at end of file + }); diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index c91173e5514..a9ab498cc98 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -179,7 +179,7 @@ export interface IEditorGroupsService { /** * The size of the editor groups area. */ - readonly dimension: IDimension; + readonly contentDimension: IDimension; /** * An active group is the default location for new editors to open. diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 9e9e0d739e8..0c9a9f933aa 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -667,7 +667,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { whenRestored: Promise = Promise.resolve(undefined); willRestoreEditors = false; - dimension = { width: 800, height: 600 }; + contentDimension = { width: 800, height: 600 }; get activeGroup(): IEditorGroup { return this.groups[0]; @@ -1622,4 +1622,4 @@ export class RemoteFileSystemProvider implements IFileSystemProvider { write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return this.diskFileSystemProvider.write!(fd, pos, data, offset, length); } private toFileResource(resource: URI): URI { return resource.with({ scheme: Schemas.file, authority: '' }); } -} \ No newline at end of file +} From 45d944cfe399e7f6291969a6c8c3fd42f1014394 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 26 Jul 2019 18:13:39 +0200 Subject: [PATCH 098/111] workbench: implement preferred size for panel and sidebar fixes #67367 --- src/vs/workbench/browser/layout.ts | 6 ++++- src/vs/workbench/browser/legacyLayout.ts | 10 ++++---- src/vs/workbench/browser/part.ts | 11 +++++++-- .../workbench/browser/parts/compositePart.ts | 1 + .../browser/parts/panel/panelPart.ts | 24 +++++++++++++------ .../browser/parts/sidebar/sidebarPart.ts | 18 +++++++++++++- .../browser/parts/statusbar/statusbarPart.ts | 3 ++- .../services/layout/browser/layoutService.ts | 6 +++++ src/vs/workbench/test/browser/part.test.ts | 5 ++-- .../workbench/test/workbenchTestServices.ts | 4 ++++ 10 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index c2e011c5370..7950b273c23 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper, Dimension } from 'vs/base/browser/dom'; import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -545,6 +545,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; // any other part cannot be hidden } + getDimension(part: Parts): Dimension { + return this.getPart(part).dimension; + } + getTitleBarOffset(): number { let offset = 0; if (this.isVisible(Parts.TITLEBAR_PART)) { diff --git a/src/vs/workbench/browser/legacyLayout.ts b/src/vs/workbench/browser/legacyLayout.ts index d936e13f1b2..8800afc09e8 100644 --- a/src/vs/workbench/browser/legacyLayout.ts +++ b/src/vs/workbench/browser/legacyLayout.ts @@ -626,11 +626,11 @@ export class WorkbenchLegacyLayout extends Disposable implements IVerticalSashLa } // Propagate to Part Layouts - this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight, -1); - this.parts.editor.layout(editorSize.width, editorSize.height, -1); - this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height, -1); - this.parts.panel.layout(panelDimension.width, panelDimension.height, -1); - this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height, -1); + this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight); + this.parts.editor.layout(editorSize.width, editorSize.height); + this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height); + this.parts.panel.layout(panelDimension.width, panelDimension.height); + this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height); // Propagate to Context View this.contextViewService.layout(); diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index f5281df2802..c78ad168cb7 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -9,7 +9,7 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Dimension, size } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; -import { ISerializableView, Orientation, IViewSize } from 'vs/base/browser/ui/grid/grid'; +import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -28,6 +28,10 @@ export interface ILayoutContentResult { * arranges an optional title and mandatory content area to show content. */ export abstract class Part extends Component implements ISerializableView { + + private _dimension: Dimension; + get dimension(): Dimension { return this._dimension; } + private parent: HTMLElement; private titleArea: HTMLElement | null; private contentArea: HTMLElement | null; @@ -127,7 +131,10 @@ export abstract class Part extends Component implements ISerializableView { abstract minimumHeight: number; abstract maximumHeight: number; - abstract layout(width: number, height: number, orientation: Orientation): void; + layout(width: number, height: number): void { + this._dimension = new Dimension(width, height); + } + abstract toJSON(): object; //#endregion diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index d09cf93901b..e5d7cfbe7c8 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -466,6 +466,7 @@ export abstract class CompositePart extends Part { } layout(width: number, height: number): void { + super.layout(width, height); // Layout contents this.contentAreaSize = super.layoutContents(width, height).contentSize; diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 874d81baddb..1189df45c45 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -59,6 +59,16 @@ export class PanelPart extends CompositePart implements IPanelService { readonly snap = true; + get preferredHeight(): number | undefined { + const sidebarDimension = this.layoutService.getDimension(Parts.SIDEBAR_PART); + return sidebarDimension.height * 0.4; + } + + get preferredWidth(): number | undefined { + const statusbarPart = this.layoutService.getDimension(Parts.STATUSBAR_PART); + return statusbarPart.width * 0.4; + } + //#endregion get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean }> { return Event.map(this.onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus })); } @@ -74,7 +84,7 @@ export class PanelPart extends CompositePart implements IPanelService { private compositeActions: Map = new Map(); private blockOpeningPanel: boolean; - private dimension: Dimension; + private _contentDimension: Dimension; constructor( @INotificationService notificationService: INotificationService, @@ -293,21 +303,21 @@ export class PanelPart extends CompositePart implements IPanelService { } if (this.layoutService.getPanelPosition() === Position.RIGHT) { - this.dimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting + this._contentDimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting } else { - this.dimension = new Dimension(width, height!); + this._contentDimension = new Dimension(width, height!); } // Layout contents - super.layout(this.dimension.width, this.dimension.height); + super.layout(this._contentDimension.width, this._contentDimension.height); // Layout composite bar this.layoutCompositeBar(); } private layoutCompositeBar(): void { - if (this.dimension) { - let availableWidth = this.dimension.width - 40; // take padding into account + if (this._contentDimension) { + let availableWidth = this._contentDimension.width - 40; // take padding into account if (this.toolBar) { availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth()); // adjust height for global actions showing } @@ -522,4 +532,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IPanelService, PanelPart); \ No newline at end of file +registerSingleton(IPanelService, PanelPart); diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 88c40e827ae..8b50a07b662 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -47,6 +47,22 @@ export class SidebarPart extends CompositePart implements IViewletServi readonly snap = true; + get preferredWidth(): number | undefined { + const viewlet = this.getActiveViewlet(); + + if (!viewlet) { + return; + } + + const width = viewlet.getOptimalWidth(); + + if (typeof width !== 'number') { + return; + } + + return width; + } + //#endregion get onDidViewletRegister(): Event { return >this.viewletRegistry.onDidRegister; } @@ -303,4 +319,4 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(FocusSideBarAction, Fo primary: KeyMod.CtrlCmd | KeyCode.KEY_0 }), 'View: Focus into Side Bar', nls.localize('viewCategory', "View")); -registerSingleton(IViewletService, SidebarPart); \ No newline at end of file +registerSingleton(IViewletService, SidebarPart); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 00fe6c45bc4..089cbd3003e 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -611,6 +611,7 @@ export class StatusbarPart extends Part implements IStatusbarService { } layout(width: number, height: number): void { + super.layout(width, height); super.layoutContents(width, height); } @@ -816,4 +817,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IStatusbarService, StatusbarPart); \ No newline at end of file +registerSingleton(IStatusbarService, StatusbarPart); diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index d0bf836984f..344c7657de5 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; +import { Dimension } from 'vs/base/browser/dom'; export const IWorkbenchLayoutService = createDecorator('layoutService'); @@ -81,6 +82,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ isVisible(part: Parts): boolean; + /** + * Returns if the part is visible. + */ + getDimension(part: Parts): Dimension; + /** * Set activity bar hidden or not */ diff --git a/src/vs/workbench/test/browser/part.test.ts b/src/vs/workbench/test/browser/part.test.ts index 73878b4e603..ed151b3aced 100644 --- a/src/vs/workbench/test/browser/part.test.ts +++ b/src/vs/workbench/test/browser/part.test.ts @@ -10,7 +10,6 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { append, $, hide } from 'vs/base/browser/dom'; import { TestStorageService, TestLayoutService } from 'vs/workbench/test/workbenchTestServices'; import { StorageScope } from 'vs/platform/storage/common/storage'; -import { Orientation } from 'vs/base/browser/ui/grid/grid'; class SimplePart extends Part { @@ -19,7 +18,7 @@ class SimplePart extends Part { minimumHeight: number; maximumHeight: number; - layout(width: number, height: number, orientation: Orientation): void { + layout(width: number, height: number): void { throw new Error('Method not implemented.'); } @@ -172,4 +171,4 @@ suite('Workbench parts', () => { assert(!document.getElementById('myPart.title')); assert(document.getElementById('myPart.content')); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 0c9a9f933aa..153fc2bbae5 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -474,6 +474,10 @@ export class TestLayoutService implements IWorkbenchLayoutService { return true; } + getDimension(_part: Parts): Dimension { + return new Dimension(0, 0); + } + public getContainer(_part: Parts): HTMLElement { return null!; } From 0e346590c409e63b7e3fab42bd073fe57c7d42ac Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 26 Jul 2019 11:36:56 -0700 Subject: [PATCH 099/111] Tweak comment reaction css --- src/vs/workbench/contrib/comments/browser/media/review.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index 767e4c97057..47f8feb5fc9 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -400,7 +400,7 @@ .monaco-editor .review-widget .action-item { min-width: 18px; - min-height: 18px; + min-height: 20px; margin-left: 4px; } From 937fd58245addcbc4522f421fecbd617a38e6ab8 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 26 Jul 2019 11:37:23 -0700 Subject: [PATCH 100/111] Small amount of code cleanup in commentNode.ts --- .../contrib/comments/browser/commentNode.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index f5a80eea68b..e8d7d850123 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -181,7 +181,7 @@ export class CommentNode extends Disposable { let hasReactionHandler = this.commentService.hasReactionHandler(this.owner); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(this.comment.commentReactions || []); actions.push(toggleReactionAction); } @@ -208,7 +208,7 @@ export class CommentNode extends Disposable { actionViewItemProvider(action: Action) { let options = {}; - if (action.id === 'comment.delete' || action.id === 'comment.edit' || action.id === ToggleReactionsAction.ID) { + if (action.id === ToggleReactionsAction.ID) { options = { label: false, icon: true }; } else { options = { label: false, icon: true }; @@ -226,7 +226,7 @@ export class CommentNode extends Disposable { } } - private createReactionPicker2(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { + private createReactionPicker(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { let toggleReactionActionViewItem: DropdownMenuActionViewItem; let toggleReactionAction = this._register(new ToggleReactionsAction(() => { if (toggleReactionActionViewItem) { @@ -321,14 +321,8 @@ export class CommentNode extends Disposable { }); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(this.comment.commentReactions || []); this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); - } else { - // let reactionGroup = this.commentService.getReactionGroup(this.owner); - // if (reactionGroup && reactionGroup.length) { - // let toggleReactionAction = this.createReactionPicker2(reactionGroup || []); - // this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); - // } } } @@ -526,4 +520,4 @@ function fillInActions(groups: [string, Array Date: Fri, 26 Jul 2019 11:46:01 -0700 Subject: [PATCH 101/111] Fix #77994. Use scoped contextKeyService in a comment thread. --- .../contrib/comments/browser/commentThreadWidget.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index b7c1ea6f12a..aac697e221c 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -115,7 +115,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._contextKeyService = contextKeyService.createScoped(this.domNode); this._threadIsEmpty = CommentContextKeys.commentThreadIsEmpty.bindTo(this._contextKeyService); this._threadIsEmpty.set(!_commentThread.comments || !_commentThread.comments.length); - this._commentThreadContextValue = contextKeyService.createKey('commentThread', _commentThread.contextValue); + this._commentThreadContextValue = this._contextKeyService.createKey('commentThread', _commentThread.contextValue); this._resizeObserver = null; this._isExpanded = _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded; @@ -569,8 +569,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const menu = this._commentMenus.getCommentThreadActions(commentThread, this._contextKeyService); this._disposables.add(menu); - this._disposables.add(menu.onDidChange(() => { - this._commentFormActions.setActions(menu); + this._disposables.add(menu.onDidChange((newMenu) => { + if (newMenu) { + this._commentFormActions.setActions(newMenu); + } else { + this._commentFormActions.setActions(menu); + } })); this._commentFormActions = new CommentFormActions(container, async (action: IAction) => { @@ -897,4 +901,4 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._submitActionsDisposables.forEach(local => local.dispose()); this._onDidClose.fire(undefined); } -} \ No newline at end of file +} From f0d3c50abcb96edc6717d3c0a26aea6fe66e165c Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 26 Jul 2019 11:49:35 -0700 Subject: [PATCH 102/111] menu.onDidChagne always returns undefined. --- .../contrib/comments/browser/commentThreadWidget.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index aac697e221c..0bd28e5fe58 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -569,12 +569,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const menu = this._commentMenus.getCommentThreadActions(commentThread, this._contextKeyService); this._disposables.add(menu); - this._disposables.add(menu.onDidChange((newMenu) => { - if (newMenu) { - this._commentFormActions.setActions(newMenu); - } else { - this._commentFormActions.setActions(menu); - } + this._disposables.add(menu.onDidChange(() => { + this._commentFormActions.setActions(menu); })); this._commentFormActions = new CommentFormActions(container, async (action: IAction) => { From 185695c93109365c90babb6f1d17953dfd991558 Mon Sep 17 00:00:00 2001 From: Sana Ajani Date: Thu, 25 Jul 2019 17:31:02 -0700 Subject: [PATCH 103/111] add office and sharepoint packages --- .../electron-browser/workspaceStatsService.ts | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index 5041cb4be1e..ff776387035 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -47,7 +47,22 @@ const ModulesToLookFor = [ 'azure-storage', 'firebase', '@google-cloud/common', - 'heroku-cli' + 'heroku-cli', + //Office and Sharepoint packages + '@microsoft/office-js', + '@microsoft/office-js-helpers', + '@types/office-js', + '@types/office-runtime', + 'office-ui-fabric-react', + '@uifabric/icons', + '@uifabric/merge-styles', + '@uifabric/styling', + '@uifabric/experiments', + '@uifabric/utilities', + '@microsoft/rush', + 'lerna', + 'just-task', + 'beachball' ]; const PyModulesToLookFor = [ 'azure', @@ -143,6 +158,20 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js-helpers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-runtime" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.office-ui-fabric-react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/icons" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/merge-styles" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/styling" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/experiments" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/utilities" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/rush" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.lerna" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.just-task" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.beachball" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, @@ -187,7 +216,8 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + } */ From 5c955e9da1ce83c5b56d308042740c4e773755eb Mon Sep 17 00:00:00 2001 From: Sana Ajani Date: Fri, 26 Jul 2019 14:55:47 -0700 Subject: [PATCH 104/111] distro --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 709608cbc69..6c721dbd92e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "7a8caddf61783ec1867857444d613a317aca500a", + "distro": "f02652facc899106dfbf5a5aab1f1f6061cf3778", "author": { "name": "Microsoft Corporation" }, @@ -158,4 +158,4 @@ "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} \ No newline at end of file +} From 28b3ae7b0cda7992acf9f389713120061f8bc6f2 Mon Sep 17 00:00:00 2001 From: Sana Ajani Date: Fri, 26 Jul 2019 15:11:30 -0700 Subject: [PATCH 105/111] clean up --- .../contrib/stats/electron-browser/workspaceStatsService.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index ff776387035..ef0dc08081c 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -216,9 +216,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - - + "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } } */ private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise { @@ -504,4 +502,4 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { private searchArray(arr: string[], regEx: RegExp): boolean | undefined { return arr.some(v => v.search(regEx) > -1) || undefined; } -} \ No newline at end of file +} From 6bb5e193f94b26eb7fe4121e23e5fdf06dd600f5 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 26 Jul 2019 15:30:31 -0700 Subject: [PATCH 106/111] start -> open, exit -> close, remove exit code --- .../src/singlefolder-tests/terminal.test.ts | 16 +++---- .../workspace.tasks.test.ts | 9 ++-- src/vs/vscode.proposed.d.ts | 48 ++++++++++--------- .../api/node/extHostTerminalService.ts | 19 ++++---- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index ee5f7505d6c..dc281a06fd5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -266,8 +266,8 @@ suite('window namespace tests', () => { }); const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, - start: () => {}, - shutdown: () => {} + open: () => {}, + close: () => {} }; window.createTerminal({ name: 'c', pty }); }); @@ -293,8 +293,8 @@ suite('window namespace tests', () => { const writeEmitter = new EventEmitter(); const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, - start: () => startResolve(), - shutdown: () => {} + open: () => startResolve(), + close: () => {} }; const terminal = window.createTerminal({ name: 'foo', pty }); }); @@ -306,7 +306,7 @@ suite('window namespace tests', () => { }); const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, - start: (dimensions) => { + open: (dimensions) => { ok(dimensions!.columns > 0); ok(dimensions!.rows > 0); const reg3 = window.onDidCloseTerminal(() => { @@ -315,7 +315,7 @@ suite('window namespace tests', () => { }); terminal.dispose(); }, - shutdown: () => {} + close: () => {} }; const terminal = window.createTerminal({ name: 'foo', pty }); }); @@ -343,8 +343,8 @@ suite('window namespace tests', () => { const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, onDidOverrideDimensions: overrideDimensionsEmitter.event, - start: () => {}, - shutdown: () => {} + open: () => {}, + close: () => {} }; const terminal = window.createTerminal({ name: 'foo', pty }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts index 56559d6aacc..daef120762c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -36,16 +36,17 @@ suite('workspace-namespace', () => { }; const writeEmitter = new vscode.EventEmitter(); const execution = new vscode.CustomExecution2((): Thenable => { - return Promise.resolve({ + const pty: vscode.Pseudoterminal = { onDidWrite: writeEmitter.event, - start: () => { + open: () => { writeEmitter.fire('testing\r\n'); }, - shutdown: () => { + close: () => { taskProvider.dispose(); done(); } - }); + }; + return Promise.resolve(pty); }); const task = new vscode.Task2(kind, vscode.TaskScope.Workspace, taskName, taskType, execution); result.push(task); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 198c96af53c..8eac40ea882 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -968,8 +968,8 @@ declare module 'vscode' { * const writeEmitter = new vscode.EventEmitter(); * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * start: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), - * shutdown: () => {} + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} * }; * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` @@ -994,13 +994,13 @@ declare module 'vscode' { * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, * onDidOverrideDimensions: dimensionsEmitter.event, - * start: () => { + * open: () => { * dimensionsEmitter.fire({ * columns: 20, * rows: 10 * }); * }, - * shutdown: () => {} + * close: () => {} * }; * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` @@ -1008,37 +1008,40 @@ declare module 'vscode' { onDidOverrideDimensions?: Event; /** - * An event that when fired will exit the process with an exit code, this will behave the - * same for an extension treminal as when a regular process exits with an exit code. Note - * that exit codes must be positive numbers, when negative the exit code will be forced to - * `1`. + * An event that when fired will signal that the pty is closed and dispose of the terminal. * - * **Example:** Exit with an exit code of `0` if the y key is pressed, otherwise `1`. + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const exitEmitter = new vscode.EventEmitter(); + * const closeEmitter = new vscode.EventEmitter(); * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * start: () => writeEmitter.fire('Press y to exit successfully'), - * shutdown: () => {} - * handleInput: data => exitEmitter.fire(data === 'y' ? 0 : 1) + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {} + * handleInput: { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * data => closeEmitter.fire(); + * } * }; * vscode.window.createTerminal({ name: 'Exit example', pty }); */ - onDidExit?: Event; + onDidClose?: Event; /** - * Implement to handle when the pty is ready to start firing events. + * Implement to handle when the pty is open and ready to start firing events. * * @param initialDimensions The dimensions of the terminal, this will be undefined if the * terminal panel has not been opened before this is called. */ - start(initialDimensions: TerminalDimensions | undefined): void; + open(initialDimensions: TerminalDimensions | undefined): void; /** - * Implement to handle when the terminal shuts down by an act of the user. + * Implement to handle when the terminal is closed by an act of the user. */ - shutdown(): void; + close(): void; /** * Implement to handle incoming keystrokes in the terminal or when an extension calls @@ -1053,8 +1056,8 @@ declare module 'vscode' { * const writeEmitter = new vscode.EventEmitter(); * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * start: () => {}, - * shutdown: () => {}, + * open: () => {}, + * close: () => {}, * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) * }; * vscode.window.createTerminal({ name: 'Local echo', pty }); @@ -1184,9 +1187,8 @@ declare module 'vscode' { /** * The callback used to execute the task. Cancellation should be handled using - * [Pseudoterminal.shutdown](#Pseudoterminal.shutdown). When the task is complete, - * [Pseudoterminal.onDidExit](#Pseudoterminal.onDidExit) should be fired with the exit code - * with '0' for success and a non-zero value for failure. + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). */ callback: (thisArg?: any) => Thenable; } diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 7b5df64321c..c42c0736bb7 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -793,8 +793,8 @@ class ExtHostPseudoterminal implements ITerminalChildProcess { ) { this._queueDisposables = []; this._queueDisposables.push(this._pty.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); - if (this._pty.onDidExit) { - this._queueDisposables.push(this._pty.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e }))); + if (this._pty.onDidClose) { + this._queueDisposables.push(this._pty.onDidClose(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: 0 }))); } if (this._pty.onDidOverrideDimensions) { this._queueDisposables.push(this._pty.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); @@ -802,8 +802,8 @@ class ExtHostPseudoterminal implements ITerminalChildProcess { } shutdown(): void { - if (this._pty.shutdown) { - this._pty.shutdown(); + if (this._pty.close) { + this._pty.close(); } } @@ -839,18 +839,15 @@ class ExtHostPseudoterminal implements ITerminalChildProcess { // Attach the real listeners this._pty.onDidWrite(e => this._onProcessData.fire(e)); - if (this._pty.onDidExit) { - this._pty.onDidExit(e => { - // Ensure only positive exit codes are returned - this._onProcessExit.fire(e >= 0 ? e : 1); - }); + if (this._pty.onDidClose) { + this._pty.onDidClose(e => this._onProcessExit.fire(0)); } if (this._pty.onDidOverrideDimensions) { this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); } - if (this._pty.start) { - this._pty.start(initialDimensions); + if (this._pty.open) { + this._pty.open(initialDimensions); } } } From b9cb543e70d865f3529818d073c7d23942527096 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Sat, 27 Jul 2019 00:30:21 +0200 Subject: [PATCH 107/111] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c721dbd92e..704ac9da679 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "f02652facc899106dfbf5a5aab1f1f6061cf3778", + "distro": "7224ab1f6e8484664148ab7362432b49c653d047", "author": { "name": "Microsoft Corporation" }, From e2888839ec1572300c7770032e72b4d32ee6e393 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 26 Jul 2019 16:47:43 -0700 Subject: [PATCH 108/111] Don't throw out ext host proc requests on slow remotes Fixes microsoft/vscode-remote-release#1031 --- .../api/node/extHostTerminalService.ts | 16 ++++----- .../terminal/common/terminalService.ts | 36 ++++++++++++++----- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index c42c0736bb7..58734d0827d 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -310,9 +310,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { private _logService: ILogService ) { this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService); - this.updateLastActiveWorkspace(); - this.updateVariableResolver(); - this.registerListeners(); + this._updateLastActiveWorkspace(); + this._updateVariableResolver(); + this._registerListeners(); } public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { @@ -532,19 +532,19 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return env; } - private registerListeners(): void { - this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this.updateLastActiveWorkspace()); - this._extHostWorkspace.onDidChangeWorkspace(() => this.updateVariableResolver()); + private _registerListeners(): void { + this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace()); + this._extHostWorkspace.onDidChangeWorkspace(() => this._updateVariableResolver()); } - private updateLastActiveWorkspace(): void { + private _updateLastActiveWorkspace(): void { const activeEditor = this._extHostDocumentsAndEditors.activeEditor(); if (activeEditor) { this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder; } } - private async updateVariableResolver(): Promise { + private async _updateVariableResolver(): Promise { const configProvider = await this._extHostConfiguration.getConfigProvider(); const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2(); this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 1bb31239d69..8bf6a5bfa5b 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -20,11 +20,15 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { timeout } from 'vs/base/common/async'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { IPickOptions, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +interface IExtHostReadyEntry { + promise: Promise; + resolve: () => void; +} + export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -38,7 +42,7 @@ export abstract class TerminalService implements ITerminalService { return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); } private _findState: FindReplaceState; - private _extHostsReady: { [authority: string]: boolean } = {}; + private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {}; private _activeTabIndex: number; public get activeTabIndex(): number { return this._activeTabIndex; } @@ -133,13 +137,11 @@ export abstract class TerminalService implements ITerminalService { public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { - // Wait for the remoteAuthority to be ready (and listening for events) before proceeding + // Wait for the remoteAuthority to be ready (and listening for events) before firing + // the event to spawn the ext host process const conn = this._remoteAgentService.getConnection(); const remoteAuthority = conn ? conn.remoteAuthority : 'null'; - let retries = 0; - while (!this._extHostsReady[remoteAuthority] && ++retries < 50) { - await timeout(100); - } + await this._whenExtHostReady(remoteAuthority); this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); }); } @@ -148,8 +150,24 @@ export abstract class TerminalService implements ITerminalService { this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); } - public extHostReady(remoteAuthority: string): void { - this._extHostsReady[remoteAuthority] = true; + public async extHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + this._extHostsReady[remoteAuthority]!.resolve(); + } + + private async _whenExtHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + return this._extHostsReady[remoteAuthority]!.promise; + } + + private _createExtHostReadyEntry(remoteAuthority: string): void { + if (this._extHostsReady[remoteAuthority]) { + return; + } + + let resolve!: () => void; + const promise = new Promise(r => resolve = r); + this._extHostsReady[remoteAuthority] = { promise, resolve }; } private _onBeforeShutdown(): boolean | Promise { From 17d9194a408046ee41d11ecb0048a25b57210610 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 26 Jul 2019 18:35:16 -0700 Subject: [PATCH 109/111] Update css service --- extensions/css-language-features/server/package.json | 2 +- .../css-language-features/server/src/cssServerMain.ts | 6 +++--- extensions/css-language-features/server/yarn.lock | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index d1913a26acf..c6e8600d2ae 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -9,7 +9,7 @@ }, "main": "./out/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.3-next.0", + "vscode-css-languageservice": "^4.0.3-next.1", "vscode-languageserver": "^5.3.0-next.8" }, "devDependencies": { diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index f762bde09c4..0bfd886c310 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -121,9 +121,9 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { scopedSettingsSupport = !!getClientCapability('workspace.configuration', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); - languageServices.css = getCSSLanguageService({ customDataProviders, fileSystemProvider }); - languageServices.scss = getSCSSLanguageService({ customDataProviders, fileSystemProvider }); - languageServices.less = getLESSLanguageService({ customDataProviders, fileSystemProvider }); + languageServices.css = getCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.scss = getSCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.less = getLESSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); const capabilities: ServerCapabilities = { // Tell the client that the server works in FULL text document sync mode diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 3537a3d2ecd..d93eec392c7 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -781,10 +781,10 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.0: - version "4.0.3-next.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.0.tgz#ba96894cf2a0c86c744a1274590f27e55ea60f58" - integrity sha512-ku58Y5jDFNfDicv2AAhgu1edgfGcRZPwlKu6EBK2ck/O/Vco7Zy64FDoClJghcYBhJiDs7sy2q/UtQD0IoGbRw== +vscode-css-languageservice@^4.0.3-next.1: + version "4.0.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.1.tgz#e89d01ce0d79b3e6c2642f5e3ad73cb8160d38d9" + integrity sha512-Zrm5TeraVUJ8vRikWhFt259dQu+WK+Ie3K5UA8BB4kqcanoM+1mcnIt8fPkTXlZLbiEWElrkJ9yuYbDNkufeBg== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" From 54fefb8d7835bc8c931835960282089f1d136bde Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 26 Jul 2019 19:49:31 -0700 Subject: [PATCH 110/111] Update html & css service --- .../server/package.json | 4 ++-- .../server/src/htmlServerMain.ts | 2 +- .../server/src/modes/cssMode.ts | 5 ++--- .../server/src/modes/languageModes.ts | 22 +++++++++---------- .../server/src/test/completions.test.ts | 3 ++- .../server/src/test/folding.test.ts | 3 ++- .../server/src/test/formatting.test.ts | 3 ++- .../server/src/utils/documentContext.ts | 3 +-- .../html-language-features/server/yarn.lock | 16 +++++++------- 9 files changed, 30 insertions(+), 31 deletions(-) diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 087fbaec82b..95a97f1110f 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,8 +9,8 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.3-next.0", - "vscode-html-languageservice": "^3.0.3", + "vscode-css-languageservice": "^4.0.3-next.1", + "vscode-html-languageservice": "^3.0.4-next.0", "vscode-languageserver": "^5.3.0-next.8", "vscode-languageserver-types": "3.15.0-next.2", "vscode-nls": "^4.1.1", diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index 7ca71d16760..01b43d9a9ba 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -96,7 +96,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { get folders() { return workspaceFolders; } }; - languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, providers); + languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, params.capabilities, providers); documents.onDidClose(e => { languageModes.onDocumentRemoved(e.document); diff --git a/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts index 168c7ceffa0..6e60c32d87c 100644 --- a/extensions/html-language-features/server/src/modes/cssMode.ts +++ b/extensions/html-language-features/server/src/modes/cssMode.ts @@ -5,13 +5,12 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { TextDocument, Position, Range, CompletionList } from 'vscode-languageserver-types'; -import { getCSSLanguageService, Stylesheet, FoldingRange } from 'vscode-css-languageservice'; +import { Stylesheet, FoldingRange, LanguageService as CSSLanguageService } from 'vscode-css-languageservice'; import { LanguageMode, Workspace } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; import { Color } from 'vscode-languageserver'; -export function getCSSMode(documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { - let cssLanguageService = getCSSLanguageService(); +export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { let embeddedCSSDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument('css')); let cssStylesheets = getLanguageModelCache(10, 60, document => cssLanguageService.parseStylesheet(document)); diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index b44b2442420..d07e0bd80f6 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -3,18 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getLanguageService as getHTMLLanguageService, DocumentContext, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; -import { - CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, - Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation, FoldingRange -} from 'vscode-languageserver-types'; -import { ColorInformation, ColorPresentation, Color, WorkspaceFolder } from 'vscode-languageserver'; - +import { getCSSLanguageService } from 'vscode-css-languageservice'; +import { ClientCapabilities, DocumentContext, getLanguageService as getHTMLLanguageService, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; +import { Color, ColorInformation, ColorPresentation, WorkspaceFolder } from 'vscode-languageserver'; +import { CompletionItem, CompletionList, Definition, Diagnostic, DocumentHighlight, DocumentLink, FoldingRange, FormattingOptions, Hover, Location, Position, Range, SignatureHelp, SymbolInformation, TextDocument, TextEdit } from 'vscode-languageserver-types'; import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache'; -import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getCSSMode } from './cssMode'; -import { getJavaScriptMode } from './javascriptMode'; +import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getHTMLMode } from './htmlMode'; +import { getJavaScriptMode } from './javascriptMode'; export { ColorInformation, ColorPresentation, Color }; @@ -66,8 +63,9 @@ export interface LanguageModeRange extends Range { attributeValue?: boolean; } -export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, customDataProviders?: IHTMLDataProvider[]): LanguageModes { - const htmlLanguageService = getHTMLLanguageService({ customDataProviders }); +export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, clientCapabilities: ClientCapabilities, customDataProviders?: IHTMLDataProvider[]): LanguageModes { + const htmlLanguageService = getHTMLLanguageService({ customDataProviders, clientCapabilities }); + const cssLanguageService = getCSSLanguageService({ clientCapabilities }); let documentRegions = getLanguageModelCache(10, 60, document => getDocumentRegions(htmlLanguageService, document)); @@ -77,7 +75,7 @@ export function getLanguageModes(supportedLanguages: { [languageId: string]: boo let modes = Object.create(null); modes['html'] = getHTMLMode(htmlLanguageService, workspace); if (supportedLanguages['css']) { - modes['css'] = getCSSMode(documentRegions, workspace); + modes['css'] = getCSSMode(cssLanguageService, documentRegions, workspace); } if (supportedLanguages['javascript']) { modes['javascript'] = getJavaScriptMode(documentRegions); diff --git a/extensions/html-language-features/server/src/test/completions.test.ts b/extensions/html-language-features/server/src/test/completions.test.ts index de056ed3c1e..aaba72add6d 100644 --- a/extensions/html-language-features/server/src/test/completions.test.ts +++ b/extensions/html-language-features/server/src/test/completions.test.ts @@ -9,6 +9,7 @@ import { URI } from 'vscode-uri'; import { TextDocument, CompletionList, CompletionItemKind } from 'vscode-languageserver-types'; import { getLanguageModes } from '../modes/languageModes'; import { WorkspaceFolder } from 'vscode-languageserver'; +import { ClientCapabilities } from 'vscode-html-languageservice'; export interface ItemDescription { label: string; @@ -58,7 +59,7 @@ export function testCompletionFor(value: string, expected: { count?: number, ite let document = TextDocument.create(uri, 'html', 0, value); let position = document.positionAt(offset); - const languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + const languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); const mode = languageModes.getModeAtPosition(document, position)!; let list = mode.doComplete!(document, position); diff --git a/extensions/html-language-features/server/src/test/folding.test.ts b/extensions/html-language-features/server/src/test/folding.test.ts index 3ce2816185b..e19555d568d 100644 --- a/extensions/html-language-features/server/src/test/folding.test.ts +++ b/extensions/html-language-features/server/src/test/folding.test.ts @@ -8,6 +8,7 @@ import * as assert from 'assert'; import { TextDocument } from 'vscode-languageserver'; import { getFoldingRanges } from '../modes/htmlFolding'; import { getLanguageModes } from '../modes/languageModes'; +import { ClientCapabilities } from 'vscode-css-languageservice'; interface ExpectedIndentRange { startLine: number; @@ -21,7 +22,7 @@ function assertRanges(lines: string[], expected: ExpectedIndentRange[], message? settings: {}, folders: [{ name: 'foo', uri: 'test://foo' }] }; - let languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + let languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); let actual = getFoldingRanges(languageModes, document, nRanges, null); let actualRanges = []; diff --git a/extensions/html-language-features/server/src/test/formatting.test.ts b/extensions/html-language-features/server/src/test/formatting.test.ts index 702aa76da6c..8c59c75e017 100644 --- a/extensions/html-language-features/server/src/test/formatting.test.ts +++ b/extensions/html-language-features/server/src/test/formatting.test.ts @@ -11,6 +11,7 @@ import { getLanguageModes } from '../modes/languageModes'; import { TextDocument, Range, FormattingOptions } from 'vscode-languageserver-types'; import { format } from '../modes/formatting'; +import { ClientCapabilities } from 'vscode-html-languageservice'; suite('HTML Embedded Formatting', () => { @@ -19,7 +20,7 @@ suite('HTML Embedded Formatting', () => { settings: options, folders: [{ name: 'foo', uri: 'test://foo' }] }; - var languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + var languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); let rangeStartOffset = value.indexOf('|'); let rangeEndOffset; diff --git a/extensions/html-language-features/server/src/utils/documentContext.ts b/extensions/html-language-features/server/src/utils/documentContext.ts index 71f9a3591be..6c391064fae 100644 --- a/extensions/html-language-features/server/src/utils/documentContext.ts +++ b/extensions/html-language-features/server/src/utils/documentContext.ts @@ -35,9 +35,8 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp try { return url.resolve(base, ref); } catch { - return undefined; + return ''; } - }, }; } diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index c386ce0bbb9..9ea59b6077c 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -229,19 +229,19 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.0: - version "4.0.3-next.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.0.tgz#ba96894cf2a0c86c744a1274590f27e55ea60f58" - integrity sha512-ku58Y5jDFNfDicv2AAhgu1edgfGcRZPwlKu6EBK2ck/O/Vco7Zy64FDoClJghcYBhJiDs7sy2q/UtQD0IoGbRw== +vscode-css-languageservice@^4.0.3-next.1: + version "4.0.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.1.tgz#e89d01ce0d79b3e6c2642f5e3ad73cb8160d38d9" + integrity sha512-Zrm5TeraVUJ8vRikWhFt259dQu+WK+Ie3K5UA8BB4kqcanoM+1mcnIt8fPkTXlZLbiEWElrkJ9yuYbDNkufeBg== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" vscode-uri "^2.0.3" -vscode-html-languageservice@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.3.tgz#0aeae18a59000e317447ea34965f72680a2140ef" - integrity sha512-U+upM3gHp3HaF3wXAnUduA6IDKcz6frWS/dTAju3cZVIyZwOLBBFElQVlLH0ycHyMzqUFrjvdv+kEyPAEWfQ/g== +vscode-html-languageservice@^3.0.4-next.0: + version "3.0.4-next.0" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.0.tgz#d4f5a103b94753a19b374158212fe734dbe670e8" + integrity sha512-5Z5ITtokWt/zuPKemKEXfC+4XHoQryBAZVAcTwpAel2qqueUwGqjd5ZrVy/2x5GZAdZAipl0BvsTTMkOBS1BFQ== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" From 5ec81e4739ab5f862e113bf20222c6d690f1937a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 26 Jul 2019 20:45:55 -0700 Subject: [PATCH 111/111] Format proxy setting descriptions --- src/vs/platform/request/common/request.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts index ed6c2611166..31e3c314242 100644 --- a/src/vs/platform/request/common/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -90,7 +90,7 @@ Registry.as(Extensions.Configuration) 'http.proxy': { type: 'string', pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$', - description: localize('proxy', "The proxy setting to use. If not set will be taken from the http_proxy and https_proxy environment variables.") + markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.") }, 'http.proxyStrictSSL': { type: 'boolean', @@ -100,7 +100,7 @@ Registry.as(Extensions.Configuration) 'http.proxyAuthorization': { type: ['null', 'string'], default: null, - description: localize('proxyAuthorization', "The value to send as the 'Proxy-Authorization' header for every network request.") + markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request.") }, 'http.proxySupport': { type: 'string',