From 776a085e6ea23ad6195cf7617a253f2e9e4a02ca Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 4 Nov 2021 15:31:24 +0100 Subject: [PATCH 01/83] Share common code for the ExtensionResourceLoaderService --- .../themes/browser/themes.contribution.ts | 4 +- .../common/webExtensionsScannerService.ts | 7 +- .../browser/extensionResourceLoaderService.ts | 54 +++-------- .../common/extensionResourceLoader.ts | 89 +++++++++++++++++++ .../extensionResourceLoaderService.ts | 40 ++++----- .../themes/browser/workbenchThemeService.ts | 12 +-- .../tokenStyleResolving.test.ts | 8 +- 7 files changed, 131 insertions(+), 83 deletions(-) diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 270fab33f64..3c45fdbe572 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -30,6 +30,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { Emitter } from 'vs/base/common/event'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; export const manageExtensionIcon = registerIcon('theme-selection-manage-extension', Codicon.gear, localize('manageExtensionIcon', 'Icon for the \'Manage\' action in the theme selection quick pick.')); @@ -49,6 +50,7 @@ export class SelectColorThemeAction extends Action { @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService, @ILogService private readonly logService: ILogService, @IProgressService private progressService: IProgressService ) { @@ -134,7 +136,7 @@ export class SelectColorThemeAction extends Action { }); quickpick.show(); - if (this.extensionGalleryService.isEnabled()) { + if (this.extensionGalleryService.isEnabled() && this.extensionResourceLoaderService.supportsExtensionGalleryResources) { const marketplaceThemes = new MarketplaceThemes(this.extensionGalleryService, this.extensionManagementService, this.themeService, this.logService); marketplaceThemes.onDidChange(() => { diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts index 0cdb7aa1a29..05a29726e1d 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts @@ -24,8 +24,6 @@ import * as semver from 'vs/base/common/semver/semver'; import { isString } from 'vs/base/common/types'; import { getErrorMessage } from 'vs/base/common/errors'; import { ResourceMap } from 'vs/base/common/map'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { format2 } from 'vs/base/common/strings'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IStringDictionary } from 'vs/base/common/collections'; import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; @@ -74,7 +72,6 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten @IFileService private readonly fileService: IFileService, @ILogService private readonly logService: ILogService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IProductService private readonly productService: IProductService, @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, @IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService, ) { @@ -334,10 +331,10 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } private async toWebExtensionFromGallery(galleryExtension: IGalleryExtension, metadata?: IStringDictionary): Promise { - if (!this.productService.extensionsGallery) { + let extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL(galleryExtension, 'extension'); + if (!extensionLocation) { throw new Error('No extension gallery service configured.'); } - let extensionLocation = URI.parse(format2(this.productService.extensionsGallery.resourceUrlTemplate, { publisher: galleryExtension.publisher, name: galleryExtension.name, version: galleryExtension.version, path: 'extension' })); extensionLocation = galleryExtension.properties.targetPlatform === TargetPlatform.WEB ? extensionLocation.with({ query: `${extensionLocation.query ? `${extensionLocation.query}&` : ''}target=${galleryExtension.properties.targetPlatform}` }) : extensionLocation; const extensionResources = await this.listExtensionResources(extensionLocation); const packageNLSResource = extensionResources.find(e => basename(e) === 'package.nls.json'); diff --git a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts index bd634b1e6ea..8f68d8a7ab2 100644 --- a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -6,35 +6,27 @@ import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { getServiceMachineId } from 'vs/platform/serviceMachineId/common/serviceMachineId'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { isWeb } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; -class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { +class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { declare readonly _serviceBrand: undefined; - private readonly _extensionGalleryResourceAuthority: string | undefined; - constructor( - @IFileService private readonly _fileService: IFileService, - @IProductService private readonly _productService: IProductService, - @IStorageService private readonly _storageService: IStorageService, - @IEnvironmentService private readonly _environmentService: IEnvironmentService, - @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IFileService fileService: IFileService, + @IStorageService storageService: IStorageService, + @IProductService productService: IProductService, + @IEnvironmentService environmentService: IEnvironmentService, + @IConfigurationService configurationService: IConfigurationService, + @ILogService readonly _logService: ILogService, ) { - if (_productService.extensionsGallery) { - this._extensionGalleryResourceAuthority = this._getExtensionResourceAuthority(URI.parse(_productService.extensionsGallery.resourceUrlTemplate)); - } + super(fileService, storageService, productService, environmentService, configurationService); } async readExtensionResource(uri: URI): Promise { @@ -46,18 +38,8 @@ class ExtensionResourceLoaderService implements IExtensionResourceLoaderService } const requestInit: RequestInit = {}; - if (this._extensionGalleryResourceAuthority && this._extensionGalleryResourceAuthority === this._getExtensionResourceAuthority(uri)) { - const machineId = await this._getServiceMachineId(); - requestInit.headers = { - 'X-Client-Name': `${this._productService.applicationName}${isWeb ? '-web' : ''}`, - 'X-Client-Version': this._productService.version - }; - if (supportsTelemetry(this._productService, this._environmentService) && getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE) { - requestInit.headers['X-Machine-Id'] = machineId; - } - if (this._productService.commit) { - requestInit.headers['X-Client-Commit'] = this._productService.commit; - } + if (this.isExtensionGalleryResource(uri)) { + requestInit.headers = await this.getExtensionGalleryRequestHeaders(); requestInit.mode = 'cors'; /* set mode to cors so that above headers are always passed */ } @@ -67,20 +49,6 @@ class ExtensionResourceLoaderService implements IExtensionResourceLoaderService throw new Error(response.statusText); } return response.text(); - - } - - private _serviceMachineIdPromise: Promise | undefined; - private _getServiceMachineId(): Promise { - if (!this._serviceMachineIdPromise) { - this._serviceMachineIdPromise = getServiceMachineId(this._environmentService, this._fileService, this._storageService); - } - return this._serviceMachineIdPromise; - } - - private _getExtensionResourceAuthority(uri: URI): string | undefined { - const index = uri.authority.indexOf('.'); - return index !== -1 ? uri.authority.substring(index + 1) : undefined; } } diff --git a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts index 0820d426cca..7b43fa7eb8f 100644 --- a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts +++ b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts @@ -3,8 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { isWeb } from 'vs/base/common/platform'; +import { format2 } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; +import { IHeaders } from 'vs/base/parts/request/common/request'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { getServiceMachineId } from 'vs/platform/serviceMachineId/common/serviceMachineId'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; export const IExtensionResourceLoaderService = createDecorator('extensionResourceLoaderService'); @@ -18,4 +29,82 @@ export interface IExtensionResourceLoaderService { * Read a certain resource within an extension. */ readExtensionResource(uri: URI): Promise; + + /** + * Returns whether the gallery provides extension resources. + */ + supportsExtensionGalleryResources: boolean; + + /** + * Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources. + */ + getExtensionGalleryResourceURL(galleryExtension: { publisher: string, name: string, version: string }, path?: string): URI | undefined; +} + + +export abstract class AbstractExtensionResourceLoaderService implements IExtensionResourceLoaderService { + + readonly _serviceBrand: undefined; + + private readonly _extensionGalleryResourceUrlTemplate: string | undefined; + private readonly _extensionGalleryAuthority: string | undefined; + + constructor( + readonly _fileService: IFileService, + readonly _storageService: IStorageService, + readonly _productService: IProductService, + readonly _environmentService: IEnvironmentService, + readonly _configurationService: IConfigurationService, + ) { + if (_productService.extensionsGallery) { + this._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate; + this._extensionGalleryAuthority = this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)); + } + } + + public get supportsExtensionGalleryResources(): boolean { + return this._extensionGalleryResourceUrlTemplate !== undefined; + } + + public getExtensionGalleryResourceURL(galleryExtension: { publisher: string, name: string, version: string }, path?: string): URI | undefined { + if (this._extensionGalleryResourceUrlTemplate) { + return URI.parse(format2(this._extensionGalleryResourceUrlTemplate, { publisher: galleryExtension.publisher, name: galleryExtension.name, version: galleryExtension.version, path: 'extension' })); + } + return undefined; + } + + + public abstract readExtensionResource(uri: URI): Promise; + + protected isExtensionGalleryResource(uri: URI) { + return this._extensionGalleryAuthority && this._extensionGalleryAuthority === this._getExtensionGalleryAuthority(uri); + } + + protected async getExtensionGalleryRequestHeaders(): Promise { + const headers: IHeaders = { + 'X-Client-Name': `${this._productService.applicationName}${isWeb ? '-web' : ''}`, + 'X-Client-Version': this._productService.version + }; + if (supportsTelemetry(this._productService, this._environmentService) && getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE) { + headers['X-Machine-Id'] = await this._getServiceMachineId(); + } + if (this._productService.commit) { + headers['X-Client-Commit'] = this._productService.commit; + } + return headers; + } + + private _serviceMachineIdPromise: Promise | undefined; + private _getServiceMachineId(): Promise { + if (!this._serviceMachineIdPromise) { + this._serviceMachineIdPromise = getServiceMachineId(this._environmentService, this._fileService, this._storageService); + } + return this._serviceMachineIdPromise; + } + + private _getExtensionGalleryAuthority(uri: URI): string | undefined { + const index = uri.authority.indexOf('.'); + return index !== -1 ? uri.authority.substring(index + 1) : undefined; + } + } diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts index a0f30427e40..4062092b43b 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts @@ -6,47 +6,37 @@ import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; -import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; import { IProductService } from 'vs/platform/product/common/productService'; import { asText, IRequestService } from 'vs/platform/request/common/request'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { CancellationToken } from 'vs/base/common/cancellation'; -export class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { - - declare readonly _serviceBrand: undefined; - - private readonly _extensionGalleryResourceAuthority: string | undefined; +export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { constructor( - @IFileService private readonly _fileService: IFileService, - @IProductService _productService: IProductService, - @IRequestService private readonly _requestService: IRequestService, + @IFileService fileService: IFileService, + @IStorageService storageService: IStorageService, + @IProductService productService: IProductService, + @IEnvironmentService environmentService: IEnvironmentService, + @IConfigurationService configurationService: IConfigurationService, + @IRequestService readonly _requestService: IRequestService, ) { - if (_productService.extensionsGallery) { - this._extensionGalleryResourceAuthority = this._getExtensionResourceAuthority(URI.parse(_productService.extensionsGallery.resourceUrlTemplate)); - } - - + super(fileService, storageService, productService, environmentService, configurationService); } async readExtensionResource(uri: URI): Promise { - - if (this._extensionGalleryResourceAuthority && this._extensionGalleryResourceAuthority === this._getExtensionResourceAuthority(uri)) { - const requestContext = await this._requestService.request({ - url: uri.toString() - }, CancellationToken.None); - + if (this.isExtensionGalleryResource(uri)) { + const headers = await this.getExtensionGalleryRequestHeaders(); + const requestContext = await this._requestService.request({ url: uri.toString(), headers }, CancellationToken.None); return (await asText(requestContext)) || ''; } - const result = await this._fileService.readFile(uri); return result.value.toString(); } - private _getExtensionResourceAuthority(uri: URI): string | undefined { - const index = uri.authority.indexOf('.'); - return index !== -1 ? uri.authority.substring(index + 1) : undefined; - } } registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService); diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 9f4118d94fc..aa5970e8d29 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -40,8 +40,6 @@ import { RunOnceScheduler, Sequencer } from 'vs/base/common/async'; import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet'; import { asCssVariableName, getColorRegistry } from 'vs/platform/theme/common/colorRegistry'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { format2 } from 'vs/base/common/strings'; // implementation @@ -113,8 +111,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @IWorkbenchLayoutService readonly layoutService: IWorkbenchLayoutService, @ILogService private readonly logService: ILogService, @IHostColorSchemeService private readonly hostColorService: IHostColorSchemeService, - @IUserDataInitializationService readonly userDataInitializationService: IUserDataInitializationService, - @IProductService private readonly productService: IProductService + @IUserDataInitializationService readonly userDataInitializationService: IUserDataInitializationService ) { this.container = layoutService.container; this.settings = new ThemeConfiguration(configurationService); @@ -412,13 +409,12 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } public async getMarketplaceColorThemes(id: string, version: string): Promise { - const resourceUrlTemplate = this.productService.extensionsGallery?.resourceUrlTemplate; - if (!resourceUrlTemplate) { + const [publisher, name] = id.split('.'); + const extensionLocation = this.extensionResourceLoaderService.getExtensionGalleryResourceURL({ publisher, name, version}, 'extension'); + if (!extensionLocation) { return []; } try { - const [publisher, name] = id.split('.'); - const extensionLocation = URI.parse(format2(resourceUrlTemplate, { publisher, name, version, path: 'extension' })); const manifestContent = await this.extensionResourceLoaderService.readExtensionResource(resources.joinPath(extensionLocation, 'package.json')); const data: ExtensionData = { extensionPublisher: publisher, extensionId: id, extensionName: name, extensionIsBuiltin: false }; diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 8031e5b4d41..8a3acdfc4d2 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -17,6 +17,9 @@ import { ExtensionResourceLoaderService } from 'vs/workbench/services/extensionR import { ITokenStyle } from 'vs/platform/theme/common/themeService'; import { mock, TestProductService } from 'vs/workbench/test/common/workbenchTestServices'; import { IRequestService } from 'vs/platform/request/common/request'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const undefinedStyle = { bold: undefined, underline: undefined, italic: undefined }; const unsetStyle = { bold: false, underline: false, italic: false }; @@ -81,8 +84,11 @@ function assertTokenStyles(themeData: ColorThemeData, expected: { [qualifiedClas suite('Themes - TokenStyleResolving', () => { const fileService = new FileService(new NullLogService()); const requestService = new (mock())(); + const storageService = new (mock())(); + const environmentService = new (mock())(); + const configurationService = new (mock())(); - const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService, TestProductService, requestService); + const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService, storageService, TestProductService, environmentService, configurationService, requestService); const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); fileService.registerProvider(Schemas.file, diskFileSystemProvider); From b68e4d2bacdb613751d1fc50e4291146aeca307f Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 4 Nov 2021 15:54:20 +0100 Subject: [PATCH 02/83] polish --- .../extensionResourceLoader/common/extensionResourceLoader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts index 7b43fa7eb8f..dad5b25ece3 100644 --- a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts +++ b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts @@ -38,7 +38,7 @@ export interface IExtensionResourceLoaderService { /** * Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources. */ - getExtensionGalleryResourceURL(galleryExtension: { publisher: string, name: string, version: string }, path?: string): URI | undefined; + getExtensionGalleryResourceURL(galleryExtension: { publisher: string, name: string, version: string }, path?: string): URI | undefined; } @@ -58,7 +58,7 @@ export abstract class AbstractExtensionResourceLoaderService implements IExtensi ) { if (_productService.extensionsGallery) { this._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate; - this._extensionGalleryAuthority = this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)); + this._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)) : undefined; } } From bb472c5519794f235013b45bfecbe8c1030d315a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 4 Nov 2021 09:45:14 -0700 Subject: [PATCH 03/83] xterm@4.15.0-beta.13 --- package.json | 4 ++-- remote/package.json | 4 ++-- remote/web/package.json | 2 +- remote/web/yarn.lock | 8 ++++---- remote/yarn.lock | 18 +++++++++--------- yarn.lock | 18 +++++++++--------- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 42a93255b05..987298959ba 100644 --- a/package.json +++ b/package.json @@ -84,12 +84,12 @@ "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.12.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.10", + "xterm": "4.15.0-beta.13", "xterm-addon-search": "0.9.0-beta.5", "xterm-addon-serialize": "0.7.0-beta.2", "xterm-addon-unicode11": "0.3.0", "xterm-addon-webgl": "0.12.0-beta.15", - "xterm-headless": "4.15.0-beta.10", + "xterm-headless": "4.15.0-beta.13", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index 1851794ddd6..f2659758d02 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,12 +24,12 @@ "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.12.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.10", + "xterm": "4.15.0-beta.13", "xterm-addon-search": "0.9.0-beta.5", "xterm-addon-serialize": "0.7.0-beta.2", "xterm-addon-unicode11": "0.3.0", "xterm-addon-webgl": "0.12.0-beta.15", - "xterm-headless": "4.15.0-beta.10", + "xterm-headless": "4.15.0-beta.13", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 307a919a301..1cd5ff1f204 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -10,7 +10,7 @@ "tas-client-umd": "0.1.4", "vscode-oniguruma": "1.5.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.10", + "xterm": "4.15.0-beta.13", "xterm-addon-search": "0.9.0-beta.5", "xterm-addon-unicode11": "0.3.0", "xterm-addon-webgl": "0.12.0-beta.15" diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 384abe27126..4d08c124a7a 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -128,7 +128,7 @@ xterm-addon-webgl@0.12.0-beta.15: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== -xterm@4.15.0-beta.10: - version "4.15.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.10.tgz#8cda3d7885e8345f2fc6cf9275a43f3833d29acf" - integrity sha512-valoh5ZcY/y7Pe+ffgcSAEFeuZfjzVeUUXcthdxTTsrGEiU1s4QR2EOg4U5jn5wye/Nc6mSfLW3s79R6Ac186w== +xterm@4.15.0-beta.13: + version "4.15.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" + integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== diff --git a/remote/yarn.lock b/remote/yarn.lock index 091d7fe7dad..39f0e8f9aac 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -561,15 +561,15 @@ xterm-addon-webgl@0.12.0-beta.15: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== -xterm-headless@4.15.0-beta.10: - version "4.15.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.10.tgz#2dbcb40dfda7ecfdacc7b63889c80da965480ce7" - integrity sha512-kDAzmaeFX8hAJvbPUJc4dW4SoVBSg4onCVOPyi8QTmxZz1o7I9mX4U7DX1v3PceyfrU27A9k6zXjuTuPjxCCSQ== - -xterm@4.15.0-beta.10: - version "4.15.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.10.tgz#8cda3d7885e8345f2fc6cf9275a43f3833d29acf" - integrity sha512-valoh5ZcY/y7Pe+ffgcSAEFeuZfjzVeUUXcthdxTTsrGEiU1s4QR2EOg4U5jn5wye/Nc6mSfLW3s79R6Ac186w== +xterm-headless@4.15.0-beta.13: + version "4.15.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.13.tgz#f9f8e3799209817e89a2961b3fe643d2ed4b71d5" + integrity sha512-csvpnLqaTi9ULNPcIWAh+o5xIswBYuD30fEmnOd6Az1tZhNaZVp27FnI1vszKdZ37DO8SxN7R1agvnz8II9QLw== + +xterm@4.15.0-beta.13: + version "4.15.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" + integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== yauzl@^2.9.2: version "2.10.0" diff --git a/yarn.lock b/yarn.lock index 2e2f0822981..d171c13d3e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10890,15 +10890,15 @@ xterm-addon-webgl@0.12.0-beta.15: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== -xterm-headless@4.15.0-beta.10: - version "4.15.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.10.tgz#2dbcb40dfda7ecfdacc7b63889c80da965480ce7" - integrity sha512-kDAzmaeFX8hAJvbPUJc4dW4SoVBSg4onCVOPyi8QTmxZz1o7I9mX4U7DX1v3PceyfrU27A9k6zXjuTuPjxCCSQ== - -xterm@4.15.0-beta.10: - version "4.15.0-beta.10" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.10.tgz#8cda3d7885e8345f2fc6cf9275a43f3833d29acf" - integrity sha512-valoh5ZcY/y7Pe+ffgcSAEFeuZfjzVeUUXcthdxTTsrGEiU1s4QR2EOg4U5jn5wye/Nc6mSfLW3s79R6Ac186w== +xterm-headless@4.15.0-beta.13: + version "4.15.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.13.tgz#f9f8e3799209817e89a2961b3fe643d2ed4b71d5" + integrity sha512-csvpnLqaTi9ULNPcIWAh+o5xIswBYuD30fEmnOd6Az1tZhNaZVp27FnI1vszKdZ37DO8SxN7R1agvnz8II9QLw== + +xterm@4.15.0-beta.13: + version "4.15.0-beta.13" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" + integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== y18n@^3.2.1: version "3.2.2" From ff2bd8f82340f47ba0709364b3c93cc461fa7407 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 4 Nov 2021 09:48:41 -0700 Subject: [PATCH 04/83] Include margin in layout, only trigger resize when settings changed Part of #134513 --- .../terminal/browser/terminalInstance.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 6f5cc9defa0..fd4a62e86a2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -128,6 +128,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _fixedRows: number | undefined; private _cwd: string | undefined = undefined; private _initialCwd: string | undefined = undefined; + private _layoutSettingsChanged: boolean = true; private _dimensionsOverride: ITerminalDimensionsOverride | undefined; private _titleReadyPromise: Promise; private _titleReadyComplete: ((title: string) => any) | undefined; @@ -378,6 +379,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { 'editor.fontFamily' ]; if (layoutSettings.some(id => e.affectsConfiguration(id))) { + this._layoutSettingsChanged = true; await this._resize(); } if (e.affectsConfiguration(TerminalSettingId.UnicodeVersion)) { @@ -440,8 +442,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } const computedStyle = window.getComputedStyle(this._wrapperElement!); - const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); - const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); + const width = parseInt(computedStyle.width); + const height = parseInt(computedStyle.height); + this._evaluateColsAndRows(width, height); } @@ -1419,7 +1422,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } - const terminalWidth = this._evaluateColsAndRows(dimension.width, dimension.height); + // Evaluate columns and rows, exclude the wrapper element's margin + const computedStyle = window.getComputedStyle(this._wrapperElement!); + const horizontalMargin = parseInt(computedStyle.marginLeft) + parseInt(computedStyle.marginRight); + const verticalMargin = parseInt(computedStyle.marginTop) + parseInt(computedStyle.marginBottom); + const terminalWidth = this._evaluateColsAndRows(dimension.width - horizontalMargin, dimension.height - verticalMargin); if (!terminalWidth) { return; } @@ -1442,8 +1449,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this.xterm) { // Only apply these settings when the terminal is visible so that // the characters are measured correctly. - if (this._isVisible) { - const font = this.xterm ? this.xterm.getFont() : this._configHelper.getFont(); + if (this._isVisible && this._layoutSettingsChanged) { + const font = this.xterm.getFont(); const config = this._configHelper.config; this._safeSetOption('letterSpacing', font.letterSpacing); this._safeSetOption('lineHeight', font.lineHeight); @@ -1457,6 +1464,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._initDimensions(); cols = this.cols; rows = this.rows; + + this._layoutSettingsChanged = false; } if (isNaN(cols) || isNaN(rows)) { From 8d6b2af2d670191031299c40e2353f31e09dbf04 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:20:11 -0700 Subject: [PATCH 05/83] Change xterm layout to push scroll bar to edge Part of #134513 --- .../terminal/browser/media/terminal.css | 70 ++++++++++++++++--- .../terminal/browser/media/widgets.css | 5 -- .../contrib/terminal/browser/media/xterm.css | 2 +- .../terminal/browser/terminalInstance.ts | 21 ++++-- 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index cf005b14e5a..bb60b347829 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -40,25 +40,72 @@ .monaco-workbench .editor-instance .terminal-wrapper, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper { display: none; - margin: 0 10px; + /* margin: 0 10px; */ height: 100%; - padding-bottom: 2px; + /* padding-bottom: 2px; */ box-sizing: border-box; } +.monaco-workbench .editor-instance .xterm, +.monaco-workbench .pane-body.integrated-terminal .xterm { + padding: 0 10px 2px; + /* Bottom align the terminal withing the split pane */ + /* position: absolute; + bottom: 0; + left: 0; + right: 0; */ +} + +.monaco-workbench .editor-instance .xterm-viewpo, +.monaco-workbench .pane-body.integrated-terminal .xterm-viewport { + z-index: 100; +} + +.monaco-workbench .editor-instance .xterm-screen, +.monaco-workbench .pane-body.integrated-terminal .xterm-screen { + z-index: 101; +} + +.xterm .xterm-screen { + cursor: text; +} + +.xterm.enable-mouse-events .xterm-screen { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; +} + +.xterm.xterm-cursor-pointer .xterm-screen { + cursor: pointer; +} + +.xterm.column-select.focus .xterm-screen { + /* Column selection mode */ + cursor: crosshair; +} + .monaco-workbench .editor-instance .terminal-wrapper.active, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.active { display: block; } -.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .terminal-wrapper, +.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .xterm, +.monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .xterm { + padding-left: 20px; +} +.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm, +.monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm { + padding-right: 20px; +} + +/* .monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .terminal-wrapper, .monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .terminal-wrapper { - margin-left: 20px; + margin-left: 20px; } .monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .terminal-wrapper, .monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .terminal-wrapper { - margin-right: 20px; -} + margin-right: 20px; +} */ .monaco-workbench .editor-instance .xterm a:not(.xterm-invalid-link), .monaco-workbench .pane-body.integrated-terminal .xterm a:not(.xterm-invalid-link) { @@ -69,22 +116,23 @@ .monaco-workbench .editor-instance .terminal-wrapper > div, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper > div { height: 100%; + /* TODO: Align to bottom */ /* Align the viewport and canvases to the bottom of the panel */ - display: flex; - align-items: flex-end; + /* display: flex; + align-items: flex-end; */ } .monaco-workbench .editor-instance .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { box-sizing: border-box; - margin-right: -10px; + /* margin-right: -10px; */ /* Override xterm.js' width as we want to size the viewport to fill the panel so the scrollbar is on the right edge */ width: auto !important; } -.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm-viewport, +/* .monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm-viewport { margin-right: -20px; -} +} */ .monaco-workbench .pane-body.integrated-terminal { font-variant-ligatures: none; diff --git a/src/vs/workbench/contrib/terminal/browser/media/widgets.css b/src/vs/workbench/contrib/terminal/browser/media/widgets.css index 51a9ab8eff2..84b7a642a9c 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/widgets.css +++ b/src/vs/workbench/contrib/terminal/browser/media/widgets.css @@ -40,11 +40,6 @@ opacity: 1; } -.monaco-workbench .pane-body.integrated-terminal .monaco-split-view2.horizontal .split-view-view:last-child .terminal-env-var-info { - /* Adjust for reduced margin in splits */ - right: -8px; -} - .monaco-workbench .terminal-env-var-info.codicon { line-height: 28px; } diff --git a/src/vs/workbench/contrib/terminal/browser/media/xterm.css b/src/vs/workbench/contrib/terminal/browser/media/xterm.css index 018a797e85b..3a8f3534809 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/xterm.css +++ b/src/vs/workbench/contrib/terminal/browser/media/xterm.css @@ -40,9 +40,9 @@ */ .xterm { - font-feature-settings: "liga" 0; position: relative; user-select: none; + -ms-user-select: none; -webkit-user-select: none; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index fd4a62e86a2..7bb0717365e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -455,21 +455,26 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { * @return The terminal's width if it requires a layout. */ private _evaluateColsAndRows(width: number, height: number): number | null { + console.trace(`Instance ${this._instanceId}: _evaluateColsAndRows`, width, height); // Ignore if dimensions are undefined or 0 if (!width || !height) { this._setLastKnownColsAndRows(); + console.log(`Instance ${this._instanceId}: set last known 1`); return null; } const dimension = this._getDimension(width, height); + console.log(`Instance ${this._instanceId}: dimension`, dimension?.width, dimension?.height); if (!dimension) { this._setLastKnownColsAndRows(); + console.log(`Instance ${this._instanceId}: set last known 2`); return null; } const font = this.xterm ? this.xterm.getFont() : this._configHelper.getFont(); if (!font.charWidth || !font.charHeight) { this._setLastKnownColsAndRows(); + console.log(`Instance ${this._instanceId}: set last known 3`); return null; } @@ -492,6 +497,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._rows = newRows; this._fireMaximumDimensionsChanged(); } + console.log(`Instance ${this._instanceId}: result`, this._cols, this._rows, dimension.width); return dimension.width; } @@ -515,10 +521,15 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return undefined; } - if (!this._wrapperElement) { + if (!this._wrapperElement || !this.xterm?.raw.element) { return undefined; } - TerminalInstance._lastKnownCanvasDimensions = new dom.Dimension(Math.min(Constants.MaxCanvasWidth, width), height + (this._hasScrollBar && !this._horizontalScrollbar ? -scrollbarHeight - 2 : 0)/* bottom padding */); + const computedStyle = window.getComputedStyle(this.xterm.raw.element); + const horizontalPadding = parseInt(computedStyle.paddingLeft) + parseInt(computedStyle.paddingRight); + const verticalPadding = parseInt(computedStyle.paddingTop) + parseInt(computedStyle.paddingBottom); + TerminalInstance._lastKnownCanvasDimensions = new dom.Dimension( + Math.min(Constants.MaxCanvasWidth, width - horizontalPadding), + height + (this._hasScrollBar && !this._horizontalScrollbar ? -scrollbarHeight : 0) - 2/* bottom padding */ - verticalPadding); return TerminalInstance._lastKnownCanvasDimensions; } @@ -1411,6 +1422,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } layout(dimension: dom.Dimension): void { + console.log(`Instance ${this._instanceId}: layout`, dimension.width, dimension.height); this._lastLayoutDimensions = dimension; if (this.disableLayout) { return; @@ -1423,10 +1435,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } // Evaluate columns and rows, exclude the wrapper element's margin - const computedStyle = window.getComputedStyle(this._wrapperElement!); - const horizontalMargin = parseInt(computedStyle.marginLeft) + parseInt(computedStyle.marginRight); - const verticalMargin = parseInt(computedStyle.marginTop) + parseInt(computedStyle.marginBottom); - const terminalWidth = this._evaluateColsAndRows(dimension.width - horizontalMargin, dimension.height - verticalMargin); + const terminalWidth = this._evaluateColsAndRows(dimension.width, dimension.height); if (!terminalWidth) { return; } From 440002016512ec52ed9a8ad7b0939736a1d5b9b3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:32:33 -0700 Subject: [PATCH 06/83] Align to bottom using pos absolute --- src/vs/workbench/contrib/terminal/browser/media/terminal.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index bb60b347829..b443d637a27 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -50,10 +50,10 @@ .monaco-workbench .pane-body.integrated-terminal .xterm { padding: 0 10px 2px; /* Bottom align the terminal withing the split pane */ - /* position: absolute; + position: absolute; bottom: 0; left: 0; - right: 0; */ + right: 0; } .monaco-workbench .editor-instance .xterm-viewpo, From 0b0dc63ebdc20ae82b9e43d6c62f9fbac37587c4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 07:12:43 -0700 Subject: [PATCH 07/83] Env var widget play nicely with scroll bar --- src/vs/workbench/contrib/terminal/browser/media/widgets.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/widgets.css b/src/vs/workbench/contrib/terminal/browser/media/widgets.css index 84b7a642a9c..56704ea529b 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/widgets.css +++ b/src/vs/workbench/contrib/terminal/browser/media/widgets.css @@ -26,12 +26,12 @@ .monaco-workbench .terminal-env-var-info { position: absolute; - right: 2px; + right: 10px; /* room for scroll bar */ top: 0; width: 28px; height: 28px; text-align: center; - z-index: 10; + z-index: 102; opacity: 0.5; } From 85aa8a4502dc80d9c4af0e80b8d8c9cb51a6f609 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 07:13:01 -0700 Subject: [PATCH 08/83] Remove logs --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 73dc2812039..2c78022438e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -461,22 +461,18 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Ignore if dimensions are undefined or 0 if (!width || !height) { this._setLastKnownColsAndRows(); - console.log(`Instance ${this._instanceId}: set last known 1`); return null; } const dimension = this._getDimension(width, height); - console.log(`Instance ${this._instanceId}: dimension`, dimension?.width, dimension?.height); if (!dimension) { this._setLastKnownColsAndRows(); - console.log(`Instance ${this._instanceId}: set last known 2`); return null; } const font = this.xterm ? this.xterm.getFont() : this._configHelper.getFont(); if (!font.charWidth || !font.charHeight) { this._setLastKnownColsAndRows(); - console.log(`Instance ${this._instanceId}: set last known 3`); return null; } @@ -499,7 +495,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._rows = newRows; this._fireMaximumDimensionsChanged(); } - console.log(`Instance ${this._instanceId}: result`, this._cols, this._rows, dimension.width); return dimension.width; } @@ -1424,7 +1419,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } layout(dimension: dom.Dimension): void { - console.log(`Instance ${this._instanceId}: layout`, dimension.width, dimension.height); this._lastLayoutDimensions = dimension; if (this.disableLayout) { return; From ab97bc8b0bf1dfd061541050d300cb295cc7ebd0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 08:26:55 -0700 Subject: [PATCH 09/83] Progress on fixed dimensions sizing --- .../terminal/browser/media/terminal.css | 23 ++++++-- .../contrib/terminal/browser/terminal.ts | 2 + .../terminal/browser/terminalInstance.ts | 58 +++++++++++++------ 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index b443d637a27..71b7df499e2 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -56,7 +56,12 @@ right: 0; } -.monaco-workbench .editor-instance .xterm-viewpo, +.monaco-workbench .editor-instance .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper .xterm, +.monaco-workbench .pane-body.integrated-terminal .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper .xterm { + position: static; +} + +.monaco-workbench .editor-instance .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { z-index: 100; } @@ -125,14 +130,20 @@ .monaco-workbench .editor-instance .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { box-sizing: border-box; - /* margin-right: -10px; */ +} + +.monaco-workbench .editor-instance .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper, +.monaco-workbench .pane-body.integrated-terminal .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper { + /* The viewport should be positioned against this so it does't conflict with a fixed dimensions terminal horizontal scroll bar*/ + position: relative; +} + +/* TODO: Add class for fixed dimensions */ +.monaco-workbench .editor-instance :not(.terminal-split-pane > .monaco-scrollable-element) > .terminal-wrapper .xterm-viewport, +.monaco-workbench .pane-body.integrated-terminal :not(.terminal-split-pane > .monaco-scrollable-element) > .terminal-wrapper .xterm-viewport { /* Override xterm.js' width as we want to size the viewport to fill the panel so the scrollbar is on the right edge */ width: auto !important; } -/* .monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm-viewport { - margin-right: -20px; -} */ .monaco-workbench .pane-body.integrated-terminal { font-variant-ligatures: none; diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 44a198e9ad5..31894a9ee79 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -387,6 +387,8 @@ export interface ITerminalInstance { readonly rows: number; readonly maxCols: number; readonly maxRows: number; + readonly fixedCols?: number; + readonly fixedRows?: number; readonly icon?: TerminalIcon; readonly color?: string; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 2c78022438e..7537026e092 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -457,7 +457,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { * @return The terminal's width if it requires a layout. */ private _evaluateColsAndRows(width: number, height: number): number | null { - console.trace(`Instance ${this._instanceId}: _evaluateColsAndRows`, width, height); // Ignore if dimensions are undefined or 0 if (!width || !height) { this._setLastKnownColsAndRows(); @@ -1611,6 +1610,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this._fixedCols = this._parseFixedDimension(cols); + this._labelComputer?.refreshLabel(); this._terminalHasFixedWidth.set(!!this._fixedCols); const rows = await this._quickInputService.input({ title: nls.localize('setTerminalDimensionsRow', "Set Fixed Dimensions: Row"), @@ -1646,39 +1646,44 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._fixedCols = undefined; this._fixedRows = undefined; this._hasScrollBar = false; + // TODO: Merge into refresh scroll bar that uses fixedCols/Rows? + await this._removeScrollbar(); this._initDimensions(); await this._resize(); - this._horizontalScrollbar?.setScrollDimensions({ scrollWidth: 0 }); } else { - let maxCols = 0; + let maxLineLength = 0; if (!this.xterm.raw.buffer.active.getLine(0)) { return; } - const lineWidth = this.xterm.raw.buffer.active.getLine(0)!.length; for (let i = this.xterm.raw.buffer.active.length - 1; i >= this.xterm.raw.buffer.active.viewportY; i--) { const lineInfo = this._getWrappedLineCount(i, this.xterm.raw.buffer.active); - maxCols = Math.max(maxCols, ((lineInfo.lineCount * lineWidth) - lineInfo.endSpaces) || 0); + maxLineLength = Math.max(maxLineLength, ((lineInfo.lineCount * this.xterm.raw.cols) - lineInfo.endSpaces) || 0); i = lineInfo.currentIndex; } - maxCols = Math.min(maxCols, Constants.MaxSupportedCols); - this._fixedCols = maxCols; + // Fixed columns should be at least xterm.js' regular column count + this._fixedCols = Math.max(this.maxCols, Math.min(maxLineLength, Constants.MaxSupportedCols)); await this._addScrollbar(); } + this._labelComputer?.refreshLabel(); this.focus(); } + // TODO: Add fixed dimensions class + // TODO: Remove right padding when using fixed diemnsions private async _addScrollbar(): Promise { const charWidth = (this.xterm ? this.xterm.getFont() : this._configHelper.getFont()).charWidth; if (!this.xterm?.raw.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { return; } - if (this._fixedCols < this.xterm.raw.buffer.active.getLine(0)!.length) { - // no scrollbar needed - return; - } + // TODO: Look into effects of this; fixed dims always have room for scrollbar + // if (this._fixedCols < this.xterm.raw.buffer.active.getLine(0)!.length) { + // // no scrollbar needed + // return; + // } this._hasScrollBar = true; this._initDimensions(); - this._fixedRows = this.rows; + // Always remove a row to make room for the scroll bar + this._fixedRows = this.rows - 1; await this._resize(); this._terminalHasFixedWidth.set(true); if (!this._horizontalScrollbar) { @@ -1691,12 +1696,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { })); this._container.appendChild(this._horizontalScrollbar.getDomNode()); } - this._horizontalScrollbar.setScrollDimensions( - { - width: this.xterm.raw.element.clientWidth, - scrollWidth: this._fixedCols * charWidth - }); - this._horizontalScrollbar!.getDomNode().style.paddingBottom = '16px'; + this._horizontalScrollbar.setScrollDimensions({ + width: this.xterm.raw.element.clientWidth, + scrollWidth: this._fixedCols * charWidth + }); + this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; // work around for https://github.com/xtermjs/xterm.js/issues/3482 for (let i = this.xterm.raw.buffer.active.viewportY; i < this.xterm.raw.buffer.active.length; i++) { @@ -1705,6 +1709,17 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } + private async _removeScrollbar(): Promise { + if (!this._container || !this._wrapperElement) { + return; + } + this._horizontalScrollbar?.getDomNode().remove(); + this._horizontalScrollbar?.dispose(); + this._horizontalScrollbar = undefined; + this._wrapperElement.remove(); + this._container.appendChild(this._wrapperElement); + } + private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { let line = buffer.getLine(index); if (!line) { @@ -2077,6 +2092,7 @@ export interface ITerminalLabelTemplateProperties { process?: string | null | undefined; sequence?: string | null | undefined; task?: string | null | undefined; + fixedDimensions?: string | null | undefined; separator?: string | ISeparator | null | undefined; } @@ -2095,11 +2111,12 @@ export class TerminalLabelComputer extends Disposable { readonly onDidChangeLabel = this._onDidChangeLabel.event; constructor( private readonly _configHelper: TerminalConfigHelper, - private readonly _instance: Pick, + private readonly _instance: Pick, @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService ) { super(); } + refreshLabel(): void { this._title = this.computeLabel(this._configHelper.config.tabs.title, TerminalLabelType.Title); this._description = this.computeLabel(this._configHelper.config.tabs.description, TerminalLabelType.Description); @@ -2120,6 +2137,9 @@ export class TerminalLabelComputer extends Disposable { process: this._instance.processName, sequence: this._instance.sequence, task: this._instance.shellLaunchConfig.description === 'Task' ? 'Task' : undefined, + fixedDimensions: this._instance.fixedCols + ? (this._instance.fixedRows ? `\u2194${this._instance.fixedCols} \u2195${this._instance.fixedRows}` : `\u2194${this._instance.fixedCols}`) + : (this._instance.fixedRows ? `\u2195${this._instance.fixedRows}` : ''), separator: { label: this._configHelper.config.tabs.separator } }; labelTemplate = labelTemplate.trim(); From ea074f283a7c370fcb2ee5ff9b40f88fa208a44d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 08:29:05 -0700 Subject: [PATCH 10/83] Add fixed-dims class --- .../contrib/terminal/browser/media/terminal.css | 12 ++++++------ .../contrib/terminal/browser/terminalInstance.ts | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 71b7df499e2..07b3b70a9c6 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -56,8 +56,8 @@ right: 0; } -.monaco-workbench .editor-instance .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper .xterm, -.monaco-workbench .pane-body.integrated-terminal .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper .xterm { +.monaco-workbench .editor-instance .terminal-wrapper.fixed-dims .xterm, +.monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.fixed-dims .xterm { position: static; } @@ -132,15 +132,15 @@ box-sizing: border-box; } -.monaco-workbench .editor-instance .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper, -.monaco-workbench .pane-body.integrated-terminal .terminal-split-pane > .monaco-scrollable-element > .terminal-wrapper { +.monaco-workbench .editor-instance .terminal-wrapper.fixed-dims, +.monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.fixed-dims { /* The viewport should be positioned against this so it does't conflict with a fixed dimensions terminal horizontal scroll bar*/ position: relative; } /* TODO: Add class for fixed dimensions */ -.monaco-workbench .editor-instance :not(.terminal-split-pane > .monaco-scrollable-element) > .terminal-wrapper .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal :not(.terminal-split-pane > .monaco-scrollable-element) > .terminal-wrapper .xterm-viewport { +.monaco-workbench .editor-instance .terminal-wrapper:not(.fixed-dims) .xterm-viewport, +.monaco-workbench .pane-body.integrated-terminal .terminal-wrapper:not(.fixed-dims) .xterm-viewport { /* Override xterm.js' width as we want to size the viewport to fill the panel so the scrollbar is on the right edge */ width: auto !important; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 7537026e092..ed8fb746c31 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1668,13 +1668,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.focus(); } - // TODO: Add fixed dimensions class + // TODO: Ideally don't set fixed rows when sizing to content // TODO: Remove right padding when using fixed diemnsions private async _addScrollbar(): Promise { const charWidth = (this.xterm ? this.xterm.getFont() : this._configHelper.getFont()).charWidth; if (!this.xterm?.raw.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { return; } + this._wrapperElement.classList.add('fixed-dims'); // TODO: Look into effects of this; fixed dims always have room for scrollbar // if (this._fixedCols < this.xterm.raw.buffer.active.getLine(0)!.length) { // // no scrollbar needed @@ -1717,6 +1718,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._horizontalScrollbar?.dispose(); this._horizontalScrollbar = undefined; this._wrapperElement.remove(); + this._wrapperElement.classList.remove('fixed-dims'); this._container.appendChild(this._wrapperElement); } From cedaa04e87ec03663820a1b1661becfe88eb70d1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 09:46:20 -0700 Subject: [PATCH 11/83] Polish fixed dimensions, remove scrollable when toggled off --- .../terminal/browser/terminalInstance.ts | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index ed8fb746c31..9943af41351 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1646,7 +1646,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._fixedCols = undefined; this._fixedRows = undefined; this._hasScrollBar = false; - // TODO: Merge into refresh scroll bar that uses fixedCols/Rows? await this._removeScrollbar(); this._initDimensions(); await this._resize(); @@ -1661,26 +1660,24 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { i = lineInfo.currentIndex; } // Fixed columns should be at least xterm.js' regular column count - this._fixedCols = Math.max(this.maxCols, Math.min(maxLineLength, Constants.MaxSupportedCols)); - await this._addScrollbar(); + const proposedCols = Math.max(this.maxCols, Math.min(maxLineLength, Constants.MaxSupportedCols)); + // Don't switch to fixed dimensions if the content already fits as it makes the scroll + // bar look bad being off the edge + if (proposedCols > this.xterm.raw.cols) { + this._fixedCols = proposedCols; + await this._addScrollbar(); + } } this._labelComputer?.refreshLabel(); this.focus(); } - // TODO: Ideally don't set fixed rows when sizing to content - // TODO: Remove right padding when using fixed diemnsions private async _addScrollbar(): Promise { const charWidth = (this.xterm ? this.xterm.getFont() : this._configHelper.getFont()).charWidth; if (!this.xterm?.raw.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { return; } this._wrapperElement.classList.add('fixed-dims'); - // TODO: Look into effects of this; fixed dims always have room for scrollbar - // if (this._fixedCols < this.xterm.raw.buffer.active.getLine(0)!.length) { - // // no scrollbar needed - // return; - // } this._hasScrollBar = true; this._initDimensions(); // Always remove a row to make room for the scroll bar @@ -1699,7 +1696,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } this._horizontalScrollbar.setScrollDimensions({ width: this.xterm.raw.element.clientWidth, - scrollWidth: this._fixedCols * charWidth + scrollWidth: this._fixedCols * charWidth + 30 }); this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; @@ -1722,14 +1719,16 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._container.appendChild(this._wrapperElement); } + // TODO: Move into XtermTerminal and write tests private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { let line = buffer.getLine(index); if (!line) { throw new Error('Could not get line'); } let currentIndex = index; - let endSpaces = -1; - for (let i = line?.length || 0; i > 0; i--) { + let endSpaces = 0; + // line.length may exceed cols as it doesn't necessarily trim the backing array on resize + for (let i = Math.min(line.length, this.xterm!.raw.cols) - 1; i >= 0; i--) { if (line && !line?.getCell(i)?.getChars()) { endSpaces++; } else { From 9419cdcf892e0afa696fecdff758e79c3909bce2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 09:48:23 -0700 Subject: [PATCH 12/83] Remove scroll bar when setting fixed dimensions to dynamic --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 9943af41351..888f1e58a90 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1621,7 +1621,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this._fixedRows = this._parseFixedDimension(rows); - this._addScrollbar(); + if (this._fixedRows || this._fixedCols) { + this._addScrollbar(); + } else { + this._removeScrollbar(); + } this._resize(); this.focus(); } @@ -1696,6 +1700,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } this._horizontalScrollbar.setScrollDimensions({ width: this.xterm.raw.element.clientWidth, + // TODO: Use const/property for padding scrollWidth: this._fixedCols * charWidth + 30 }); this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; From f2fa8597a31fa497b3b3edea170a130a9bb6add1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 09:53:30 -0700 Subject: [PATCH 13/83] Create refresh scroll bar method, increase scroll padding --- .../terminal/browser/terminalInstance.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 888f1e58a90..6e43621a153 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1621,11 +1621,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this._fixedRows = this._parseFixedDimension(rows); - if (this._fixedRows || this._fixedCols) { - this._addScrollbar(); - } else { - this._removeScrollbar(); - } + this._labelComputer?.refreshLabel(); + await this._refreshScrollbar(); this._resize(); this.focus(); } @@ -1650,7 +1647,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._fixedCols = undefined; this._fixedRows = undefined; this._hasScrollBar = false; - await this._removeScrollbar(); this._initDimensions(); await this._resize(); } else { @@ -1669,13 +1665,20 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // bar look bad being off the edge if (proposedCols > this.xterm.raw.cols) { this._fixedCols = proposedCols; - await this._addScrollbar(); } } + await this._refreshScrollbar(); this._labelComputer?.refreshLabel(); this.focus(); } + private _refreshScrollbar(): Promise { + if (this._fixedCols || this._fixedRows) { + return this._addScrollbar(); + } + return this._removeScrollbar(); + } + private async _addScrollbar(): Promise { const charWidth = (this.xterm ? this.xterm.getFont() : this._configHelper.getFont()).charWidth; if (!this.xterm?.raw.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { @@ -1701,7 +1704,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._horizontalScrollbar.setScrollDimensions({ width: this.xterm.raw.element.clientWidth, // TODO: Use const/property for padding - scrollWidth: this._fixedCols * charWidth + 30 + scrollWidth: this._fixedCols * charWidth + 40 }); this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; @@ -1713,11 +1716,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } private async _removeScrollbar(): Promise { - if (!this._container || !this._wrapperElement) { + if (!this._container || !this._wrapperElement || !this._horizontalScrollbar) { return; } - this._horizontalScrollbar?.getDomNode().remove(); - this._horizontalScrollbar?.dispose(); + this._horizontalScrollbar.getDomNode().remove(); + this._horizontalScrollbar.dispose(); this._horizontalScrollbar = undefined; this._wrapperElement.remove(); this._wrapperElement.classList.remove('fixed-dims'); From 14595210d2bc3017a9e55463e92fbf758404ff26 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 5 Nov 2021 12:51:21 -0700 Subject: [PATCH 14/83] Move line counting into XtermTerminal --- .../terminal/browser/terminalInstance.ts | 64 +++++++++---------- .../terminal/browser/xterm/xtermTerminal.ts | 34 +++++++++- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 6e43621a153..4e2fbcfd915 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -29,7 +29,7 @@ import { TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { ITerminalInstanceService, ITerminalInstance, ITerminalExternalLinkProvider, IRequestAddInstanceToGroupEvent } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; -import type { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; +import type { Terminal as XTermTerminal, ITerminalAddon } from 'xterm'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/xterm/navigationModeAddon'; import { IViewsService, IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; import { EnvironmentVariableInfoWidget } from 'vs/workbench/contrib/terminal/browser/widgets/environmentVariableInfoWidget'; @@ -1650,17 +1650,17 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._initDimensions(); await this._resize(); } else { - let maxLineLength = 0; - if (!this.xterm.raw.buffer.active.getLine(0)) { - return; - } - for (let i = this.xterm.raw.buffer.active.length - 1; i >= this.xterm.raw.buffer.active.viewportY; i--) { - const lineInfo = this._getWrappedLineCount(i, this.xterm.raw.buffer.active); - maxLineLength = Math.max(maxLineLength, ((lineInfo.lineCount * this.xterm.raw.cols) - lineInfo.endSpaces) || 0); - i = lineInfo.currentIndex; - } + // let maxLineLength = 0; + // if (!this.xterm.raw.buffer.active.getLine(0)) { + // return; + // } + // for (let i = this.xterm.raw.buffer.active.length - 1; i >= this.xterm.raw.buffer.active.viewportY; i--) { + // const lineInfo = this._getWrappedLineCount(i, this.xterm.raw.buffer.active); + // maxLineLength = Math.max(maxLineLength, ((lineInfo.lineCount * this.xterm.raw.cols) - lineInfo.endSpaces) || 0); + // i = lineInfo.currentIndex; + // } // Fixed columns should be at least xterm.js' regular column count - const proposedCols = Math.max(this.maxCols, Math.min(maxLineLength, Constants.MaxSupportedCols)); + const proposedCols = Math.max(this.maxCols, Math.min(this.xterm.getLongestViewportWrappedLineLength(), Constants.MaxSupportedCols)); // Don't switch to fixed dimensions if the content already fits as it makes the scroll // bar look bad being off the edge if (proposedCols > this.xterm.raw.cols) { @@ -1728,27 +1728,27 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } // TODO: Move into XtermTerminal and write tests - private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { - let line = buffer.getLine(index); - if (!line) { - throw new Error('Could not get line'); - } - let currentIndex = index; - let endSpaces = 0; - // line.length may exceed cols as it doesn't necessarily trim the backing array on resize - for (let i = Math.min(line.length, this.xterm!.raw.cols) - 1; i >= 0; i--) { - if (line && !line?.getCell(i)?.getChars()) { - endSpaces++; - } else { - break; - } - } - while (line?.isWrapped && currentIndex > 0) { - currentIndex--; - line = buffer.getLine(currentIndex); - } - return { lineCount: index - currentIndex + 1, currentIndex, endSpaces }; - } + // private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { + // let line = buffer.getLine(index); + // if (!line) { + // throw new Error('Could not get line'); + // } + // let currentIndex = index; + // let endSpaces = 0; + // // line.length may exceed cols as it doesn't necessarily trim the backing array on resize + // for (let i = Math.min(line.length, this.xterm!.raw.cols) - 1; i >= 0; i--) { + // if (line && !line?.getCell(i)?.getChars()) { + // endSpaces++; + // } else { + // break; + // } + // } + // while (line?.isWrapped && currentIndex > 0) { + // currentIndex--; + // line = buffer.getLine(currentIndex); + // } + // return { lineCount: index - currentIndex + 1, currentIndex, endSpaces }; + // } private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { this._shellLaunchConfig.args = shellLaunchConfig.args; diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index dfc69cec4fd..213eea3cde1 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { ITheme, RendererType, Terminal as RawXtermTerminal } from 'xterm'; +import type { IBuffer, ITheme, RendererType, Terminal as RawXtermTerminal } from 'xterm'; import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search'; import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11'; import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl'; @@ -222,6 +222,38 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { return this._configHelper.getFont(this._core); } + getLongestViewportWrappedLineLength(): number { + let maxLineLength = 0; + for (let i = this.raw.buffer.active.length - 1; i >= this.raw.buffer.active.viewportY; i--) { + const lineInfo = this._getWrappedLineCount(i, this.raw.buffer.active); + maxLineLength = Math.max(maxLineLength, ((lineInfo.lineCount * this.raw.cols) - lineInfo.endSpaces) || 0); + i = lineInfo.currentIndex; + } + return maxLineLength; + } + + private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { + let line = buffer.getLine(index); + if (!line) { + throw new Error('Could not get line'); + } + let currentIndex = index; + let endSpaces = 0; + // line.length may exceed cols as it doesn't necessarily trim the backing array on resize + for (let i = Math.min(line.length, this.raw.cols) - 1; i >= 0; i--) { + if (line && !line?.getCell(i)?.getChars()) { + endSpaces++; + } else { + break; + } + } + while (line?.isWrapped && currentIndex > 0) { + currentIndex--; + line = buffer.getLine(currentIndex); + } + return { lineCount: index - currentIndex + 1, currentIndex, endSpaces }; + } + scrollDownLine(): void { this.raw.scrollLines(1); } From 89862489b1e5892eb2d0b6aec1d7bfcec9b07a6b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 08:45:23 +0100 Subject: [PATCH 15/83] clean up --- .../browser/extensionResourceLoaderService.ts | 2 +- .../common/extensionResourceLoader.ts | 12 ++++++------ .../extensionResourceLoaderService.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts index 8f68d8a7ab2..85b431f430e 100644 --- a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -24,7 +24,7 @@ class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderServ @IProductService productService: IProductService, @IEnvironmentService environmentService: IEnvironmentService, @IConfigurationService configurationService: IConfigurationService, - @ILogService readonly _logService: ILogService, + @ILogService private readonly _logService: ILogService, ) { super(fileService, storageService, productService, environmentService, configurationService); } diff --git a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts index dad5b25ece3..e8f41ff6e41 100644 --- a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts +++ b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts @@ -33,7 +33,7 @@ export interface IExtensionResourceLoaderService { /** * Returns whether the gallery provides extension resources. */ - supportsExtensionGalleryResources: boolean; + readonly supportsExtensionGalleryResources: boolean; /** * Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources. @@ -50,11 +50,11 @@ export abstract class AbstractExtensionResourceLoaderService implements IExtensi private readonly _extensionGalleryAuthority: string | undefined; constructor( - readonly _fileService: IFileService, - readonly _storageService: IStorageService, - readonly _productService: IProductService, - readonly _environmentService: IEnvironmentService, - readonly _configurationService: IConfigurationService, + protected readonly _fileService: IFileService, + private readonly _storageService: IStorageService, + private readonly _productService: IProductService, + private readonly _environmentService: IEnvironmentService, + private readonly _configurationService: IConfigurationService, ) { if (_productService.extensionsGallery) { this._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate; diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts index 4062092b43b..471f36a8d0a 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts @@ -22,7 +22,7 @@ export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoa @IProductService productService: IProductService, @IEnvironmentService environmentService: IEnvironmentService, @IConfigurationService configurationService: IConfigurationService, - @IRequestService readonly _requestService: IRequestService, + @IRequestService private readonly _requestService: IRequestService, ) { super(fileService, storageService, productService, environmentService, configurationService); } From 13438fb09f9085d27d4e1d64acfc15520aa415fc Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 8 Nov 2021 14:00:00 +0100 Subject: [PATCH 16/83] Adopts injected text for breakpoint space decoration. --- .../browser/breakpointEditorContribution.ts | 16 +++++++++++++--- .../debug/browser/media/debug.contribution.css | 8 +++++++- .../debug/test/browser/breakpoints.test.ts | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 04317e2bc55..5003be9dfdd 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -73,6 +73,8 @@ export function createBreakpointDecorations(model: ITextModel, breakpoints: Read return result; } +const noBreakWhitespace = '\xa0'; + function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, state: State, breakpointsActivated: boolean, showBreakpointsInOverviewRuler: boolean): IModelDecorationOptions { const { icon, message } = getBreakpointMessageAndIcon(state, breakpointsActivated, breakpoint, undefined); let glyphMarginHoverMessage: MarkdownString | undefined; @@ -100,7 +102,11 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi glyphMarginClassName: ThemeIcon.asClassName(icon), glyphMarginHoverMessage, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - beforeContentClassName: renderInline ? `debug-breakpoint-placeholder` : undefined, + before: renderInline ? { + content: noBreakWhitespace, + inlineClassName: `debug-breakpoint-placeholder`, + inlineClassNameAffectsLetterSpacing: true + } : undefined, overviewRuler: overviewRulerDecoration }; } @@ -133,7 +139,11 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio options: { description: 'breakpoint-placeholder-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - beforeContentClassName: breakpointAtPosition ? undefined : `debug-breakpoint-placeholder` + before: breakpointAtPosition ? undefined : { + content: noBreakWhitespace, + inlineClassName: `debug-breakpoint-placeholder`, + inlineClassNameAffectsLetterSpacing: true + }, }, breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined }); @@ -466,7 +476,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi this.breakpointDecorations = decorationIds.map((decorationId, index) => { let inlineWidget: InlineBreakpointWidget | undefined = undefined; const breakpoint = breakpoints[index]; - if (desiredBreakpointDecorations[index].options.beforeContentClassName) { + if (desiredBreakpointDecorations[index].options.before) { const contextMenuActions = () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column); inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredBreakpointDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, contextMenuActions); } diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index dce0bd9ab47..d8d1c897632 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -30,7 +30,13 @@ left: -8px !important; } -.monaco-editor .debug-breakpoint-placeholder::before, +.monaco-editor .debug-breakpoint-placeholder { + width: 0.9em; + display: inline-flex; + vertical-align: middle; + margin-top: -1px; +} + .monaco-editor .debug-top-stack-frame-column::before { content: ' '; width: 0.9em; diff --git a/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts b/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts index b3d0cf795ab..6c7a6a4eaa9 100644 --- a/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts @@ -358,7 +358,7 @@ suite('Debug - Breakpoints', () => { assert.deepStrictEqual(decorations[1].range, new Range(2, 4, 2, 5)); assert.deepStrictEqual(decorations[2].range, new Range(3, 5, 3, 6)); assert.strictEqual(decorations[0].options.beforeContentClassName, undefined); - assert.strictEqual(decorations[1].options.beforeContentClassName, `debug-breakpoint-placeholder`); + assert.strictEqual(decorations[1].options.before?.inlineClassName, `debug-breakpoint-placeholder`); assert.strictEqual(decorations[0].options.overviewRuler?.position, OverviewRulerLane.Left); const expected = new MarkdownString().appendCodeblock(languageId, 'Expression condition: x > 5'); assert.deepStrictEqual(decorations[0].options.glyphMarginHoverMessage, expected); From 6336884c388008561ca0a0a22fb89e64937b1754 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 8 Nov 2021 13:59:43 +0100 Subject: [PATCH 17/83] Adopts injected text for debug-top-stack-frame-column spacer. --- src/vs/base/common/strings.ts | 2 ++ .../contrib/debug/browser/breakpointEditorContribution.ts | 3 +-- .../contrib/debug/browser/callStackEditorContribution.ts | 7 ++++++- .../contrib/debug/browser/media/debug.contribution.css | 5 ++--- .../workbench/contrib/debug/test/browser/callStack.test.ts | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index e6a325056cb..ac3308e8a3e 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -1030,3 +1030,5 @@ const enum CodePoint { */ enclosingKeyCap = 0x20E3, } + +export const noBreakWhitespace = '\xa0'; diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 5003be9dfdd..978f847cf19 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -36,6 +36,7 @@ import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { ILabelService } from 'vs/platform/label/common/label'; import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { noBreakWhitespace } from 'vs/base/common/strings'; const $ = dom.$; @@ -73,8 +74,6 @@ export function createBreakpointDecorations(model: ITextModel, breakpoints: Read return result; } -const noBreakWhitespace = '\xa0'; - function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, state: State, breakpointsActivated: boolean, showBreakpointsInOverviewRuler: boolean): IModelDecorationOptions { const { icon, message } = getBreakpointMessageAndIcon(state, breakpointsActivated, breakpoint, undefined); let glyphMarginHoverMessage: MarkdownString | undefined; diff --git a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts index 565463d04c9..5f69a93eeb5 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts @@ -17,6 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { distinct } from 'vs/base/common/arrays'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { debugStackframe, debugStackframeFocused } from 'vs/workbench/contrib/debug/browser/debugIcons'; +import { noBreakWhitespace } from 'vs/base/common/strings'; export const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#ffff0033' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.')); export const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#7abd7a4d' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.')); @@ -80,7 +81,11 @@ export function createDecorationsForStackFrame(stackFrame: IStackFrame, isFocuse result.push({ options: { description: 'top-stack-frame-inline-decoration', - beforeContentClassName: noCharactersBefore ? 'debug-top-stack-frame-column start-of-line' : 'debug-top-stack-frame-column' + before: { + content: noBreakWhitespace, + inlineClassName: noCharactersBefore ? 'debug-top-stack-frame-column start-of-line' : 'debug-top-stack-frame-column', + inlineClassNameAffectsLetterSpacing: true + }, }, range: columnUntilEOLRange }); diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index d8d1c897632..67aba82591a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -37,8 +37,7 @@ margin-top: -1px; } -.monaco-editor .debug-top-stack-frame-column::before { - content: ' '; +.monaco-editor .debug-top-stack-frame-column { width: 0.9em; display: inline-flex; vertical-align: middle; @@ -46,7 +45,7 @@ } /* Do not push text with inline decoration when decoration on start of line */ -.monaco-editor .debug-top-stack-frame-column.start-of-line::before { +.monaco-editor .debug-top-stack-frame-column.start-of-line { position: absolute; top: 50%; transform: translate(-17px, -50%); diff --git a/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts b/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts index fef65e21829..64a90805523 100644 --- a/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts @@ -335,7 +335,7 @@ suite('Debug - CallStack', () => { assert.strictEqual(decorations[1].options.className, 'debug-top-stack-frame-line'); assert.strictEqual(decorations[1].options.isWholeLine, true); // Inline decoration gets rendered in this case - assert.strictEqual(decorations[2].options.beforeContentClassName, 'debug-top-stack-frame-column'); + assert.strictEqual(decorations[2].options.before?.inlineClassName, 'debug-top-stack-frame-column'); assert.deepStrictEqual(decorations[2].range, new Range(1, 2, 1, Constants.MAX_SAFE_SMALL_INTEGER)); }); From 744c859e71bd5e98234ddbed13aada49fe6f4596 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 8 Nov 2021 14:11:22 +0100 Subject: [PATCH 18/83] Adopts injected text for debug inline values. --- .../debug/browser/debugEditorContribution.ts | 44 ++++++++++--------- .../browser/media/debug.contribution.css | 6 +++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 655a1ee37f6..5efdae15f8a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -18,8 +18,6 @@ import { distinct, flatten } from 'vs/base/common/arrays'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; -import { IDecorationOptions } from 'vs/editor/common/editorCommon'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { Range } from 'vs/editor/common/core/range'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -33,7 +31,7 @@ import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; import { memoize } from 'vs/base/common/decorators'; import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover'; -import { ITextModel } from 'vs/editor/common/model'; +import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { basename } from 'vs/base/common/path'; @@ -44,13 +42,11 @@ import { Event } from 'vs/base/common/event'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Expression } from 'vs/workbench/contrib/debug/common/debugModel'; -import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { addDisposableListener } from 'vs/base/browser/dom'; import { DomEmitter } from 'vs/base/browser/event'; const LAUNCH_JSON_REGEX = /\.vscode\/launch\.json$/; -const INLINE_VALUE_DECORATION_KEY = 'inlinevaluedecoration'; const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We want to limit ourselves for perf reasons const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped @@ -72,7 +68,7 @@ class InlineSegment { } } -function createInlineValueDecoration(lineNumber: number, contentText: string, column = Constants.MAX_SAFE_SMALL_INTEGER): IDecorationOptions { +function createInlineValueDecoration(lineNumber: number, contentText: string, column = Constants.MAX_SAFE_SMALL_INTEGER): IModelDeltaDecoration { // If decoratorText is too long, trim and add ellipses. This could happen for minified files with everything on a single line if (contentText.length > MAX_INLINE_DECORATOR_LENGTH) { contentText = contentText.substr(0, MAX_INLINE_DECORATOR_LENGTH) + '...'; @@ -85,18 +81,23 @@ function createInlineValueDecoration(lineNumber: number, contentText: string, co startColumn: column, endColumn: column }, - renderOptions: { + options: { + description: 'debug-inline-value-decoration', after: { - contentText, - backgroundColor: themeColorFromId(debugInlineBackground), - margin: '10px', - color: themeColorFromId(debugInlineForeground) - } + content: replaceWsWithNoBreakWs(contentText), + inlineClassName: 'debug-inline-value', + inlineClassNameAffectsLetterSpacing: true, + }, + showIfCollapsed: true } }; } -function createInlineValueDecorationsInsideRange(expressions: ReadonlyArray, range: Range, model: ITextModel, wordToLineNumbersMap: Map): IDecorationOptions[] { +function replaceWsWithNoBreakWs(str: string): string { + return str.replace(/[ \t]/g, strings.noBreakWhitespace); +} + +function createInlineValueDecorationsInsideRange(expressions: ReadonlyArray, range: Range, model: ITextModel, wordToLineNumbersMap: Map): IModelDeltaDecoration[] { const nameValueMap = new Map(); for (let expr of expressions) { nameValueMap.set(expr.name, expr.value); @@ -126,7 +127,7 @@ function createInlineValueDecorationsInsideRange(expressions: ReadonlyArray { const contentText = names.sort((first, second) => { @@ -196,13 +197,13 @@ export class DebugEditorContribution implements IDebugEditorContribution { private configurationWidget: FloatingClickWidget | undefined; private altListener: IDisposable | undefined; private altPressed = false; + private oldDecorations: string[] = []; constructor( private editor: ICodeEditor, @IDebugService private readonly debugService: IDebugService, @IInstantiationService private readonly instantiationService: IInstantiationService, @ICommandService private readonly commandService: ICommandService, - @ICodeEditorService private readonly codeEditorService: ICodeEditorService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService private readonly configurationService: IConfigurationService, @IHostService private readonly hostService: IHostService, @@ -213,7 +214,6 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.toDispose = []; this.registerListeners(); this.updateConfigurationWidgetVisibility(); - this.codeEditorService.registerDecorationType('debug-inline-value-decoration', INLINE_VALUE_DECORATION_KEY, {}); this.exceptionWidgetVisible = CONTEXT_EXCEPTION_WIDGET_VISIBLE.bindTo(contextKeyService); this.toggleExceptionWidget(); } @@ -575,7 +575,9 @@ export class DebugEditorContribution implements IDebugEditorContribution { @memoize private get removeInlineValuesScheduler(): RunOnceScheduler { return new RunOnceScheduler( - () => this.editor.removeDecorations(INLINE_VALUE_DECORATION_KEY), + () => { + this.oldDecorations = this.editor.deltaDecorations(this.oldDecorations, []); + }, 100 ); } @@ -605,7 +607,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.removeInlineValuesScheduler.cancel(); - let allDecorations: IDecorationOptions[]; + let allDecorations: IModelDeltaDecoration[]; if (InlineValuesProviderRegistry.has(model)) { @@ -717,10 +719,10 @@ export class DebugEditorContribution implements IDebugEditorContribution { allDecorations = distinct(decorationsPerScope.reduce((previous, current) => previous.concat(current), []), // Deduplicate decorations since same variable can appear in multiple scopes, leading to duplicated decorations #129770 - decoration => `${decoration.range.startLineNumber}:${decoration.renderOptions?.after?.contentText}`); + decoration => `${decoration.range.startLineNumber}:${decoration?.options.after?.content}`); } - this.editor.setDecorations('debug-inline-value-decoration', INLINE_VALUE_DECORATION_KEY, allDecorations); + this.oldDecorations = this.editor.deltaDecorations(this.oldDecorations, allDecorations); } dispose(): void { @@ -731,5 +733,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.configurationWidget.dispose(); } this.toDispose = dispose(this.toDispose); + + this.oldDecorations = this.editor.deltaDecorations(this.oldDecorations, []); } } diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 67aba82591a..4cec7a57750 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -122,3 +122,9 @@ .monaco-workbench .monaco-list-row .expression .unavailable { font-style: italic; } + +.monaco-workbench .debug-inline-value { + background-color: var(--vscode-editor-inlineValuesBackground); + margin: 10px; + color: var(--vscode-editor-inlineValuesForeground); +} From e7eb1fca51c97d57095bbae6817f13a383b21aaf Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 8 Nov 2021 16:45:40 +0100 Subject: [PATCH 19/83] Makes DynamicCssRules reusable. --- src/vs/editor/browser/editorDom.ts | 144 +++++++++++++++++ .../inlayHints/inlayHintsController.ts | 2 +- src/vs/editor/contrib/inlayHints/utils.ts | 150 ------------------ 3 files changed, 145 insertions(+), 151 deletions(-) delete mode 100644 src/vs/editor/contrib/inlayHints/utils.ts diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 42b36655db7..5fc2b1ef831 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -6,7 +6,11 @@ import * as dom from 'vs/base/browser/dom'; import { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { RunOnceScheduler } from 'vs/base/common/async'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { asCssVariableName } from 'vs/platform/theme/common/colorRegistry'; +import { ThemeColor } from 'vs/platform/theme/common/themeService'; /** * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY) @@ -215,3 +219,143 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { this._globalMouseMoveMonitor.stopMonitoring(true); } } + + +/** + * A helper to create dynamic css rules, bound to a class name. + * Rules are reused. + * Reference counting and delayed garbage collection ensure that no rules leak. +*/ +export class DynamicCssRules { + private _counter = 0; + private readonly _rules = new Map(); + + // We delay garbage collection so that hanging rules can be reused. + private readonly _garbageCollectionScheduler = new RunOnceScheduler(() => this.garbageCollect(), 1000); + + constructor(private readonly _editor: ICodeEditor) { + } + + public createClassNameRef(options: CssProperties): ClassNameReference { + const rule = this.getOrCreateRule(options); + rule.increaseRefCount(); + + return { + className: rule.className, + dispose: () => { + rule.decreaseRefCount(); + this._garbageCollectionScheduler.schedule(); + } + }; + } + + private getOrCreateRule(properties: CssProperties): RefCountedCssRule { + const key = this.computeUniqueKey(properties); + let existingRule = this._rules.get(key); + if (!existingRule) { + const counter = this._counter++; + existingRule = new RefCountedCssRule(key, `dyn-rule-${counter}`, + dom.isInShadowDOM(this._editor.getContainerDomNode()) + ? this._editor.getContainerDomNode() + : undefined, + properties + ); + this._rules.set(key, existingRule); + } + return existingRule; + } + + private computeUniqueKey(properties: CssProperties): string { + return JSON.stringify(properties); + } + + private garbageCollect() { + for (const rule of this._rules.values()) { + if (!rule.hasReferences()) { + this._rules.delete(rule.key); + rule.dispose(); + } + } + } +} + +export interface ClassNameReference extends IDisposable { + className: string; +} + +export interface CssProperties { + border?: string; + borderColor?: string | ThemeColor; + borderRadius?: string; + fontStyle?: string; + fontWeight?: string; + fontSize?: string; + fontFamily?: string; + textDecoration?: string; + color?: string | ThemeColor; + backgroundColor?: string | ThemeColor; + opacity?: string; + verticalAlign?: string; + + margin?: string; + padding?: string; + width?: string; + height?: string; +} + +class RefCountedCssRule { + private _referenceCount: number = 0; + private _styleElement: HTMLStyleElement; + + constructor( + public readonly key: string, + public readonly className: string, + _containerElement: HTMLElement | undefined, + public readonly properties: CssProperties, + ) { + this._styleElement = dom.createStyleSheet( + _containerElement + ); + + this._styleElement.textContent = this.getCssText(this.className, this.properties); + } + + private getCssText(className: string, properties: CssProperties): string { + let str = `.${className} {`; + for (const prop in properties) { + const value = (properties as any)[prop] as string | ThemeColor; + let cssValue; + if (typeof value === 'object') { + cssValue = `var(${asCssVariableName(value.id)})`; + } else { + cssValue = value; + } + + const cssPropName = camelToDashes(prop); + str += `\n\t${cssPropName}: ${cssValue};`; + } + str += `\n}`; + return str; + } + + public dispose(): void { + this._styleElement.remove(); + } + + public increaseRefCount(): void { + this._referenceCount++; + } + + public decreaseRefCount(): void { + this._referenceCount--; + } + + public hasReferences(): boolean { + return this._referenceCount > 0; + } +} + +function camelToDashes(str: string): string { + return str.replace(/(^[A-Z])/, ([first]) => first.toLowerCase()) + .replace(/([A-Z])/g, ([letter]) => `-${letter.toLowerCase()}`); +} diff --git a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts index 19b0dee4719..b21bf6a1487 100644 --- a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts @@ -12,6 +12,7 @@ import { IRange } from 'vs/base/common/range'; import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { DynamicCssRules } from 'vs/editor/browser/editorDom'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { EditorOption, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; @@ -21,7 +22,6 @@ import { IModelDeltaDecoration, InjectedTextOptions, ITextModel, IWordAtPosition import { InlayHint, InlayHintKind, InlayHintsProvider, InlayHintsProviderRegistry } from 'vs/editor/common/modes'; import { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { DynamicCssRules } from 'vs/editor/contrib/inlayHints/utils'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { editorInlayHintBackground, editorInlayHintForeground, editorInlayHintParameterBackground, editorInlayHintParameterForeground, editorInlayHintTypeBackground, editorInlayHintTypeForeground } from 'vs/platform/theme/common/colorRegistry'; import { ThemeColor, themeColorFromId } from 'vs/platform/theme/common/themeService'; diff --git a/src/vs/editor/contrib/inlayHints/utils.ts b/src/vs/editor/contrib/inlayHints/utils.ts deleted file mode 100644 index 3e6cecc8bf2..00000000000 --- a/src/vs/editor/contrib/inlayHints/utils.ts +++ /dev/null @@ -1,150 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { RunOnceScheduler } from 'vs/base/common/async'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import * as dom from 'vs/base/browser/dom'; -import { ThemeColor } from 'vs/platform/theme/common/themeService'; -import { asCssVariableName } from 'vs/platform/theme/common/colorRegistry'; - -/** - * A helper to create dynamic css rules, bound to a class name. - * Rules are reused. - * Reference counting and delayed garbage collection ensure that no rules leak. -*/ -export class DynamicCssRules { - private _counter = 0; - private readonly _rules = new Map(); - - // We delay garbage collection so that hanging rules can be reused. - private readonly _garbageCollectionScheduler = new RunOnceScheduler(() => this.garbageCollect(), 1000); - - constructor(private readonly _editor: ICodeEditor) { - } - - public createClassNameRef(options: CssProperties): ClassNameReference { - const rule = this.getOrCreateRule(options); - rule.increaseRefCount(); - - return { - className: rule.className, - dispose: () => { - rule.decreaseRefCount(); - this._garbageCollectionScheduler.schedule(); - } - }; - } - - private getOrCreateRule(properties: CssProperties): RefCountedCssRule { - const key = this.computeUniqueKey(properties); - let existingRule = this._rules.get(key); - if (!existingRule) { - const counter = this._counter++; - existingRule = new RefCountedCssRule(key, `dyn-rule-${counter}`, - dom.isInShadowDOM(this._editor.getContainerDomNode()) - ? this._editor.getContainerDomNode() - : undefined, - properties - ); - this._rules.set(key, existingRule); - } - return existingRule; - } - - private computeUniqueKey(properties: CssProperties): string { - return JSON.stringify(properties); - } - - private garbageCollect() { - for (const rule of this._rules.values()) { - if (!rule.hasReferences()) { - this._rules.delete(rule.key); - rule.dispose(); - } - } - } -} - -export interface ClassNameReference extends IDisposable { - className: string; -} - -export interface CssProperties { - border?: string; - borderColor?: string | ThemeColor; - borderRadius?: string; - fontStyle?: string; - fontWeight?: string; - fontSize?: string; - fontFamily?: string; - textDecoration?: string; - color?: string | ThemeColor; - backgroundColor?: string | ThemeColor; - opacity?: string; - verticalAlign?: string; - - margin?: string; - padding?: string; - width?: string; - height?: string; -} - -class RefCountedCssRule { - private _referenceCount: number = 0; - private _styleElement: HTMLStyleElement; - - constructor( - public readonly key: string, - public readonly className: string, - _containerElement: HTMLElement | undefined, - public readonly properties: CssProperties, - ) { - this._styleElement = dom.createStyleSheet( - _containerElement - ); - - this._styleElement.textContent = this.getCssText(this.className, this.properties); - } - - private getCssText(className: string, properties: CssProperties): string { - let str = `.${className} {`; - for (const prop in properties) { - const value = (properties as any)[prop] as string | ThemeColor; - let cssValue; - if (typeof value === 'object') { - cssValue = `var(${asCssVariableName(value.id)})`; - } else { - cssValue = value; - } - - const cssPropName = camelToDashes(prop); - str += `\n\t${cssPropName}: ${cssValue};`; - } - str += `\n}`; - return str; - } - - public dispose(): void { - this._styleElement.remove(); - } - - public increaseRefCount(): void { - this._referenceCount++; - } - - public decreaseRefCount(): void { - this._referenceCount--; - } - - public hasReferences(): boolean { - return this._referenceCount > 0; - } -} - -function camelToDashes(str: string): string { - return str.replace(/(^[A-Z])/, ([first]) => first.toLowerCase()) - .replace(/([A-Z])/g, ([letter]) => `-${letter.toLowerCase()}`); -} From 8b0ea7ddd9140e7893c7ef902f57d598771c2dda Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 8 Nov 2021 16:50:04 +0100 Subject: [PATCH 20/83] Refactors color detector to use injected text. --- .../contrib/colorPicker/colorDetector.ts | 71 ++++++++----------- .../contrib/colorPicker/colorPicker.css | 16 +++++ .../contrib/hover/colorHoverParticipant.ts | 2 +- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index f3f0ad44808..fbbc2fe0103 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -6,11 +6,11 @@ import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async'; import { RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { hash } from 'vs/base/common/hash'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { noBreakWhitespace } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { DynamicCssRules } from 'vs/editor/browser/editorDom'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -36,13 +36,14 @@ export class ColorDetector extends Disposable implements IEditorContribution { private _decorationsIds: string[] = []; private _colorDatas = new Map(); - private _colorDecoratorIds: string[] = []; - private readonly _decorationsTypes = new Set(); + private _colorDecoratorIds: ReadonlySet = new Set(); private _isEnabled: boolean; - constructor(private readonly _editor: ICodeEditor, - @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + private readonly _ruleFactory = new DynamicCssRules(this._editor); + + constructor( + private readonly _editor: ICodeEditor, @IConfigurationService private readonly _configurationService: IConfigurationService ) { super(); @@ -166,36 +167,24 @@ export class ColorDetector extends Disposable implements IEditorContribution { this._decorationsIds.forEach((id, i) => this._colorDatas.set(id, colorDatas[i])); } + private _colorDecorationClassRefs = this._register(new DisposableStore()); + private updateColorDecorators(colorData: IColorData[]): void { + this._colorDecorationClassRefs.clear(); + let decorations: IModelDeltaDecoration[] = []; - let newDecorationsTypes: { [key: string]: boolean } = {}; for (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) { const { red, green, blue, alpha } = colorData[i].colorInfo.color; const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha); - let subKey = hash(`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`).toString(16); let color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; - let key = 'colorBox-' + subKey; - if (!this._decorationsTypes.has(key) && !newDecorationsTypes[key]) { - this._codeEditorService.registerDecorationType('color-detector-color', key, { - before: { - contentText: ' ', - border: 'solid 0.1em #000', - margin: '0.1em 0.2em 0 0.2em', - width: '0.8em', - height: '0.8em', - backgroundColor: color - }, - dark: { - before: { - border: 'solid 0.1em #eee' - } - } - }, undefined, this._editor); - } + const ref = this._colorDecorationClassRefs.add( + this._ruleFactory.createClassNameRef({ + backgroundColor: color + }) + ); - newDecorationsTypes[key] = true; decorations.push({ range: { startLineNumber: colorData[i].colorInfo.range.startLineNumber, @@ -203,26 +192,24 @@ export class ColorDetector extends Disposable implements IEditorContribution { endLineNumber: colorData[i].colorInfo.range.endLineNumber, endColumn: colorData[i].colorInfo.range.endColumn }, - options: this._codeEditorService.resolveDecorationOptions(key, true) + options: { + description: 'colorDetector', + before: { + content: noBreakWhitespace, + inlineClassName: `${ref.className} colorpicker-color-decoration`, + inlineClassNameAffectsLetterSpacing: true, + } + } }); } - this._decorationsTypes.forEach(subType => { - if (!newDecorationsTypes[subType]) { - this._codeEditorService.removeDecorationType(subType); - } - }); - - this._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, decorations); + this._colorDecoratorIds = new Set(this._editor.deltaDecorations([...this._colorDecoratorIds], decorations)); } private removeAllDecorations(): void { this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, []); - this._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, []); - - this._decorationsTypes.forEach(subType => { - this._codeEditorService.removeDecorationType(subType); - }); + this._colorDecoratorIds = new Set(this._editor.deltaDecorations([...this._colorDecoratorIds], [])); + this._colorDecorationClassRefs.clear(); } getColorData(position: Position): IColorData | null { @@ -241,6 +228,10 @@ export class ColorDetector extends Disposable implements IEditorContribution { return this._colorDatas.get(decorations[0].id)!; } + + isColorDecorationId(decorationId: string): boolean { + return this._colorDecoratorIds.has(decorationId); + } } registerEditorContribution(ColorDetector.ID, ColorDetector); diff --git a/src/vs/editor/contrib/colorPicker/colorPicker.css b/src/vs/editor/contrib/colorPicker/colorPicker.css index 96056d480d1..ee6b21f0ffb 100644 --- a/src/vs/editor/contrib/colorPicker/colorPicker.css +++ b/src/vs/editor/contrib/colorPicker/colorPicker.css @@ -14,6 +14,22 @@ outline: none; } +/* Decoration */ + +.colorpicker-color-decoration { + border: solid 0.1em #000; + box-sizing: border-box; + margin: 0.1em 0.2em 0 0.2em; + width: 0.8em; + height: 0.8em; + line-height: 0.8em; + display: inline-block; +} + +.hc-black .colorpicker-color-decoration, +.vs-dark .colorpicker-color-decoration { + border: solid 0.1em #eee; +} /* Header */ diff --git a/src/vs/editor/contrib/hover/colorHoverParticipant.ts b/src/vs/editor/contrib/hover/colorHoverParticipant.ts index bcb7d04e531..4ca1edf2cb8 100644 --- a/src/vs/editor/contrib/hover/colorHoverParticipant.ts +++ b/src/vs/editor/contrib/hover/colorHoverParticipant.ts @@ -60,7 +60,7 @@ export class ColorHoverParticipant implements IEditorHoverParticipant Date: Tue, 9 Nov 2021 09:57:46 +0100 Subject: [PATCH 21/83] Move error handling code sooner in the extension host process lifecycle --- .../node/extensionHostProcessSetup.ts | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index dc5c4cf13eb..70b86fcd4d6 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -239,43 +239,6 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise[] = []; - process.on('unhandledRejection', (reason: any, promise: Promise) => { - unhandledPromises.push(promise); - setTimeout(() => { - const idx = unhandledPromises.indexOf(promise); - if (idx >= 0) { - promise.catch(e => { - unhandledPromises.splice(idx, 1); - if (!isPromiseCanceledError(e)) { - console.warn(`rejected promise not handled within 1 second: ${e}`); - if (e && e.stack) { - console.warn(`stack trace: ${e.stack}`); - } - if (reason) { - onUnexpectedError(reason); - } - } - }); - } - }, 1000); - }); - - process.on('rejectionHandled', (promise: Promise) => { - const idx = unhandledPromises.indexOf(promise); - if (idx >= 0) { - unhandledPromises.splice(idx, 1); - } - }); - - // Print a console message when an exception isn't handled. - process.on('uncaughtException', function (err: Error) { - onUnexpectedError(err); - }); - // Kill oneself if one's parent dies. Much drama. let epermErrors = 0; setInterval(function () { @@ -321,6 +284,44 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { + + // Print a console message when rejection isn't handled within N seconds. For details: + // see https://nodejs.org/api/process.html#process_event_unhandledrejection + // and https://nodejs.org/api/process.html#process_event_rejectionhandled + const unhandledPromises: Promise[] = []; + process.on('unhandledRejection', (reason: any, promise: Promise) => { + unhandledPromises.push(promise); + setTimeout(() => { + const idx = unhandledPromises.indexOf(promise); + if (idx >= 0) { + promise.catch(e => { + unhandledPromises.splice(idx, 1); + if (!isPromiseCanceledError(e)) { + console.warn(`rejected promise not handled within 1 second: ${e}`); + if (e && e.stack) { + console.warn(`stack trace: ${e.stack}`); + } + if (reason) { + onUnexpectedError(reason); + } + } + }); + } + }, 1000); + }); + + process.on('rejectionHandled', (promise: Promise) => { + const idx = unhandledPromises.indexOf(promise); + if (idx >= 0) { + unhandledPromises.splice(idx, 1); + } + }); + + // Print a console message when an exception isn't handled. + process.on('uncaughtException', function (err: Error) { + onUnexpectedError(err); + }); + performance.mark(`code/extHost/willConnectToRenderer`); const protocol = await createExtHostProtocol(); performance.mark(`code/extHost/didConnectToRenderer`); From 86dc8a88a47ac2e9a683081d69ecbf41dd144e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 09:24:54 +0100 Subject: [PATCH 22/83] refactor(table): align table colors with keybinding table --- .../contrib/preferences/browser/keybindingsEditor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 43e50f31bfb..a011b3b1200 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -29,7 +29,7 @@ import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { listHighlightForeground, badgeBackground, contrastBorder, badgeForeground, listActiveSelectionForeground, listInactiveSelectionForeground, listHoverForeground, listFocusForeground, editorBackground, foreground, listActiveSelectionBackground, listInactiveSelectionBackground, listFocusBackground, listHoverBackground, registerColor, transparent, tableOddRowsBackgroundColor } from 'vs/platform/theme/common/colorRegistry'; +import { listHighlightForeground, badgeBackground, contrastBorder, badgeForeground, listActiveSelectionForeground, listInactiveSelectionForeground, listHoverForeground, listFocusForeground, editorBackground, foreground, listActiveSelectionBackground, listInactiveSelectionBackground, listFocusBackground, listHoverBackground, registerColor, tableOddRowsBackgroundColor } from 'vs/platform/theme/common/colorRegistry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; import { WorkbenchTable } from 'vs/platform/list/browser/listService'; @@ -1165,7 +1165,7 @@ class AccessibilityProvider implements IListAccessibilityProvider { From 5e0d7da4072cb1b7fe3be450920b0ce2f7290da5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 10:07:11 +0100 Subject: [PATCH 23/83] debug error name --- .../electron-sandbox/remoteExtensionManagementService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index b09884935b7..e762b091eba 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -68,6 +68,7 @@ export class NativeRemoteExtensionManagementService extends ExtensionManagementC throw e; } default: + this.logService.debug(error.name); throw error; } } From 3ad622acbdc2e1ab05a5505b4114f3abb607c562 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 10:11:36 +0100 Subject: [PATCH 24/83] update log message --- .../electron-sandbox/remoteExtensionManagementService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index e762b091eba..08c32dc6ee5 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -68,7 +68,7 @@ export class NativeRemoteExtensionManagementService extends ExtensionManagementC throw e; } default: - this.logService.debug(error.name); + this.logService.debug('Remote Install Error Name', error.name); throw error; } } From 056fa407c67758b38b515256775dfcd4f3c504aa Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 9 Nov 2021 11:02:45 +0100 Subject: [PATCH 25/83] Await workspace trust in auto tasks Fixes #136715 --- .../workbench/contrib/tasks/browser/runAutomaticTasks.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts index 7c6c1e57d73..c50630bda75 100644 --- a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts +++ b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts @@ -35,21 +35,22 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut } private async tryRunTasks() { - this.logService.info('RunAutomaticTasks: Trying to run tasks.'); + this.logService.trace('RunAutomaticTasks: Trying to run tasks.'); // Wait until we have task system info (the extension host and workspace folders are available). if (!this.taskService.hasTaskSystemInfo) { - this.logService.info('RunAutomaticTasks: Awaiting task system info.'); + this.logService.trace('RunAutomaticTasks: Awaiting task system info.'); await Event.toPromise(Event.once(this.taskService.onDidChangeTaskSystemInfo)); } - this.logService.info('RunAutomaticTasks: Checking if automatic tasks should run.'); + this.logService.trace('RunAutomaticTasks: Checking if automatic tasks should run.'); const isFolderAutomaticAllowed = this.storageService.getBoolean(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, StorageScope.WORKSPACE, undefined); + await this.workspaceTrustManagementService.workspaceTrustInitialized; const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkspaceTrusted(); // Only run if allowed. Prompting for permission occurs when a user first tries to run a task. if (isFolderAutomaticAllowed && isWorkspaceTrusted) { this.taskService.getWorkspaceTasks(TaskRunSource.FolderOpen).then(workspaceTaskResult => { let { tasks } = RunAutomaticTasks.findAutoTasks(this.taskService, workspaceTaskResult); - this.logService.info(`RunAutomaticTasks: Found ${tasks.length} automatic tasks tasks`); + this.logService.trace(`RunAutomaticTasks: Found ${tasks.length} automatic tasks tasks`); if (tasks.length > 0) { RunAutomaticTasks.runTasks(this.taskService, tasks); From d2df861e5071ff4279e99ed1773d5e1ea829853d Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 11:29:29 +0100 Subject: [PATCH 26/83] Improves prefix sum computer docs. --- src/vs/editor/common/viewModel/prefixSumComputer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/editor/common/viewModel/prefixSumComputer.ts b/src/vs/editor/common/viewModel/prefixSumComputer.ts index eaf8faf4398..47ac2a2c65b 100644 --- a/src/vs/editor/common/viewModel/prefixSumComputer.ts +++ b/src/vs/editor/common/viewModel/prefixSumComputer.ts @@ -115,6 +115,10 @@ export class PrefixSumComputer { return this._getPrefixSum(this.values.length - 1); } + /** + * Returns the sum of the first `index + 1` many items. + * @returns `SUM(0 <= j <= index, values[j])`. + */ public getPrefixSum(index: number): number { if (index < 0) { return 0; From 80ab37febe7311f5e818b1d85bc1e13fc2f85fca Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 11:30:21 +0100 Subject: [PATCH 27/83] model line projection cleanup. --- .../common/viewModel/modelLineProjection.ts | 16 ++++++++++------ src/vs/editor/common/viewModel/viewModelLines.ts | 2 +- .../viewModel/splitLinesCollection.test.ts | 6 +++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/common/viewModel/modelLineProjection.ts b/src/vs/editor/common/viewModel/modelLineProjection.ts index ca0154bfc88..f1d7f867660 100644 --- a/src/vs/editor/common/viewModel/modelLineProjection.ts +++ b/src/vs/editor/common/viewModel/modelLineProjection.ts @@ -12,6 +12,10 @@ import { InjectedText, LineBreakData, SingleLineInlineDecoration, ViewLineData } export interface IModelLineProjection { isVisible(): boolean; + + /** + * This invalidates the current instance (potentially reuses and returns it again). + */ setVisible(isVisible: boolean): IModelLineProjection; getLineBreakData(): LineBreakData | null; @@ -21,12 +25,12 @@ export interface IModelLineProjection { getViewLineMinColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number; getViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number; getViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData; - getViewLinesData(model: ISimpleModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void; + getViewLinesData(model: ISimpleModel, modelLineNumber: number, fromOutputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void; getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number; getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number, affinity?: PositionAffinity): Position; getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number; - normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position; + normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position; getInjectedTextAt(outputLineIndex: number, column: number): InjectedText | null; } @@ -57,7 +61,7 @@ export function createModelLineProjection(lineBreakData: LineBreakData | null, i * * wrap model lines * * inject text */ -export class ModelLineProjection implements IModelLineProjection { +class ModelLineProjection implements IModelLineProjection { private readonly _lineBreakData: LineBreakData; private _isVisible: boolean; @@ -246,7 +250,7 @@ export class ModelLineProjection implements IModelLineProjection { return deltaLineNumber + r.outputLineIndex; } - public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { + public normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { const baseViewLineNumber = outputPosition.lineNumber - outputLineIndex; const normalizedOutputPosition = this._lineBreakData.normalizeOutputPosition(outputLineIndex, outputPosition.column - 1, affinity); const result = normalizedOutputPosition.toPosition(baseViewLineNumber); @@ -341,7 +345,7 @@ class IdentityModelLineProjection implements IModelLineProjection { return deltaLineNumber; } - public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { + public normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { return outputPosition; } @@ -413,7 +417,7 @@ class HiddenModelLineProjection implements IModelLineProjection { throw new Error('Not supported'); } - public normalizePosition(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { + public normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position { throw new Error('Not supported'); } diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index 26d39cca22e..3347cd86d45 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -931,7 +931,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { normalizePosition(position: Position, affinity: PositionAffinity): Position { const info = this.getViewLineInfo(position.lineNumber); - return this.modelLineProjections[info.modelLineNumber - 1].normalizePosition(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx, position, affinity); + return this.modelLineProjections[info.modelLineNumber - 1].normalizePosition(info.modelLineWrappedLineIdx, position, affinity); } public getLineIndentColumn(lineNumber: number): number { diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index 0b9ea83cdcc..cb941405805 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -19,7 +19,7 @@ import { LineBreakData, ViewLineData } from 'vs/editor/common/viewModel/viewMode import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createTextModel } from 'vs/editor/test/common/editorTestUtils'; -import { ISimpleModel, ModelLineProjection } from 'vs/editor/common/viewModel/modelLineProjection'; +import { ISimpleModel, IModelLineProjection, createModelLineProjection } from 'vs/editor/common/viewModel/modelLineProjection'; suite('Editor ViewModel - SplitLinesCollection', () => { test('SplitLine', () => { @@ -947,8 +947,8 @@ function pos(lineNumber: number, column: number): Position { return new Position(lineNumber, column); } -function createSplitLine(splitLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number, isVisible: boolean = true): ModelLineProjection { - return new ModelLineProjection(createLineBreakData(splitLengths, breakingOffsetsVisibleColumn, wrappedTextIndentWidth), isVisible); +function createSplitLine(splitLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number, isVisible: boolean = true): IModelLineProjection { + return createModelLineProjection(createLineBreakData(splitLengths, breakingOffsetsVisibleColumn, wrappedTextIndentWidth), isVisible); } function createLineBreakData(breakingLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number): LineBreakData { From 0b5e7026d2fd18980420b74dfbe31d4b43193b07 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 11:35:21 +0100 Subject: [PATCH 28/83] Renames LineBreakData to ModelLineProjectionData --- .../browser/view/domLineBreaksComputer.ts | 16 +++++++-------- .../common/viewModel/modelLineProjection.ts | 16 +++++++-------- .../viewModel/monospaceLineBreaksComputer.ts | 18 ++++++++--------- src/vs/editor/common/viewModel/viewModel.ts | 6 +++--- .../editor/common/viewModel/viewModelLines.ts | 20 +++++++++---------- .../common/viewModel/lineBreakData.test.ts | 16 +++++++-------- .../monospaceLineBreaksComputer.test.ts | 12 +++++------ .../viewModel/splitLinesCollection.test.ts | 6 +++--- 8 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/vs/editor/browser/view/domLineBreaksComputer.ts b/src/vs/editor/browser/view/domLineBreaksComputer.ts index 40fba14c8f0..3e1c460a4b6 100644 --- a/src/vs/editor/browser/view/domLineBreaksComputer.ts +++ b/src/vs/editor/browser/view/domLineBreaksComputer.ts @@ -9,7 +9,7 @@ import { createStringBuilder, IStringBuilder } from 'vs/editor/common/core/strin import { CharCode } from 'vs/base/common/charCode'; import * as strings from 'vs/base/common/strings'; import { Configuration } from 'vs/editor/browser/config/configuration'; -import { ILineBreaksComputer, ILineBreaksComputerFactory, LineBreakData } from 'vs/editor/common/viewModel/viewModel'; +import { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import { InjectedTextOptions } from 'vs/editor/common/model'; @@ -31,7 +31,7 @@ export class DOMLineBreaksComputerFactory implements ILineBreaksComputerFactory let requests: string[] = []; let injectedTexts: (LineInjectedText[] | null)[] = []; return { - addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: LineBreakData | null) => { + addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => { requests.push(lineText); injectedTexts.push(injectedText); }, @@ -42,8 +42,8 @@ export class DOMLineBreaksComputerFactory implements ILineBreaksComputerFactory } } -function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: number, firstLineBreakColumn: number, wrappingIndent: WrappingIndent, injectedTextsPerLine: (LineInjectedText[] | null)[]): (LineBreakData | null)[] { - function createEmptyLineBreakWithPossiblyInjectedText(requestIdx: number): LineBreakData | null { +function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: number, firstLineBreakColumn: number, wrappingIndent: WrappingIndent, injectedTextsPerLine: (LineInjectedText[] | null)[]): (ModelLineProjectionData | null)[] { + function createEmptyLineBreakWithPossiblyInjectedText(requestIdx: number): ModelLineProjectionData | null { const injectedTexts = injectedTextsPerLine[requestIdx]; if (injectedTexts) { const lineText = LineInjectedText.applyInjectedText(requests[requestIdx], injectedTexts); @@ -53,14 +53,14 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe // creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK // because `breakOffsetsVisibleColumn` will never be used because it contains injected text - return new LineBreakData(injectionOffsets, injectionOptions, [lineText.length], [], 0); + return new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0); } else { return null; } } if (firstLineBreakColumn === -1) { - const result: (LineBreakData | null)[] = []; + const result: (ModelLineProjectionData | null)[] = []; for (let i = 0, len = requests.length; i < len; i++) { result[i] = createEmptyLineBreakWithPossiblyInjectedText(i); } @@ -138,7 +138,7 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe let range = document.createRange(); const lineDomNodes = Array.prototype.slice.call(containerDomNode.children, 0); - let result: (LineBreakData | null)[] = []; + let result: (ModelLineProjectionData | null)[] = []; for (let i = 0; i < requests.length; i++) { const lineDomNode = lineDomNodes[i]; const breakOffsets: number[] | null = readLineBreaks(range, lineDomNode, renderLineContents[i], allCharOffsets[i]); @@ -174,7 +174,7 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe injectionOffsets = null; } - result[i] = new LineBreakData(injectionOffsets, injectionOptions, breakOffsets, breakOffsetsVisibleColumn, wrappedTextIndentLength); + result[i] = new ModelLineProjectionData(injectionOffsets, injectionOptions, breakOffsets, breakOffsetsVisibleColumn, wrappedTextIndentLength); } document.body.removeChild(containerDomNode); diff --git a/src/vs/editor/common/viewModel/modelLineProjection.ts b/src/vs/editor/common/viewModel/modelLineProjection.ts index f1d7f867660..5a1398b762c 100644 --- a/src/vs/editor/common/viewModel/modelLineProjection.ts +++ b/src/vs/editor/common/viewModel/modelLineProjection.ts @@ -8,7 +8,7 @@ import { Position } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; import { EndOfLinePreference, ITextModel, PositionAffinity } from 'vs/editor/common/model'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; -import { InjectedText, LineBreakData, SingleLineInlineDecoration, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { InjectedText, ModelLineProjectionData, SingleLineInlineDecoration, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; export interface IModelLineProjection { isVisible(): boolean; @@ -18,7 +18,7 @@ export interface IModelLineProjection { */ setVisible(isVisible: boolean): IModelLineProjection; - getLineBreakData(): LineBreakData | null; + getLineBreakData(): ModelLineProjectionData | null; getViewLineCount(): number; getViewLineContent(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): string; getViewLineLength(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number; @@ -44,7 +44,7 @@ export interface ISimpleModel { getValueInRange(range: IRange, eol?: EndOfLinePreference): string; } -export function createModelLineProjection(lineBreakData: LineBreakData | null, isVisible: boolean): IModelLineProjection { +export function createModelLineProjection(lineBreakData: ModelLineProjectionData | null, isVisible: boolean): IModelLineProjection { if (lineBreakData === null) { // No mapping needed if (isVisible) { @@ -62,10 +62,10 @@ export function createModelLineProjection(lineBreakData: LineBreakData | null, i * * inject text */ class ModelLineProjection implements IModelLineProjection { - private readonly _lineBreakData: LineBreakData; + private readonly _lineBreakData: ModelLineProjectionData; private _isVisible: boolean; - constructor(lineBreakData: LineBreakData, isVisible: boolean) { + constructor(lineBreakData: ModelLineProjectionData, isVisible: boolean) { this._lineBreakData = lineBreakData; this._isVisible = isVisible; } @@ -79,7 +79,7 @@ class ModelLineProjection implements IModelLineProjection { return this; } - public getLineBreakData(): LineBreakData | null { + public getLineBreakData(): ModelLineProjectionData | null { return this._lineBreakData; } @@ -287,7 +287,7 @@ class IdentityModelLineProjection implements IModelLineProjection { return HiddenModelLineProjection.INSTANCE; } - public getLineBreakData(): LineBreakData | null { + public getLineBreakData(): ModelLineProjectionData | null { return null; } @@ -373,7 +373,7 @@ class HiddenModelLineProjection implements IModelLineProjection { return IdentityModelLineProjection.INSTANCE; } - public getLineBreakData(): LineBreakData | null { + public getLineBreakData(): ModelLineProjectionData | null { return null; } diff --git a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts index ffc5502936b..057d25bb6c2 100644 --- a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts +++ b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts @@ -8,7 +8,7 @@ import * as strings from 'vs/base/common/strings'; import { WrappingIndent, IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { ILineBreaksComputer, ILineBreaksComputerFactory, LineBreakData } from 'vs/editor/common/viewModel/viewModel'; +import { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import { InjectedTextOptions } from 'vs/editor/common/model'; @@ -78,16 +78,16 @@ export class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFa const requests: string[] = []; const injectedTexts: (LineInjectedText[] | null)[] = []; - const previousBreakingData: (LineBreakData | null)[] = []; + const previousBreakingData: (ModelLineProjectionData | null)[] = []; return { - addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: LineBreakData | null) => { + addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => { requests.push(lineText); injectedTexts.push(injectedText); previousBreakingData.push(previousLineBreakData); }, finalize: () => { const columnsForFullWidthChar = fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth; //@perf - let result: (LineBreakData | null)[] = []; + let result: (ModelLineProjectionData | null)[] = []; for (let i = 0, len = requests.length; i < len; i++) { const injectedText = injectedTexts[i]; const previousLineBreakData = previousBreakingData[i]; @@ -105,7 +105,7 @@ export class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFa } } -function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: LineBreakData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): LineBreakData | null { +function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: ModelLineProjectionData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): ModelLineProjectionData | null { if (firstLineBreakColumn === -1) { return null; } @@ -357,7 +357,7 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla return previousBreakingData; } -function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: string, injectedTexts: LineInjectedText[] | null, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): LineBreakData | null { +function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: string, injectedTexts: LineInjectedText[] | null, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): ModelLineProjectionData | null { const lineText = LineInjectedText.applyInjectedText(_lineText, injectedTexts); let injectionOptions: InjectedTextOptions[] | null; @@ -376,7 +376,7 @@ function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: st } // creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK // because `breakOffsetsVisibleColumn` will never be used because it contains injected text - return new LineBreakData(injectionOffsets, injectionOptions, [lineText.length], [], 0); + return new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0); } const len = lineText.length; @@ -386,7 +386,7 @@ function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: st } // creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK // because `breakOffsetsVisibleColumn` will never be used because it contains injected text - return new LineBreakData(injectionOffsets, injectionOptions, [lineText.length], [], 0); + return new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0); } const wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent); @@ -464,7 +464,7 @@ function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: st breakingOffsets[breakingOffsetsCount] = len; breakingOffsetsVisibleColumn[breakingOffsetsCount] = visibleColumn; - return new LineBreakData(injectionOffsets, injectionOptions, breakingOffsets, breakingOffsetsVisibleColumn, wrappedTextIndentLength); + return new ModelLineProjectionData(injectionOffsets, injectionOptions, breakingOffsets, breakingOffsetsVisibleColumn, wrappedTextIndentLength); } function computeCharWidth(charCode: number, visibleColumn: number, tabSize: number, columnsForFullWidthChar: number): number { diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 313e48af997..b705c57538f 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -137,7 +137,7 @@ export class OutputPosition { * xxxxxx[ii]xxxx * ``` */ -export class LineBreakData { +export class ModelLineProjectionData { constructor( public injectionOffsets: number[] | null, /** @@ -391,8 +391,8 @@ export interface ILineBreaksComputer { /** * Pass in `previousLineBreakData` if the only difference is in breaking columns!!! */ - addRequest(lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: LineBreakData | null): void; - finalize(): (LineBreakData | null)[]; + addRequest(lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null): void; + finalize(): (ModelLineProjectionData | null)[]; } export interface IViewModel extends ICursorSimpleModel { diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index 3347cd86d45..d51f3d3aa53 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -15,7 +15,7 @@ import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { createModelLineProjection, IModelLineProjection } from 'vs/editor/common/viewModel/modelLineProjection'; import { ConstantTimePrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { ICoordinatesConverter, ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText, LineBreakData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { ICoordinatesConverter, ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText, ModelLineProjectionData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; export interface IViewModelLines extends IDisposable { createCoordinatesConverter(): ICoordinatesConverter; @@ -28,8 +28,8 @@ export interface IViewModelLines extends IDisposable { createLineBreaksComputer(): ILineBreaksComputer; onModelFlushed(): void; onModelLinesDeleted(versionId: number | null, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null; - onModelLinesInserted(versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null; - onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null]; + onModelLinesInserted(versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null; + onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null]; acceptVersionId(versionId: number): void; getViewLineCount(): number; @@ -111,7 +111,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return new CoordinatesConverter(this); } - private _constructLines(resetHiddenAreas: boolean, previousLineBreaks: ((LineBreakData | null)[]) | null): void { + private _constructLines(resetHiddenAreas: boolean, previousLineBreaks: ((ModelLineProjectionData | null)[]) | null): void { this.modelLineProjections = []; if (resetHiddenAreas) { @@ -308,7 +308,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { this.wrappingColumn = wrappingColumn; this.wrappingIndent = wrappingIndent; - let previousLineBreaks: ((LineBreakData | null)[]) | null = null; + let previousLineBreaks: ((ModelLineProjectionData | null)[]) | null = null; if (onlyWrappingColumnChanged) { previousLineBreaks = []; for (let i = 0, len = this.modelLineProjections.length; i < len; i++) { @@ -350,7 +350,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return new viewEvents.ViewLinesDeletedEvent(outputFromLineNumber, outputToLineNumber); } - public onModelLinesInserted(versionId: number | null, fromLineNumber: number, _toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null { + public onModelLinesInserted(versionId: number | null, fromLineNumber: number, _toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null { if (!versionId || versionId <= this._validModelVersionId) { // Here we check for versionId in case the lines were reconstructed in the meantime. // We don't want to apply stale change events on top of a newer read model state. @@ -386,7 +386,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return new viewEvents.ViewLinesInsertedEvent(outputFromLineNumber, outputFromLineNumber + totalOutputLineCount - 1); } - public onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] { + public onModelLineChanged(versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] { if (versionId !== null && versionId <= this._validModelVersionId) { // Here we check for versionId in case the lines were reconstructed in the meantime. // We don't want to apply stale change events on top of a newer read model state. @@ -1056,7 +1056,7 @@ export class ViewModelLinesFromModelAsIs implements IViewModelLines { public createLineBreaksComputer(): ILineBreaksComputer { let result: null[] = []; return { - addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: LineBreakData | null) => { + addRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => { result.push(null); }, finalize: () => { @@ -1072,11 +1072,11 @@ export class ViewModelLinesFromModelAsIs implements IViewModelLines { return new viewEvents.ViewLinesDeletedEvent(fromLineNumber, toLineNumber); } - public onModelLinesInserted(_versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null { + public onModelLinesInserted(_versionId: number | null, fromLineNumber: number, toLineNumber: number, lineBreaks: (ModelLineProjectionData | null)[]): viewEvents.ViewLinesInsertedEvent | null { return new viewEvents.ViewLinesInsertedEvent(fromLineNumber, toLineNumber); } - public onModelLineChanged(_versionId: number | null, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] { + public onModelLineChanged(_versionId: number | null, lineNumber: number, lineBreakData: ModelLineProjectionData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] { return [false, new viewEvents.ViewLinesChangedEvent(lineNumber, lineNumber), null, null]; } diff --git a/src/vs/editor/test/common/viewModel/lineBreakData.test.ts b/src/vs/editor/test/common/viewModel/lineBreakData.test.ts index 0372cc1ad6c..20705b9396c 100644 --- a/src/vs/editor/test/common/viewModel/lineBreakData.test.ts +++ b/src/vs/editor/test/common/viewModel/lineBreakData.test.ts @@ -6,11 +6,11 @@ import assert = require('assert'); import { PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationInjectedTextOptions } from 'vs/editor/common/model/textModel'; -import { LineBreakData } from 'vs/editor/common/viewModel/viewModel'; +import { ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; suite('Editor ViewModel - LineBreakData', () => { test('Basic', () => { - const data = new LineBreakData([], [], [100], [0], 10); + const data = new ModelLineProjectionData([], [], [100], [0], 10); assert.strictEqual(data.translateToInputOffset(0, 50), 50); assert.strictEqual(data.translateToInputOffset(1, 60), 150); @@ -24,18 +24,18 @@ suite('Editor ViewModel - LineBreakData', () => { return result; } - function testInverse(data: LineBreakData) { + function testInverse(data: ModelLineProjectionData) { for (let i = 0; i < 100; i++) { const output = data.translateToOutputPosition(i); assert.deepStrictEqual(data.translateToInputOffset(output.outputLineIndex, output.outputOffset), i); } } - function getInputOffsets(data: LineBreakData, outputLineIdx: number): number[] { + function getInputOffsets(data: ModelLineProjectionData, outputLineIdx: number): number[] { return sequence(20).map(i => data.translateToInputOffset(outputLineIdx, i)); } - function getOutputOffsets(data: LineBreakData, affinity: PositionAffinity): string[] { + function getOutputOffsets(data: ModelLineProjectionData, affinity: PositionAffinity): string[] { return sequence(25).map(i => data.translateToOutputPosition(i, affinity).toString()); } @@ -44,7 +44,7 @@ suite('Editor ViewModel - LineBreakData', () => { } suite('Injected Text 1', () => { - const data = new LineBreakData([2, 3, 10], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 10); + const data = new ModelLineProjectionData([2, 3, 10], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 10); test('getInputOffsetOfOutputPosition', () => { // For every view model position, what is the model position? @@ -183,7 +183,7 @@ suite('Editor ViewModel - LineBreakData', () => { }); suite('Injected Text 2', () => { - const data = new LineBreakData([2, 2, 6], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 0); + const data = new ModelLineProjectionData([2, 2, 6], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 0); test('getInputOffsetOfOutputPosition', () => { assert.deepStrictEqual( @@ -205,7 +205,7 @@ suite('Editor ViewModel - LineBreakData', () => { }); suite('Injected Text 3', () => { - const data = new LineBreakData([2, 2, 7], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 0); + const data = new ModelLineProjectionData([2, 2, 7], mapTextToInjectedTextOptions(['1', '22', '333']), [10, 100], [], 0); test('getInputOffsetOfOutputPosition', () => { assert.deepStrictEqual( diff --git a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts index 5f28ef78c47..dd7f378e6a0 100644 --- a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts +++ b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { WrappingIndent, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { ILineBreaksComputerFactory, LineBreakData } from 'vs/editor/common/viewModel/viewModel'; +import { ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; function parseAnnotatedText(annotatedText: string): { text: string; indices: number[]; } { let text = ''; @@ -23,7 +23,7 @@ function parseAnnotatedText(annotatedText: string): { text: string; indices: num return { text: text, indices: indices }; } -function toAnnotatedText(text: string, lineBreakData: LineBreakData | null): string { +function toAnnotatedText(text: string, lineBreakData: ModelLineProjectionData | null): string { // Insert line break markers again, according to algorithm let actualAnnotatedText = ''; if (lineBreakData) { @@ -43,7 +43,7 @@ function toAnnotatedText(text: string, lineBreakData: LineBreakData | null): str return actualAnnotatedText; } -function getLineBreakData(factory: ILineBreaksComputerFactory, tabSize: number, breakAfter: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, text: string, previousLineBreakData: LineBreakData | null): LineBreakData | null { +function getLineBreakData(factory: ILineBreaksComputerFactory, tabSize: number, breakAfter: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, text: string, previousLineBreakData: ModelLineProjectionData | null): ModelLineProjectionData | null { const fontInfo = new FontInfo({ zoomLevel: 0, pixelRatio: 1, @@ -63,12 +63,12 @@ function getLineBreakData(factory: ILineBreaksComputerFactory, tabSize: number, maxDigitWidth: 7 }, false); const lineBreaksComputer = factory.createLineBreaksComputer(fontInfo, tabSize, breakAfter, wrappingIndent); - const previousLineBreakDataClone = previousLineBreakData ? new LineBreakData(null, null, previousLineBreakData.breakOffsets.slice(0), previousLineBreakData.breakOffsetsVisibleColumn.slice(0), previousLineBreakData.wrappedTextIndentLength) : null; + const previousLineBreakDataClone = previousLineBreakData ? new ModelLineProjectionData(null, null, previousLineBreakData.breakOffsets.slice(0), previousLineBreakData.breakOffsetsVisibleColumn.slice(0), previousLineBreakData.wrappedTextIndentLength) : null; lineBreaksComputer.addRequest(text, null, previousLineBreakDataClone); return lineBreaksComputer.finalize()[0]; } -function assertLineBreaks(factory: ILineBreaksComputerFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None): LineBreakData | null { +function assertLineBreaks(factory: ILineBreaksComputerFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None): ModelLineProjectionData | null { // Create version of `annotatedText` with line break markers removed const text = parseAnnotatedText(annotatedText).text; const lineBreakData = getLineBreakData(factory, tabSize, breakAfter, 2, wrappingIndent, text, null); @@ -122,7 +122,7 @@ suite('Editor ViewModel - MonospaceLineBreaksComputer', () => { assertLineBreaks(factory, 4, 5, 'aa.(.|).aaa'); }); - function assertLineBreakDataEqual(a: LineBreakData | null, b: LineBreakData | null): void { + function assertLineBreakDataEqual(a: ModelLineProjectionData | null, b: ModelLineProjectionData | null): void { if (!a || !b) { assert.deepStrictEqual(a, b); return; diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index cb941405805..dac9403c5ce 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -15,7 +15,7 @@ import * as modes from 'vs/editor/common/modes'; import { NULL_STATE } from 'vs/editor/common/modes/nullMode'; import { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer'; import { ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines'; -import { LineBreakData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { ModelLineProjectionData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createTextModel } from 'vs/editor/test/common/editorTestUtils'; @@ -951,12 +951,12 @@ function createSplitLine(splitLengths: number[], breakingOffsetsVisibleColumn: n return createModelLineProjection(createLineBreakData(splitLengths, breakingOffsetsVisibleColumn, wrappedTextIndentWidth), isVisible); } -function createLineBreakData(breakingLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number): LineBreakData { +function createLineBreakData(breakingLengths: number[], breakingOffsetsVisibleColumn: number[], wrappedTextIndentWidth: number): ModelLineProjectionData { let sums: number[] = []; for (let i = 0; i < breakingLengths.length; i++) { sums[i] = (i > 0 ? sums[i - 1] : 0) + breakingLengths[i]; } - return new LineBreakData(null, null, sums, breakingOffsetsVisibleColumn, wrappedTextIndentWidth); + return new ModelLineProjectionData(null, null, sums, breakingOffsetsVisibleColumn, wrappedTextIndentWidth); } function createModel(text: string): ISimpleModel { From c833f69a9b4e11c918dc1d80d3191932ddb1d03e Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 11:41:33 +0100 Subject: [PATCH 29/83] Moves modelLineProjectionData into its own file. --- .../editor/browser/controller/mouseTarget.ts | 3 +- .../browser/view/domLineBreaksComputer.ts | 2 +- .../editor/browser/widget/diffEditorWidget.ts | 3 +- .../common/viewModel/modelLineProjection.ts | 3 +- .../viewModel/modelLineProjectionData.ts | 316 +++++++++++++++++ .../viewModel/monospaceLineBreaksComputer.ts | 2 +- src/vs/editor/common/viewModel/viewModel.ts | 319 +----------------- .../editor/common/viewModel/viewModelImpl.ts | 3 +- .../editor/common/viewModel/viewModelLines.ts | 3 +- .../common/viewModel/lineBreakData.test.ts | 2 +- .../monospaceLineBreaksComputer.test.ts | 2 +- .../viewModel/splitLinesCollection.test.ts | 3 +- 12 files changed, 338 insertions(+), 323 deletions(-) create mode 100644 src/vs/editor/common/viewModel/modelLineProjectionData.ts diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index be1f71119d3..e6dc5ca034a 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -14,11 +14,12 @@ import { Position } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; import { HorizontalPosition } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; -import { InjectedText, IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; import * as dom from 'vs/base/browser/dom'; import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations'; import { PositionAffinity } from 'vs/editor/common/model'; +import { InjectedText } from 'vs/editor/common/viewModel/modelLineProjectionData'; export interface IViewZoneData { viewZoneId: string; diff --git a/src/vs/editor/browser/view/domLineBreaksComputer.ts b/src/vs/editor/browser/view/domLineBreaksComputer.ts index 3e1c460a4b6..68b9aab8b09 100644 --- a/src/vs/editor/browser/view/domLineBreaksComputer.ts +++ b/src/vs/editor/browser/view/domLineBreaksComputer.ts @@ -9,9 +9,9 @@ import { createStringBuilder, IStringBuilder } from 'vs/editor/common/core/strin import { CharCode } from 'vs/base/common/charCode'; import * as strings from 'vs/base/common/strings'; import { Configuration } from 'vs/editor/browser/config/configuration'; -import { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import { InjectedTextOptions } from 'vs/editor/common/model'; +import { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; const ttPolicy = window.trustedTypes?.createPolicy('domLineBreaksComputer', { createHTML: value => value }); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 666b4beb2f1..61c4755ee6a 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -32,7 +32,7 @@ import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; -import { ILineBreaksComputer, InlineDecoration, InlineDecorationType, IViewModel, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; +import { InlineDecoration, InlineDecorationType, IViewModel, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -52,6 +52,7 @@ import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor import { IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { ILineBreaksComputer } from 'vs/editor/common/viewModel/modelLineProjectionData'; export interface IDiffCodeEditorWidgetOptions { originalEditor?: ICodeEditorWidgetOptions; diff --git a/src/vs/editor/common/viewModel/modelLineProjection.ts b/src/vs/editor/common/viewModel/modelLineProjection.ts index 5a1398b762c..390fb638bbb 100644 --- a/src/vs/editor/common/viewModel/modelLineProjection.ts +++ b/src/vs/editor/common/viewModel/modelLineProjection.ts @@ -8,7 +8,8 @@ import { Position } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; import { EndOfLinePreference, ITextModel, PositionAffinity } from 'vs/editor/common/model'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; -import { InjectedText, ModelLineProjectionData, SingleLineInlineDecoration, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { InjectedText, ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; +import { SingleLineInlineDecoration, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; export interface IModelLineProjection { isVisible(): boolean; diff --git a/src/vs/editor/common/viewModel/modelLineProjectionData.ts b/src/vs/editor/common/viewModel/modelLineProjectionData.ts new file mode 100644 index 00000000000..a786ebfbff0 --- /dev/null +++ b/src/vs/editor/common/viewModel/modelLineProjectionData.ts @@ -0,0 +1,316 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + + +import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; +import { FontInfo } from 'vs/editor/common/config/fontInfo'; +import { Position } from 'vs/editor/common/core/position'; +import { InjectedTextOptions, PositionAffinity } from 'vs/editor/common/model'; +import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; + +/** + * *input*: + * ``` + * xxxxxxxxxxxxxxxxxxxxxxxxxxx + * ``` + * + * -> Applying injections `[i...i]`, *inputWithInjections*: + * ``` + * xxxxxx[iiiiiiiiii]xxxxxxxxxxxxxxxxx[ii]xxxx + * ``` + * + * -> breaking at offsets `|` in `xxxxxx[iiiiiii|iii]xxxxxxxxxxx|xxxxxx[ii]xxxx|`: + * ``` + * xxxxxx[iiiiiii + * iii]xxxxxxxxxxx + * xxxxxx[ii]xxxx + * ``` + * + * -> applying wrappedTextIndentLength, *output*: + * ``` + * xxxxxx[iiiiiii + * iii]xxxxxxxxxxx + * xxxxxx[ii]xxxx + * ``` + */ +export class ModelLineProjectionData { + constructor( + public injectionOffsets: number[] | null, + /** + * `injectionOptions.length` must equal `injectionOffsets.length` + */ + public injectionOptions: InjectedTextOptions[] | null, + /** + * Refers to offsets after applying injections to the source. + * The last break offset indicates the length of the source after applying injections. + */ + public breakOffsets: number[], + /** + * Refers to offsets after applying injections + */ + public breakOffsetsVisibleColumn: number[], + public wrappedTextIndentLength: number + ) { + } + + public getOutputLineCount(): number { + return this.breakOffsets.length; + } + + public getMinOutputOffset(outputLineIndex: number): number { + if (outputLineIndex > 0) { + return this.wrappedTextIndentLength; + } + return 0; + } + + public getLineLength(outputLineIndex: number): number { + // These offsets refer to model text with injected text. + const startOffset = outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0; + const endOffset = this.breakOffsets[outputLineIndex]; + + let lineLength = endOffset - startOffset; + if (outputLineIndex > 0) { + lineLength += this.wrappedTextIndentLength; + } + return lineLength; + } + + public getMaxOutputOffset(outputLineIndex: number): number { + return this.getLineLength(outputLineIndex); + } + + public translateToInputOffset(outputLineIndex: number, outputOffset: number): number { + if (outputLineIndex > 0) { + outputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength); + } + + const offsetInInputWithInjection = outputLineIndex === 0 ? outputOffset : this.breakOffsets[outputLineIndex - 1] + outputOffset; + let offsetInInput = offsetInInputWithInjection; + + if (this.injectionOffsets !== null) { + for (let i = 0; i < this.injectionOffsets.length; i++) { + if (offsetInInput > this.injectionOffsets[i]) { + if (offsetInInput < this.injectionOffsets[i] + this.injectionOptions![i].content.length) { + // `inputOffset` is within injected text + offsetInInput = this.injectionOffsets[i]; + } else { + offsetInInput -= this.injectionOptions![i].content.length; + } + } else { + break; + } + } + } + + return offsetInInput; + } + + public translateToOutputPosition(inputOffset: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition { + let inputOffsetInInputWithInjection = inputOffset; + if (this.injectionOffsets !== null) { + for (let i = 0; i < this.injectionOffsets.length; i++) { + if (inputOffset < this.injectionOffsets[i]) { + break; + } + + if (affinity !== PositionAffinity.Right && inputOffset === this.injectionOffsets[i]) { + break; + } + + inputOffsetInInputWithInjection += this.injectionOptions![i].content.length; + } + } + + return this.offsetInInputWithInjectionsToOutputPosition(inputOffsetInInputWithInjection, affinity); + } + + private offsetInInputWithInjectionsToOutputPosition(offsetInInputWithInjections: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition { + let low = 0; + let high = this.breakOffsets.length - 1; + let mid = 0; + let midStart = 0; + + while (low <= high) { + mid = low + ((high - low) / 2) | 0; + + const midStop = this.breakOffsets[mid]; + midStart = mid > 0 ? this.breakOffsets[mid - 1] : 0; + + if (affinity === PositionAffinity.Left) { + if (offsetInInputWithInjections <= midStart) { + high = mid - 1; + } else if (offsetInInputWithInjections > midStop) { + low = mid + 1; + } else { + break; + } + } else { + if (offsetInInputWithInjections < midStart) { + high = mid - 1; + } else if (offsetInInputWithInjections >= midStop) { + low = mid + 1; + } else { + break; + } + } + } + + let outputOffset = offsetInInputWithInjections - midStart; + if (mid > 0) { + outputOffset += this.wrappedTextIndentLength; + } + + return new OutputPosition(mid, outputOffset); + } + + public normalizeOutputPosition(outputLineIndex: number, outputOffset: number, affinity: PositionAffinity): OutputPosition { + if (this.injectionOffsets !== null) { + const offsetInInputWithInjections = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset); + const normalizedOffsetInUnwrappedLine = this.normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections, affinity); + if (normalizedOffsetInUnwrappedLine !== offsetInInputWithInjections) { + // injected text caused a change + return this.offsetInInputWithInjectionsToOutputPosition(normalizedOffsetInUnwrappedLine, affinity); + } + } + + if (affinity === PositionAffinity.Left) { + if (outputLineIndex > 0 && outputOffset === this.getMinOutputOffset(outputLineIndex)) { + return new OutputPosition(outputLineIndex - 1, this.getMaxOutputOffset(outputLineIndex - 1)); + } + } + else if (affinity === PositionAffinity.Right) { + const maxOutputLineIndex = this.getOutputLineCount() - 1; + if (outputLineIndex < maxOutputLineIndex && outputOffset === this.getMaxOutputOffset(outputLineIndex)) { + return new OutputPosition(outputLineIndex + 1, this.getMinOutputOffset(outputLineIndex + 1)); + } + } + + return new OutputPosition(outputLineIndex, outputOffset); + } + + private outputPositionToOffsetInInputWithInjections(outputLineIndex: number, outputOffset: number): number { + if (outputLineIndex > 0) { + outputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength); + } + const result = (outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0) + outputOffset; + return result; + } + + private normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections: number, affinity: PositionAffinity): number { + const injectedText = this.getInjectedTextAtOffset(offsetInInputWithInjections); + if (!injectedText) { + return offsetInInputWithInjections; + } + + if (affinity === PositionAffinity.None) { + if (offsetInInputWithInjections === injectedText.offsetInInputWithInjections + injectedText.length) { + // go to the end of this injected text + return injectedText.offsetInInputWithInjections + injectedText.length; + } else { + // go to the start of this injected text + return injectedText.offsetInInputWithInjections; + } + } + + if (affinity === PositionAffinity.Right) { + let result = injectedText.offsetInInputWithInjections + injectedText.length; + let index = injectedText.injectedTextIndex; + // traverse all injected text that touch each other + while (index + 1 < this.injectionOffsets!.length && this.injectionOffsets![index + 1] === this.injectionOffsets![index]) { + result += this.injectionOptions![index + 1].content.length; + index++; + } + return result; + } + + // affinity is left + let result = injectedText.offsetInInputWithInjections; + let index = injectedText.injectedTextIndex; + // traverse all injected text that touch each other + while (index - 1 >= 0 && this.injectionOffsets![index - 1] === this.injectionOffsets![index]) { + result -= this.injectionOptions![index - 1].content.length; + index++; + } + return result; + } + + public getInjectedText(outputLineIndex: number, outputOffset: number): InjectedText | null { + const offset = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset); + const injectedText = this.getInjectedTextAtOffset(offset); + if (!injectedText) { + return null; + } + return { + options: this.injectionOptions![injectedText.injectedTextIndex] + }; + } + + private getInjectedTextAtOffset(offsetInInputWithInjections: number): { injectedTextIndex: number, offsetInInputWithInjections: number, length: number } | undefined { + const injectionOffsets = this.injectionOffsets; + const injectionOptions = this.injectionOptions; + + if (injectionOffsets !== null) { + let totalInjectedTextLengthBefore = 0; + for (let i = 0; i < injectionOffsets.length; i++) { + const length = injectionOptions![i].content.length; + const injectedTextStartOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore; + const injectedTextEndOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore + length; + + if (injectedTextStartOffsetInInputWithInjections > offsetInInputWithInjections) { + // Injected text starts later. + break; // All later injected texts have an even larger offset. + } + + if (offsetInInputWithInjections <= injectedTextEndOffsetInInputWithInjections) { + // Injected text ends after or with the given position (but also starts with or before it). + return { + injectedTextIndex: i, + offsetInInputWithInjections: injectedTextStartOffsetInInputWithInjections, + length + }; + } + + totalInjectedTextLengthBefore += length; + } + } + + return undefined; + } +} + +export class InjectedText { + constructor(public readonly options: InjectedTextOptions) { } +} + +export class OutputPosition { + outputLineIndex: number; + outputOffset: number; + + constructor(outputLineIndex: number, outputOffset: number) { + this.outputLineIndex = outputLineIndex; + this.outputOffset = outputOffset; + } + + toString(): string { + return `${this.outputLineIndex}:${this.outputOffset}`; + } + + toPosition(baseLineNumber: number): Position { + return new Position(baseLineNumber + this.outputLineIndex, this.outputOffset + 1); + } +} + +export interface ILineBreaksComputerFactory { + createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer; +} + +export interface ILineBreaksComputer { + /** + * Pass in `previousLineBreakData` if the only difference is in breaking columns!!! + */ + addRequest(lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null): void; + finalize(): (ModelLineProjectionData | null)[]; +} diff --git a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts index 057d25bb6c2..dd6d1437b0c 100644 --- a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts +++ b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts @@ -8,9 +8,9 @@ import * as strings from 'vs/base/common/strings'; import { WrappingIndent, IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import { InjectedTextOptions } from 'vs/editor/common/model'; +import { ILineBreaksComputerFactory, ILineBreaksComputer, ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; const enum CharacterClass { NONE = 0, diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index b705c57538f..f11a0f62ea5 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -5,21 +5,19 @@ import { IScrollPosition, Scrollable } from 'vs/base/common/scrollable'; import * as strings from 'vs/base/common/strings'; +import { CursorConfiguration, CursorState, EditOperationType, IColumnSelectData, ICursorSimpleModel, PartialCursorState } from 'vs/editor/common/controller/cursorCommon'; +import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon'; -import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions, ITextModel, InjectedTextOptions, PositionAffinity, IndentGuide, BracketGuideOptions } from 'vs/editor/common/model'; +import { BracketGuideOptions, EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, IndentGuide, ITextModel, PositionAffinity, TextModelResolvedOptions } from 'vs/editor/common/model'; +import { EditorTheme } from 'vs/editor/common/view/viewContext'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; -import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout'; -import { EditorTheme } from 'vs/editor/common/view/viewContext'; -import { ICursorSimpleModel, PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon'; -import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { ILineBreaksComputer, InjectedText } from 'vs/editor/common/viewModel/modelLineProjectionData'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; -import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; -import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; export interface IViewWhitespaceViewportData { readonly id: string; @@ -94,307 +92,6 @@ export interface ICoordinatesConverter { getViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number; } -export class OutputPosition { - outputLineIndex: number; - outputOffset: number; - - constructor(outputLineIndex: number, outputOffset: number) { - this.outputLineIndex = outputLineIndex; - this.outputOffset = outputOffset; - } - - toString(): string { - return `${this.outputLineIndex}:${this.outputOffset}`; - } - - toPosition(baseLineNumber: number): Position { - return new Position(baseLineNumber + this.outputLineIndex, this.outputOffset + 1); - } -} - -/** - * *input*: - * ``` - * xxxxxxxxxxxxxxxxxxxxxxxxxxx - * ``` - * - * -> Applying injections `[i...i]`, *inputWithInjections*: - * ``` - * xxxxxx[iiiiiiiiii]xxxxxxxxxxxxxxxxx[ii]xxxx - * ``` - * - * -> breaking at offsets `|` in `xxxxxx[iiiiiii|iii]xxxxxxxxxxx|xxxxxx[ii]xxxx|`: - * ``` - * xxxxxx[iiiiiii - * iii]xxxxxxxxxxx - * xxxxxx[ii]xxxx - * ``` - * - * -> applying wrappedTextIndentLength, *output*: - * ``` - * xxxxxx[iiiiiii - * iii]xxxxxxxxxxx - * xxxxxx[ii]xxxx - * ``` - */ -export class ModelLineProjectionData { - constructor( - public injectionOffsets: number[] | null, - /** - * `injectionOptions.length` must equal `injectionOffsets.length` - */ - public injectionOptions: InjectedTextOptions[] | null, - /** - * Refers to offsets after applying injections to the source. - * The last break offset indicates the length of the source after applying injections. - */ - public breakOffsets: number[], - /** - * Refers to offsets after applying injections - */ - public breakOffsetsVisibleColumn: number[], - public wrappedTextIndentLength: number - ) { - } - - public getOutputLineCount(): number { - return this.breakOffsets.length; - } - - public getMinOutputOffset(outputLineIndex: number): number { - if (outputLineIndex > 0) { - return this.wrappedTextIndentLength; - } - return 0; - } - - public getLineLength(outputLineIndex: number): number { - // These offsets refer to model text with injected text. - const startOffset = outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0; - const endOffset = this.breakOffsets[outputLineIndex]; - - let lineLength = endOffset - startOffset; - if (outputLineIndex > 0) { - lineLength += this.wrappedTextIndentLength; - } - return lineLength; - } - - public getMaxOutputOffset(outputLineIndex: number): number { - return this.getLineLength(outputLineIndex); - } - - public translateToInputOffset(outputLineIndex: number, outputOffset: number): number { - if (outputLineIndex > 0) { - outputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength); - } - - const offsetInInputWithInjection = outputLineIndex === 0 ? outputOffset : this.breakOffsets[outputLineIndex - 1] + outputOffset; - let offsetInInput = offsetInInputWithInjection; - - if (this.injectionOffsets !== null) { - for (let i = 0; i < this.injectionOffsets.length; i++) { - if (offsetInInput > this.injectionOffsets[i]) { - if (offsetInInput < this.injectionOffsets[i] + this.injectionOptions![i].content.length) { - // `inputOffset` is within injected text - offsetInInput = this.injectionOffsets[i]; - } else { - offsetInInput -= this.injectionOptions![i].content.length; - } - } else { - break; - } - } - } - - return offsetInInput; - } - - public translateToOutputPosition(inputOffset: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition { - let inputOffsetInInputWithInjection = inputOffset; - if (this.injectionOffsets !== null) { - for (let i = 0; i < this.injectionOffsets.length; i++) { - if (inputOffset < this.injectionOffsets[i]) { - break; - } - - if (affinity !== PositionAffinity.Right && inputOffset === this.injectionOffsets[i]) { - break; - } - - inputOffsetInInputWithInjection += this.injectionOptions![i].content.length; - } - } - - return this.offsetInInputWithInjectionsToOutputPosition(inputOffsetInInputWithInjection, affinity); - } - - private offsetInInputWithInjectionsToOutputPosition(offsetInInputWithInjections: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition { - let low = 0; - let high = this.breakOffsets.length - 1; - let mid = 0; - let midStart = 0; - - while (low <= high) { - mid = low + ((high - low) / 2) | 0; - - const midStop = this.breakOffsets[mid]; - midStart = mid > 0 ? this.breakOffsets[mid - 1] : 0; - - if (affinity === PositionAffinity.Left) { - if (offsetInInputWithInjections <= midStart) { - high = mid - 1; - } else if (offsetInInputWithInjections > midStop) { - low = mid + 1; - } else { - break; - } - } else { - if (offsetInInputWithInjections < midStart) { - high = mid - 1; - } else if (offsetInInputWithInjections >= midStop) { - low = mid + 1; - } else { - break; - } - } - } - - let outputOffset = offsetInInputWithInjections - midStart; - if (mid > 0) { - outputOffset += this.wrappedTextIndentLength; - } - - return new OutputPosition(mid, outputOffset); - } - - public normalizeOutputPosition(outputLineIndex: number, outputOffset: number, affinity: PositionAffinity): OutputPosition { - if (this.injectionOffsets !== null) { - const offsetInInputWithInjections = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset); - const normalizedOffsetInUnwrappedLine = this.normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections, affinity); - if (normalizedOffsetInUnwrappedLine !== offsetInInputWithInjections) { - // injected text caused a change - return this.offsetInInputWithInjectionsToOutputPosition(normalizedOffsetInUnwrappedLine, affinity); - } - } - - if (affinity === PositionAffinity.Left) { - if (outputLineIndex > 0 && outputOffset === this.getMinOutputOffset(outputLineIndex)) { - return new OutputPosition(outputLineIndex - 1, this.getMaxOutputOffset(outputLineIndex - 1)); - } - } - else if (affinity === PositionAffinity.Right) { - const maxOutputLineIndex = this.getOutputLineCount() - 1; - if (outputLineIndex < maxOutputLineIndex && outputOffset === this.getMaxOutputOffset(outputLineIndex)) { - return new OutputPosition(outputLineIndex + 1, this.getMinOutputOffset(outputLineIndex + 1)); - } - } - - return new OutputPosition(outputLineIndex, outputOffset); - } - - private outputPositionToOffsetInInputWithInjections(outputLineIndex: number, outputOffset: number): number { - if (outputLineIndex > 0) { - outputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength); - } - const result = (outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0) + outputOffset; - return result; - } - - private normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections: number, affinity: PositionAffinity): number { - const injectedText = this.getInjectedTextAtOffset(offsetInInputWithInjections); - if (!injectedText) { - return offsetInInputWithInjections; - } - - if (affinity === PositionAffinity.None) { - if (offsetInInputWithInjections === injectedText.offsetInInputWithInjections + injectedText.length) { - // go to the end of this injected text - return injectedText.offsetInInputWithInjections + injectedText.length; - } else { - // go to the start of this injected text - return injectedText.offsetInInputWithInjections; - } - } - - if (affinity === PositionAffinity.Right) { - let result = injectedText.offsetInInputWithInjections + injectedText.length; - let index = injectedText.injectedTextIndex; - // traverse all injected text that touch each other - while (index + 1 < this.injectionOffsets!.length && this.injectionOffsets![index + 1] === this.injectionOffsets![index]) { - result += this.injectionOptions![index + 1].content.length; - index++; - } - return result; - } - - // affinity is left - let result = injectedText.offsetInInputWithInjections; - let index = injectedText.injectedTextIndex; - // traverse all injected text that touch each other - while (index - 1 >= 0 && this.injectionOffsets![index - 1] === this.injectionOffsets![index]) { - result -= this.injectionOptions![index - 1].content.length; - index++; - } - return result; - } - - public getInjectedText(outputLineIndex: number, outputOffset: number): InjectedText | null { - const offset = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset); - const injectedText = this.getInjectedTextAtOffset(offset); - if (!injectedText) { - return null; - } - return { - options: this.injectionOptions![injectedText.injectedTextIndex] - }; - } - - private getInjectedTextAtOffset(offsetInInputWithInjections: number): { injectedTextIndex: number, offsetInInputWithInjections: number, length: number } | undefined { - const injectionOffsets = this.injectionOffsets; - const injectionOptions = this.injectionOptions; - - if (injectionOffsets !== null) { - let totalInjectedTextLengthBefore = 0; - for (let i = 0; i < injectionOffsets.length; i++) { - const length = injectionOptions![i].content.length; - const injectedTextStartOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore; - const injectedTextEndOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore + length; - - if (injectedTextStartOffsetInInputWithInjections > offsetInInputWithInjections) { - // Injected text starts later. - break; // All later injected texts have an even larger offset. - } - - if (offsetInInputWithInjections <= injectedTextEndOffsetInInputWithInjections) { - // Injected text ends after or with the given position (but also starts with or before it). - return { - injectedTextIndex: i, - offsetInInputWithInjections: injectedTextStartOffsetInInputWithInjections, - length - }; - } - - totalInjectedTextLengthBefore += length; - } - } - - return undefined; - } -} - -export interface ILineBreaksComputerFactory { - createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer; -} - -export interface ILineBreaksComputer { - /** - * Pass in `previousLineBreakData` if the only difference is in breaking columns!!! - */ - addRequest(lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null): void; - finalize(): (ModelLineProjectionData | null)[]; -} - export interface IViewModel extends ICursorSimpleModel { readonly model: ITextModel; @@ -487,10 +184,6 @@ export interface IViewModel extends ICursorSimpleModel { //#endregion } -export class InjectedText { - constructor(public readonly options: InjectedTextOptions) { } -} - export class MinimapLinesRenderingData { public readonly tabSize: number; public readonly data: Array; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 73408764b5c..5dd89a09c2a 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -21,7 +21,7 @@ import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTok import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout'; import { IViewModelLines, ViewModelLinesFromModelAsIs, ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines'; -import { ICoordinatesConverter, InjectedText, ILineBreaksComputer, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration, OverviewRulerDecorationsGroup, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/viewModel'; +import { ICoordinatesConverter, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration, OverviewRulerDecorationsGroup } from 'vs/editor/common/viewModel/viewModel'; import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations'; import { RunOnceScheduler } from 'vs/base/common/async'; import * as platform from 'vs/base/common/platform'; @@ -34,6 +34,7 @@ import { ViewModelEventDispatcher, OutgoingViewModelEvent, FocusChangedEvent, Sc import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { ArrayQueue } from 'vs/base/common/arrays'; +import { ILineBreaksComputerFactory, ILineBreaksComputer, InjectedText } from 'vs/editor/common/viewModel/modelLineProjectionData'; const USE_IDENTITY_LINES_COLLECTION = true; diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index d51f3d3aa53..c79bc0c5b1d 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -14,8 +14,9 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { createModelLineProjection, IModelLineProjection } from 'vs/editor/common/viewModel/modelLineProjection'; +import { ILineBreaksComputer, ModelLineProjectionData, InjectedText, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/modelLineProjectionData'; import { ConstantTimePrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { ICoordinatesConverter, ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText, ModelLineProjectionData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { ICoordinatesConverter, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; export interface IViewModelLines extends IDisposable { createCoordinatesConverter(): ICoordinatesConverter; diff --git a/src/vs/editor/test/common/viewModel/lineBreakData.test.ts b/src/vs/editor/test/common/viewModel/lineBreakData.test.ts index 20705b9396c..6ff5c565287 100644 --- a/src/vs/editor/test/common/viewModel/lineBreakData.test.ts +++ b/src/vs/editor/test/common/viewModel/lineBreakData.test.ts @@ -6,7 +6,7 @@ import assert = require('assert'); import { PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationInjectedTextOptions } from 'vs/editor/common/model/textModel'; -import { ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; +import { ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; suite('Editor ViewModel - LineBreakData', () => { test('Basic', () => { diff --git a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts index dd7f378e6a0..bb53c937bbc 100644 --- a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts +++ b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { WrappingIndent, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/viewModel/viewModel'; +import { ModelLineProjectionData, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/modelLineProjectionData'; function parseAnnotatedText(annotatedText: string): { text: string; indices: number[]; } { let text = ''; diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index dac9403c5ce..636d0f18a83 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -15,11 +15,12 @@ import * as modes from 'vs/editor/common/modes'; import { NULL_STATE } from 'vs/editor/common/modes/nullMode'; import { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer'; import { ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines'; -import { ModelLineProjectionData, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { createTextModel } from 'vs/editor/test/common/editorTestUtils'; import { ISimpleModel, IModelLineProjection, createModelLineProjection } from 'vs/editor/common/viewModel/modelLineProjection'; +import { ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; suite('Editor ViewModel - SplitLinesCollection', () => { test('SplitLine', () => { From 3f56153091e7a0abfc79b2b01582ab603d2c4ddd Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 11:48:49 +0100 Subject: [PATCH 30/83] =?UTF-8?q?=F0=9F=92=84=20(Reordering=20Symbols,=20F?= =?UTF-8?q?ixing=20spaces)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewModel/modelLineProjectionData.ts | 1 - .../viewModel/monospaceLineBreaksComputer.ts | 91 ++++++----- src/vs/editor/common/viewModel/viewModel.ts | 146 +++++++++--------- .../viewModel/viewModelEventDispatcher.ts | 20 +-- 4 files changed, 128 insertions(+), 130 deletions(-) diff --git a/src/vs/editor/common/viewModel/modelLineProjectionData.ts b/src/vs/editor/common/viewModel/modelLineProjectionData.ts index a786ebfbff0..a8328e19265 100644 --- a/src/vs/editor/common/viewModel/modelLineProjectionData.ts +++ b/src/vs/editor/common/viewModel/modelLineProjectionData.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; import { Position } from 'vs/editor/common/core/position'; diff --git a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts index dd6d1437b0c..4c1cd5c4ad9 100644 --- a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts +++ b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts @@ -12,53 +12,7 @@ import { LineInjectedText } from 'vs/editor/common/model/textModelEvents'; import { InjectedTextOptions } from 'vs/editor/common/model'; import { ILineBreaksComputerFactory, ILineBreaksComputer, ModelLineProjectionData } from 'vs/editor/common/viewModel/modelLineProjectionData'; -const enum CharacterClass { - NONE = 0, - BREAK_BEFORE = 1, - BREAK_AFTER = 2, - BREAK_IDEOGRAPHIC = 3 // for Han and Kana. -} - -class WrappingCharacterClassifier extends CharacterClassifier { - - constructor(BREAK_BEFORE: string, BREAK_AFTER: string) { - super(CharacterClass.NONE); - - for (let i = 0; i < BREAK_BEFORE.length; i++) { - this.set(BREAK_BEFORE.charCodeAt(i), CharacterClass.BREAK_BEFORE); - } - - for (let i = 0; i < BREAK_AFTER.length; i++) { - this.set(BREAK_AFTER.charCodeAt(i), CharacterClass.BREAK_AFTER); - } - } - - public override get(charCode: number): CharacterClass { - if (charCode >= 0 && charCode < 256) { - return this._asciiMap[charCode]; - } else { - // Initialize CharacterClass.BREAK_IDEOGRAPHIC for these Unicode ranges: - // 1. CJK Unified Ideographs (0x4E00 -- 0x9FFF) - // 2. CJK Unified Ideographs Extension A (0x3400 -- 0x4DBF) - // 3. Hiragana and Katakana (0x3040 -- 0x30FF) - if ( - (charCode >= 0x3040 && charCode <= 0x30FF) - || (charCode >= 0x3400 && charCode <= 0x4DBF) - || (charCode >= 0x4E00 && charCode <= 0x9FFF) - ) { - return CharacterClass.BREAK_IDEOGRAPHIC; - } - - return (this._map.get(charCode) || this._defaultValue); - } - } -} - -let arrPool1: number[] = []; -let arrPool2: number[] = []; - export class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFactory { - public static create(options: IComputedEditorOptions): MonospaceLineBreaksComputerFactory { return new MonospaceLineBreaksComputerFactory( options.get(EditorOption.wordWrapBreakBeforeCharacters), @@ -105,6 +59,51 @@ export class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFa } } +const enum CharacterClass { + NONE = 0, + BREAK_BEFORE = 1, + BREAK_AFTER = 2, + BREAK_IDEOGRAPHIC = 3 // for Han and Kana. +} + +class WrappingCharacterClassifier extends CharacterClassifier { + + constructor(BREAK_BEFORE: string, BREAK_AFTER: string) { + super(CharacterClass.NONE); + + for (let i = 0; i < BREAK_BEFORE.length; i++) { + this.set(BREAK_BEFORE.charCodeAt(i), CharacterClass.BREAK_BEFORE); + } + + for (let i = 0; i < BREAK_AFTER.length; i++) { + this.set(BREAK_AFTER.charCodeAt(i), CharacterClass.BREAK_AFTER); + } + } + + public override get(charCode: number): CharacterClass { + if (charCode >= 0 && charCode < 256) { + return this._asciiMap[charCode]; + } else { + // Initialize CharacterClass.BREAK_IDEOGRAPHIC for these Unicode ranges: + // 1. CJK Unified Ideographs (0x4E00 -- 0x9FFF) + // 2. CJK Unified Ideographs Extension A (0x3400 -- 0x4DBF) + // 3. Hiragana and Katakana (0x3040 -- 0x30FF) + if ( + (charCode >= 0x3040 && charCode <= 0x30FF) + || (charCode >= 0x3400 && charCode <= 0x4DBF) + || (charCode >= 0x4E00 && charCode <= 0x9FFF) + ) { + return CharacterClass.BREAK_IDEOGRAPHIC; + } + + return (this._map.get(charCode) || this._defaultValue); + } + } +} + +let arrPool1: number[] = []; +let arrPool2: number[] = []; + function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: ModelLineProjectionData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): ModelLineProjectionData | null { if (firstLineBreakColumn === -1) { return null; diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index f11a0f62ea5..dc254cf21eb 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -19,79 +19,6 @@ import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewL import { ILineBreaksComputer, InjectedText } from 'vs/editor/common/viewModel/modelLineProjectionData'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; -export interface IViewWhitespaceViewportData { - readonly id: string; - readonly afterLineNumber: number; - readonly verticalOffset: number; - readonly height: number; -} - -export class Viewport { - readonly _viewportBrand: void = undefined; - - readonly top: number; - readonly left: number; - readonly width: number; - readonly height: number; - - constructor(top: number, left: number, width: number, height: number) { - this.top = top | 0; - this.left = left | 0; - this.width = width | 0; - this.height = height | 0; - } -} - -export interface IViewLayout { - - getScrollable(): Scrollable; - - getScrollWidth(): number; - getScrollHeight(): number; - - getCurrentScrollLeft(): number; - getCurrentScrollTop(): number; - getCurrentViewport(): Viewport; - - getFutureViewport(): Viewport; - - validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition; - - getLinesViewportData(): IPartialViewLinesViewportData; - getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData; - getWhitespaces(): IEditorWhitespace[]; - - isAfterLines(verticalOffset: number): boolean; - isInTopPadding(verticalOffset: number): boolean; - isInBottomPadding(verticalOffset: number): boolean; - getLineNumberAtVerticalOffset(verticalOffset: number): number; - getVerticalOffsetForLineNumber(lineNumber: number): number; - getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null; - - /** - * Get the layout information for whitespaces currently in the viewport - */ - getWhitespaceViewportData(): IViewWhitespaceViewportData[]; -} - -export interface ICoordinatesConverter { - // View -> Model conversion and related methods - convertViewPositionToModelPosition(viewPosition: Position): Position; - convertViewRangeToModelRange(viewRange: Range): Range; - validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position; - validateViewRange(viewRange: Range, expectedModelRange: Range): Range; - - // Model -> View conversion and related methods - convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity): Position; - /** - * @param affinity Only has an effect if the range is empty. - */ - convertModelRangeToViewRange(modelRange: Range, affinity?: PositionAffinity): Range; - modelPositionIsVisible(modelPosition: Position): boolean; - getModelLineViewLineCount(modelLineNumber: number): number; - getViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number; -} - export interface IViewModel extends ICursorSimpleModel { readonly model: ITextModel; @@ -184,6 +111,79 @@ export interface IViewModel extends ICursorSimpleModel { //#endregion } +export interface IViewLayout { + + getScrollable(): Scrollable; + + getScrollWidth(): number; + getScrollHeight(): number; + + getCurrentScrollLeft(): number; + getCurrentScrollTop(): number; + getCurrentViewport(): Viewport; + + getFutureViewport(): Viewport; + + validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition; + + getLinesViewportData(): IPartialViewLinesViewportData; + getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData; + getWhitespaces(): IEditorWhitespace[]; + + isAfterLines(verticalOffset: number): boolean; + isInTopPadding(verticalOffset: number): boolean; + isInBottomPadding(verticalOffset: number): boolean; + getLineNumberAtVerticalOffset(verticalOffset: number): number; + getVerticalOffsetForLineNumber(lineNumber: number): number; + getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null; + + /** + * Get the layout information for whitespaces currently in the viewport + */ + getWhitespaceViewportData(): IViewWhitespaceViewportData[]; +} + +export interface IViewWhitespaceViewportData { + readonly id: string; + readonly afterLineNumber: number; + readonly verticalOffset: number; + readonly height: number; +} + +export class Viewport { + readonly _viewportBrand: void = undefined; + + readonly top: number; + readonly left: number; + readonly width: number; + readonly height: number; + + constructor(top: number, left: number, width: number, height: number) { + this.top = top | 0; + this.left = left | 0; + this.width = width | 0; + this.height = height | 0; + } +} + +export interface ICoordinatesConverter { + // View -> Model conversion and related methods + convertViewPositionToModelPosition(viewPosition: Position): Position; + convertViewRangeToModelRange(viewRange: Range): Range; + validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position; + validateViewRange(viewRange: Range, expectedModelRange: Range): Range; + + // Model -> View conversion and related methods + convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity): Position; + /** + * @param affinity Only has an effect if the range is empty. + */ + convertModelRangeToViewRange(modelRange: Range, affinity?: PositionAffinity): Range; + modelPositionIsVisible(modelPosition: Position): boolean; + getModelLineViewLineCount(modelLineNumber: number): number; + getViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number; +} + export class MinimapLinesRenderingData { public readonly tabSize: number; public readonly data: Array; diff --git a/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts b/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts index 78293d65788..641e5b2efef 100644 --- a/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts +++ b/src/vs/editor/common/viewModel/viewModelEventDispatcher.ts @@ -171,6 +171,16 @@ export class ViewModelEventsCollector { } } +export type OutgoingViewModelEvent = ( + ContentSizeChangedEvent + | FocusChangedEvent + | ScrollChangedEvent + | ViewZonesChangedEvent + | HiddenAreasChangedEvent + | ReadOnlyEditAttemptEvent + | CursorStateChangedEvent +); + export const enum OutgoingViewModelEventKind { ContentSizeChanged, FocusChanged, @@ -399,13 +409,3 @@ export class ReadOnlyEditAttemptEvent { return this; } } - -export type OutgoingViewModelEvent = ( - ContentSizeChangedEvent - | FocusChangedEvent - | ScrollChangedEvent - | ViewZonesChangedEvent - | HiddenAreasChangedEvent - | ReadOnlyEditAttemptEvent - | CursorStateChangedEvent -); From 1abc24d708bcd26120b0a39970bf6b1273ba6c78 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 12:11:36 +0100 Subject: [PATCH 31/83] _reduceRanges -> normalizeLineRanges. --- .../editor/common/viewModel/viewModelLines.ts | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index c79bc0c5b1d..4daedfde680 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -165,34 +165,9 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { }); } - private _reduceRanges(_ranges: Range[]): Range[] { - if (_ranges.length === 0) { - return []; - } - let ranges = _ranges.map(r => this.model.validateRange(r)).sort(Range.compareRangesUsingStarts); - - let result: Range[] = []; - let currentRangeStart = ranges[0].startLineNumber; - let currentRangeEnd = ranges[0].endLineNumber; - - for (let i = 1, len = ranges.length; i < len; i++) { - let range = ranges[i]; - - if (range.startLineNumber > currentRangeEnd + 1) { - result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1)); - currentRangeStart = range.startLineNumber; - currentRangeEnd = range.endLineNumber; - } else if (range.endLineNumber > currentRangeEnd) { - currentRangeEnd = range.endLineNumber; - } - } - result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1)); - return result; - } - public setHiddenAreas(_ranges: Range[]): boolean { - - let newRanges = this._reduceRanges(_ranges); + const validatedRanges = _ranges.map(r => this.model.validateRange(r)); + let newRanges = normalizeLineRanges(validatedRanges); // BEGIN TODO@Martin: Please stop calling this method on each model change! let oldRanges = this.hiddenAreasIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); @@ -948,6 +923,43 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { } } +/** + * Overlapping unsorted ranges: + * [ ) [ ) [ ) + * [ ) [ ) + * -> + * Non overlapping sorted ranges: + * [ ) [ ) [ ) + * + * Note: This function only considers line information! Columns are ignored. +*/ +function normalizeLineRanges(ranges: Range[]): Range[] { + if (ranges.length === 0) { + return []; + } + + const sortedRanges = ranges.slice(); + sortedRanges.sort(Range.compareRangesUsingStarts); + + const result: Range[] = []; + let currentRangeStart = sortedRanges[0].startLineNumber; + let currentRangeEnd = sortedRanges[0].endLineNumber; + + for (let i = 1, len = sortedRanges.length; i < len; i++) { + let range = sortedRanges[i]; + + if (range.startLineNumber > currentRangeEnd + 1) { + result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1)); + currentRangeStart = range.startLineNumber; + currentRangeEnd = range.endLineNumber; + } else if (range.endLineNumber > currentRangeEnd) { + currentRangeEnd = range.endLineNumber; + } + } + result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1)); + return result; +} + /** * Represents a view line. Can be used to efficiently query more information about it. */ From ace51630a927f5b09248dae3515fb03f23f4b3fa Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 12:16:46 +0100 Subject: [PATCH 32/83] hiddenAreasIds -> hiddenAreasDecorationIds, fixes leaking decorations when lines are reconstructed. --- .../editor/common/viewModel/viewModelLines.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index 4daedfde680..338a2825126 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -77,7 +77,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { */ private projectedModelLineLineCounts!: ConstantTimePrefixSumComputer; - private hiddenAreasIds!: string[]; + private hiddenAreasDecorationIds!: string[]; constructor( editorId: number, @@ -105,7 +105,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { } public dispose(): void { - this.hiddenAreasIds = this.model.deltaDecorations(this.hiddenAreasIds, []); + this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []); } public createCoordinatesConverter(): ICoordinatesConverter { @@ -116,7 +116,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { this.modelLineProjections = []; if (resetHiddenAreas) { - this.hiddenAreasIds = []; + this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []); } const linesContent = this.model.getLinesContent(); @@ -133,7 +133,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { let values: number[] = []; - let hiddenAreas = this.hiddenAreasIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); + let hiddenAreas = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); let hiddenAreaStart = 1, hiddenAreaEnd = 0; let hiddenAreaIdx = -1; let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2; @@ -160,9 +160,9 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { } public getHiddenAreas(): Range[] { - return this.hiddenAreasIds.map((decId) => { - return this.model.getDecorationRange(decId)!; - }); + return this.hiddenAreasDecorationIds.map( + (decId) => this.model.getDecorationRange(decId)! + ); } public setHiddenAreas(_ranges: Range[]): boolean { @@ -170,7 +170,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { let newRanges = normalizeLineRanges(validatedRanges); // BEGIN TODO@Martin: Please stop calling this method on each model change! - let oldRanges = this.hiddenAreasIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); + let oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); if (newRanges.length === oldRanges.length) { let hasDifference = false; @@ -194,7 +194,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { }); } - this.hiddenAreasIds = this.model.deltaDecorations(this.hiddenAreasIds, newDecorations); + this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, newDecorations); let hiddenAreas = newRanges; let hiddenAreaStart = 1, hiddenAreaEnd = 0; From 5dfa71a9e8605f47c09e5501101a21ae1c38ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 13:24:28 +0100 Subject: [PATCH 33/83] fix(git): :bug: git api commands should be registered as contributions Closes: #111658 --- .vscode/settings.json | 3 ++- extensions/git/package.json | 27 +++++++++++++++++++++++++++ extensions/git/package.nls.json | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5fcdc566ba0..a6cd70e725d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -85,6 +85,7 @@ "grid", "splitview", "table", - "list" + "list", + "git" ] } diff --git a/extensions/git/package.json b/extensions/git/package.json index 48828c4e262..b778540aa91 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -515,6 +515,21 @@ "command": "git.rebaseAbort", "title": "%command.rebaseAbort%", "category": "Git" + }, + { + "command": "git.api.getRepositories", + "title": "%command.api.getRepositories%", + "category": "Git API" + }, + { + "command": "git.api.getRepositoryState", + "title": "%command.api.getRepositoryState%", + "category": "Git API" + }, + { + "command": "git.api.getRemoteSources", + "title": "%command.api.getRemoteSources%", + "category": "Git API" } ], "keybindings": [ @@ -898,6 +913,18 @@ { "command": "git.timeline.compareWithSelected", "when": "false" + }, + { + "command": "git.api.getRepositories", + "when": "false" + }, + { + "command": "git.api.getRepositoryState", + "when": "false" + }, + { + "command": "git.api.getRemoteSources", + "when": "false" } ], "scm/title": [ diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index ce652f94947..7b3af1f5ca9 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -92,6 +92,9 @@ "command.timelineCopyCommitMessage": "Copy Commit Message", "command.timelineSelectForCompare": "Select for Compare", "command.timelineCompareWithSelected": "Compare with Selected", + "command.api.getRepositories": "Get Repositories", + "command.api.getRepositoryState": "Get Repository State", + "command.api.getRemoteSources": "Get Remote Sources", "config.enabled": "Whether git is enabled.", "config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows). This can also be an array of string values containing multiple paths to look up.", "config.autoRepositoryDetection": "Configures when repositories should be automatically detected.", From b2b3437743bd1c9fa53e16df310ae0ee987c4597 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 13:25:23 +0100 Subject: [PATCH 34/83] Improves comments. --- src/vs/editor/common/viewModel/viewModelLines.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index 338a2825126..b396a66e196 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -169,9 +169,10 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { const validatedRanges = _ranges.map(r => this.model.validateRange(r)); let newRanges = normalizeLineRanges(validatedRanges); - // BEGIN TODO@Martin: Please stop calling this method on each model change! - let oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); + // TODO@Martin: Please stop calling this method on each model change! + // This checks if there really was a change + let oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts); if (newRanges.length === oldRanges.length) { let hasDifference = false; for (let i = 0; i < newRanges.length; i++) { @@ -184,8 +185,7 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return false; } } - // END TODO@Martin: Please stop calling this method on each model change! - + let newDecorations: IModelDeltaDecoration[] = []; for (const newRange of newRanges) { newDecorations.push({ From d7ed0e37403926c89a484c1ab46c31b92adde0c4 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 13:27:09 +0100 Subject: [PATCH 35/83] Uses Array.map. --- src/vs/editor/common/viewModel/viewModelLines.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index b396a66e196..8879899e6d6 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -185,14 +185,14 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return false; } } - - let newDecorations: IModelDeltaDecoration[] = []; - for (const newRange of newRanges) { - newDecorations.push({ - range: newRange, - options: ModelDecorationOptions.EMPTY - }); - } + + const newDecorations = newRanges.map( + (r) => + ({ + range: r, + options: ModelDecorationOptions.EMPTY, + }) + ); this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, newDecorations); From 3abda3b8b965b8b09444a49e1e34f97a76e3c501 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Nov 2021 13:38:03 +0100 Subject: [PATCH 36/83] :lipstick: --- src/vs/workbench/api/common/extHost.api.impl.ts | 14 +++++++------- .../services/extensions/common/extensions.ts | 6 +----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index e631f08178c..2e253a57d53 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -46,7 +46,7 @@ import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import type * as vscode from 'vscode'; @@ -200,8 +200,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // We only inform once, it is not a warning because we just want to raise awareness and because // we cannot say if the extension is doing it right or wrong... const checkSelector = (function () { - let done = (!extension.isUnderDevelopment); - function informOnce(selector: vscode.DocumentSelector) { + let done = !extension.isUnderDevelopment; + function informOnce() { if (!done) { extHostLogService.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`); done = true; @@ -211,14 +211,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I if (Array.isArray(selector)) { selector.forEach(perform); } else if (typeof selector === 'string') { - informOnce(selector); + informOnce(); } else { const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768 if (typeof filter.scheme === 'undefined') { - informOnce(selector); + informOnce(); } - if (!extension.enableProposedApi && typeof filter.exclusive === 'boolean') { - throwProposedApiError(extension); + if (typeof filter.exclusive === 'boolean') { + checkProposedApiEnabled(extension); } } return selector; diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index c70a33e3d9c..9713a42faa4 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -321,14 +321,10 @@ export interface ProfileSession { export function checkProposedApiEnabled(extension: IExtensionDescription): void { if (!extension.enableProposedApi) { - throwProposedApiError(extension); + throw new Error(`[${extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.identifier.value}`); } } -export function throwProposedApiError(extension: IExtensionDescription): never { - throw new Error(`[${extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.identifier.value}`); -} - export function toExtension(extensionDescription: IExtensionDescription): IExtension { return { type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User, From 986784928729f70f10c443c945b4aa8a49d30790 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Nov 2021 13:52:01 +0100 Subject: [PATCH 37/83] use nullExtensionDescription in more places, https://github.com/microsoft/vscode/issues/131165 --- .../browser/api/extHostAuthentication.test.ts | 51 ++++++++----------- .../extHostDocumentSaveParticipant.test.ts | 14 +---- .../test/browser/api/extHostTreeViews.test.ts | 23 +++++---- .../test/browser/api/extHostWorkspace.test.ts | 16 +----- 4 files changed, 36 insertions(+), 68 deletions(-) diff --git a/src/vs/workbench/test/browser/api/extHostAuthentication.test.ts b/src/vs/workbench/test/browser/api/extHostAuthentication.test.ts index be6599dc213..87b04169218 100644 --- a/src/vs/workbench/test/browser/api/extHostAuthentication.test.ts +++ b/src/vs/workbench/test/browser/api/extHostAuthentication.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; @@ -20,7 +20,7 @@ import { ExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.pro import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication'; import { IActivityService } from 'vs/workbench/services/activity/common/activity'; import { AuthenticationService, IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionService, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { TestRemoteAgentService } from 'vs/workbench/services/remote/test/common/testServices'; import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol'; @@ -89,18 +89,7 @@ class TestAuthProvider implements AuthenticationProvider { suite('ExtHostAuthentication', () => { let disposables: DisposableStore; - let nullExtensionDescription: IExtensionDescription = { - identifier: new ExtensionIdentifier('nullExtensionDescription'), - name: 'Null Extension Description', - publisher: 'vscode', - enableProposedApi: true, - engines: undefined!, - extensionLocation: undefined!, - isBuiltin: false, - isUserBuiltin: false, - isUnderDevelopment: false, - version: undefined! - }; + let extensionDescription: IExtensionDescription = { ...nullExtensionDescription, enableProposedApi: true }; let extHostAuthentication: ExtHostAuthentication; let instantiationService: TestInstantiationService; @@ -140,7 +129,7 @@ suite('ExtHostAuthentication', () => { test('createIfNone - true', async () => { const session = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -152,7 +141,7 @@ suite('ExtHostAuthentication', () => { test('createIfNone - false', async () => { const nosession = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], {}); @@ -160,7 +149,7 @@ suite('ExtHostAuthentication', () => { // Now create the session const session = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -171,7 +160,7 @@ suite('ExtHostAuthentication', () => { assert.strictEqual(session?.scopes[0], 'foo'); const session2 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], {}); @@ -184,7 +173,7 @@ suite('ExtHostAuthentication', () => { // should behave the same as createIfNone: false test('silent - true', async () => { const nosession = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -194,7 +183,7 @@ suite('ExtHostAuthentication', () => { // Now create the session const session = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -205,7 +194,7 @@ suite('ExtHostAuthentication', () => { assert.strictEqual(session?.scopes[0], 'foo'); const session2 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -218,7 +207,7 @@ suite('ExtHostAuthentication', () => { test('forceNewSession - true', async () => { const session1 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -227,7 +216,7 @@ suite('ExtHostAuthentication', () => { // Now create the session const session2 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -241,7 +230,7 @@ suite('ExtHostAuthentication', () => { test('forceNewSession - detail', async () => { const session1 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -250,7 +239,7 @@ suite('ExtHostAuthentication', () => { // Now create the session const session2 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -265,7 +254,7 @@ suite('ExtHostAuthentication', () => { test('clearSessionPreference - true', async () => { // Now create the session const session = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test-multiple', ['foo'], { @@ -276,7 +265,7 @@ suite('ExtHostAuthentication', () => { assert.strictEqual(session?.scopes[0], 'foo'); const session2 = await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test-multiple', ['foo'], { @@ -294,7 +283,7 @@ suite('ExtHostAuthentication', () => { test('forceNewSession with no sessions', async () => { try { await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -309,7 +298,7 @@ suite('ExtHostAuthentication', () => { test('createIfNone and forceNewSession', async () => { try { await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -325,7 +314,7 @@ suite('ExtHostAuthentication', () => { test('forceNewSession and silent', async () => { try { await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { @@ -341,7 +330,7 @@ suite('ExtHostAuthentication', () => { test('createIfNone and silent', async () => { try { await extHostAuthentication.getSession( - nullExtensionDescription, + extensionDescription, 'test', ['foo'], { diff --git a/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts index 68708e71ad1..4859a1f9086 100644 --- a/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts @@ -15,7 +15,7 @@ import type * as vscode from 'vscode'; import { mock } from 'vs/base/test/common/mock'; import { NullLogService } from 'vs/platform/log/common/log'; import { timeout } from 'vs/base/common/async'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; suite('ExtHostDocumentSaveParticipant', () => { @@ -23,18 +23,6 @@ suite('ExtHostDocumentSaveParticipant', () => { let mainThreadBulkEdits = new class extends mock() { }; let documents: ExtHostDocuments; let nullLogService = new NullLogService(); - let nullExtensionDescription: IExtensionDescription = { - identifier: new ExtensionIdentifier('nullExtensionDescription'), - name: 'Null Extension Description', - publisher: 'vscode', - enableProposedApi: false, - engines: undefined!, - extensionLocation: undefined!, - isBuiltin: false, - isUserBuiltin: false, - isUnderDevelopment: false, - version: undefined! - }; setup(() => { const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null), new NullLogService()); diff --git a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts index dc6fdca0353..46fc654a936 100644 --- a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts @@ -19,6 +19,7 @@ import { TreeItemCollapsibleState, ITreeItem, IRevealOptions } from 'vs/workbenc import { NullLogService } from 'vs/platform/log/common/log'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import type { IDisposable } from 'vs/base/common/lifecycle'; +import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; suite('ExtHostTreeView', function () { @@ -41,6 +42,8 @@ suite('ExtHostTreeView', function () { } + const extensionsDescription: IExtensionDescription = { ...nullExtensionDescription, enableProposedApi: true }; + let testObject: ExtHostTreeViews; let target: RecordingShape; let onDidChangeTreeNode: Emitter<{ key: string } | undefined>; @@ -80,9 +83,9 @@ suite('ExtHostTreeView', function () { ), new NullLogService()); onDidChangeTreeNode = new Emitter<{ key: string } | undefined>(); onDidChangeTreeNodeWithId = new Emitter<{ key: string }>(); - testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); - testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); - testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, extensionsDescription); + testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }, extensionsDescription); + testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }, extensionsDescription); return loadCompleteTree('testNodeTreeProvider'); }); @@ -482,14 +485,14 @@ suite('ExtHostTreeView', function () { }); test('reveal will throw an error if getParent is not implemented', () => { - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() }, extensionsDescription); return treeView.reveal({ key: 'a' }) .then(() => assert.fail('Reveal should throw an error as getParent is not implemented'), () => null); }); test('reveal will return empty array for root element', () => { const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); const expected = { item: { handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }, @@ -506,7 +509,7 @@ suite('ExtHostTreeView', function () { test('reveal will return parents array for an element when hierarchy is not loaded', () => { const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); const expected = { item: { handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }] @@ -523,7 +526,7 @@ suite('ExtHostTreeView', function () { test('reveal will return parents array for an element when hierarchy is loaded', () => { const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); const expected = { item: { handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }] @@ -549,7 +552,7 @@ suite('ExtHostTreeView', function () { } }; const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); const expected = { item: { handle: '0/0:b/0:ba/0:bac', label: { label: 'bac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, parentChain: [ @@ -569,7 +572,7 @@ suite('ExtHostTreeView', function () { test('reveal after first udpate', () => { const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); const expected = { item: { handle: '0/0:a/0:ac', label: { label: 'ac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }] @@ -601,7 +604,7 @@ suite('ExtHostTreeView', function () { test('reveal after second udpate', () => { const revealTarget = sinon.spy(target, '$reveal'); - const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); + const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, extensionsDescription); return loadCompleteTree('treeDataProvider') .then(() => { return runWithEventMerging((resolve) => { diff --git a/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts index 37bfb0b6870..154a72f8ab9 100644 --- a/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { CancellationToken } from 'vs/base/common/cancellation'; import { basename } from 'vs/base/common/path'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; import { MainThreadWorkspace } from 'vs/workbench/api/browser/mainThreadWorkspace'; @@ -23,6 +23,7 @@ import { IPatternInfo } from 'vs/workbench/services/search/common/search'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo'; import { FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; +import { nullExtensionDescription as extensionDescriptor } from 'vs/workbench/services/extensions/common/extensions'; function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService): ExtHostWorkspace { const result = new ExtHostWorkspace( @@ -37,19 +38,6 @@ function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, suite('ExtHostWorkspace', function () { - const extensionDescriptor: IExtensionDescription = { - identifier: new ExtensionIdentifier('nullExtensionDescription'), - name: 'ext', - publisher: 'vscode', - enableProposedApi: false, - engines: undefined!, - extensionLocation: undefined!, - isBuiltin: false, - isUserBuiltin: false, - isUnderDevelopment: false, - version: undefined! - }; - function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) { const actual = workspace.getRelativePath(input, includeWorkspace); assert.strictEqual(actual, expected); From 799d82fcc3c92933a8bce04cd4178c0cd8f10b3e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 9 Nov 2021 14:13:32 +0100 Subject: [PATCH 38/83] add isProposedApiEnabled-util, move checkProposedApiEnabled-util, use utils instead of reading the enableProposedApi-property, https://github.com/microsoft/vscode/issues/129037 --- src/vs/platform/extensions/common/extensions.ts | 12 +++++++++++- src/vs/workbench/api/browser/viewsExtensionPoint.ts | 4 ++-- src/vs/workbench/api/common/extHost.api.impl.ts | 13 ++++++------- .../workbench/api/common/extHostExtensionService.ts | 4 ++-- .../workbench/api/common/extHostMessageService.ts | 3 +-- .../workbench/api/common/extHostNotebookKernels.ts | 3 +-- .../api/common/extHostNotebookRenderers.ts | 4 ++-- src/vs/workbench/api/common/extHostOutput.ts | 3 +-- src/vs/workbench/api/common/extHostSCM.ts | 3 +-- src/vs/workbench/api/common/menusExtensionPoint.ts | 5 +++-- src/vs/workbench/contrib/remote/browser/remote.ts | 4 ++-- .../welcome/common/viewsWelcomeContribution.ts | 3 ++- .../services/extensions/common/extensions.ts | 6 ------ .../services/extensions/node/proxyResolver.ts | 4 ++-- .../workbench/services/label/common/labelService.ts | 3 ++- .../services/themes/common/iconExtensionPoint.ts | 6 +++--- 16 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index a9b78238899..d595e2ab237 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -349,6 +349,16 @@ export interface IExtensionDescription extends IExtensionManifest { enableProposedApi?: boolean; } +export function isProposedApiEnabled(extension: IExtensionDescription | IExtensionManifest): boolean { + return Boolean(extension.enableProposedApi); +} + +export function checkProposedApiEnabled(extension: IExtensionDescription): void { + if (!isProposedApiEnabled(extension)) { + throw new Error(`[${extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.identifier.value}`); + } +} + export function isLanguagePackExtension(manifest: IExtensionManifest): boolean { return manifest.contributes && manifest.contributes.localizations ? manifest.contributes.localizations.length > 0 : false; } @@ -358,7 +368,7 @@ export function isAuthenticationProviderExtension(manifest: IExtensionManifest): } export function isResolverExtension(manifest: IExtensionManifest, remoteAuthority: string | undefined): boolean { - if (remoteAuthority && manifest.enableProposedApi) { + if (remoteAuthority && isProposedApiEnabled(manifest)) { const activationEvent = `onResolveRemoteAuthority:${getRemoteName(remoteAuthority)}`; return manifest.activationEvents?.indexOf(activationEvent) !== -1; } diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index ad5481ed97b..63fcf147042 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -10,7 +10,7 @@ import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -404,7 +404,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { return; } - if (entry.key === 'remote' && !extension.description.enableProposedApi) { + if (entry.key === 'remote' && !isProposedApiEnabled(extension.description)) { collector.warn(localize('ViewContainerRequiresProposedAPI', "View container '{0}' requires 'enableProposedApi' turned on to be added to 'Remote'.", entry.key)); return; } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 2e253a57d53..3313761cc00 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -46,11 +46,10 @@ import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import type * as vscode from 'vscode'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { checkProposedApiEnabled, IExtensionDescription, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { values } from 'vs/base/common/collections'; import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets'; import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService'; @@ -600,7 +599,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return >extHostMessageService.showMessage(extension, Severity.Error, message, rest[0], >rest.slice(1)); }, showQuickPick(items: any, options?: vscode.QuickPickOptions, token?: vscode.CancellationToken): any { - return extHostQuickOpen.showQuickPick(items, !!extension.enableProposedApi, options, token); + return extHostQuickOpen.showQuickPick(items, isProposedApiEnabled(extension), options, token); }, showWorkspaceFolderPick(options?: vscode.WorkspaceFolderPickOptions) { return extHostQuickOpen.showWorkspaceFolderPick(options); @@ -689,7 +688,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostUrls.registerUriHandler(extension.identifier, handler); }, createQuickPick(): vscode.QuickPick { - return extHostQuickOpen.createQuickPick(extension.identifier, !!extension.enableProposedApi); + return extHostQuickOpen.createQuickPick(extension.identifier, isProposedApiEnabled(extension)); }, createInputBox(): vscode.InputBox { return extHostQuickOpen.createInputBox(extension.identifier); @@ -891,11 +890,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostNotebook.onDidCloseNotebookDocument; }, registerNotebookSerializer(viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) { - return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options, extension.enableProposedApi ? registration : undefined); + return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options, isProposedApiEnabled(extension) ? registration : undefined); }, registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) => { checkProposedApiEnabled(extension); - return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options, extension.enableProposedApi ? registration : undefined); + return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options, isProposedApiEnabled(extension) ? registration : undefined); }, onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return configProvider.onDidChangeConfiguration(listener, thisArgs, disposables); @@ -1095,7 +1094,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // namespace: notebook const notebooks: typeof vscode.notebooks = { createNotebookController(id: string, notebookType: string, label: string, handler?, rendererScripts?: vscode.NotebookRendererScript[]) { - return extHostNotebookKernels.createNotebookController(extension, id, notebookType, label, handler, extension.enableProposedApi ? rendererScripts : undefined); + return extHostNotebookKernels.createNotebookController(extension, id, notebookType, label, handler, isProposedApiEnabled(extension) ? rendererScripts : undefined); }, registerNotebookCellStatusBarItemProvider: (notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) => { return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, notebookType, provider); diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index dbbd8cf7be7..abd8d5c0b34 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -17,11 +17,11 @@ import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/co import { ActivatedExtension, EmptyExtension, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { MissingExtensionDependency, checkProposedApiEnabled, ActivationKind } from 'vs/workbench/services/extensions/common/extensions'; +import { MissingExtensionDependency, ActivationKind } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import * as errors from 'vs/base/common/errors'; import type * as vscode from 'vscode'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { checkProposedApiEnabled, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { VSBuffer } from 'vs/base/common/buffer'; import { ExtensionGlobalMemento, ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; import { RemoteAuthorityResolverError, ExtensionKind, ExtensionMode, ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes'; diff --git a/src/vs/workbench/api/common/extHostMessageService.ts b/src/vs/workbench/api/common/extHostMessageService.ts index 9f36d8dd3ac..d33e16ce3d7 100644 --- a/src/vs/workbench/api/common/extHostMessageService.ts +++ b/src/vs/workbench/api/common/extHostMessageService.ts @@ -6,9 +6,8 @@ import Severity from 'vs/base/common/severity'; import type * as vscode from 'vscode'; import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { checkProposedApiEnabled, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; function isMessageItem(item: any): item is vscode.MessageItem { return item && item.title; diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index 91b9099a90b..b307608415c 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -10,7 +10,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { checkProposedApiEnabled, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape, NotebookOutputDto } from 'vs/workbench/api/common/extHost.protocol'; import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; @@ -21,7 +21,6 @@ import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConve import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes'; import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as vscode from 'vscode'; diff --git a/src/vs/workbench/api/common/extHostNotebookRenderers.ts b/src/vs/workbench/api/common/extHostNotebookRenderers.ts index 2b18b0d9f26..6e50023991c 100644 --- a/src/vs/workbench/api/common/extHostNotebookRenderers.ts +++ b/src/vs/workbench/api/common/extHostNotebookRenderers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter } from 'vs/base/common/event'; -import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManifest, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { ExtHostNotebookRenderersShape, IMainContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; import { ExtHostNotebookEditor } from 'vs/workbench/api/common/extHostNotebookEditor'; @@ -31,7 +31,7 @@ export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape { // In the stable API, the editor is given as an empty object, and this map // is used to maintain references. This can be removed after editor finalization. - const notebookEditorVisible = !!manifest.enableProposedApi; + const notebookEditorVisible = isProposedApiEnabled(manifest); const notebookEditorAliases = new WeakMap<{}, vscode.NotebookEditor>(); const messaging: vscode.NotebookRendererMessaging = { diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 26dce856bc2..8d7158e8778 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -9,8 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { Disposable } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionDescription, checkProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; import { OutputChannelUpdateMode } from 'vs/workbench/contrib/output/common/output'; import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer'; diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 9db4f1ac9c8..11aa457b084 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -16,8 +16,7 @@ import type * as vscode from 'vscode'; import { ISplice } from 'vs/base/common/sequence'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { checkProposedApiEnabled, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { MarshalledId } from 'vs/base/common/marshalling'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IMarkdownString } from 'vs/base/common/htmlContent'; diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 805f160947f..29e02c1c08b 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -16,6 +16,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { Iterable } from 'vs/base/common/iterator'; import { index } from 'vs/base/common/arrays'; +import { isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; interface IAPIMenu { readonly key: string; @@ -633,7 +634,7 @@ commandsExtensionPoint.setHandler(extensions => { title, source: extension.description.displayName ?? extension.description.name, shortTitle, - tooltip: extension.description.enableProposedApi ? title : undefined, + tooltip: isProposedApiEnabled(extension.description) ? title : undefined, category, precondition: ContextKeyExpr.deserialize(enablement), icon: absoluteIcon @@ -763,7 +764,7 @@ menusExtensionPoint.setHandler(extensions => { return; } - if (menu.proposed && !extension.description.enableProposedApi) { + if (menu.proposed && !isProposedApiEnabled(extension.description)) { collector.error(localize('proposedAPI.invalid', "{0} is a proposed menu identifier and is only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", entry.key, extension.description.identifier.value)); return; } diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 206a61c1b42..5acad42f25c 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -21,7 +21,7 @@ import { AutomaticPortForwarding, ForwardedPortsView, PortRestore, VIEWLET_ID } import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewDescriptor, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, IViewDescriptorService } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -498,7 +498,7 @@ export class RemoteViewPaneContainer extends FilterViewPaneContainer implements } private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser, helpInformation: HelpInformation[]) { - if (!extension.description.enableProposedApi) { + if (!isProposedApiEnabled(extension.description)) { return; } diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts index f07c1184d4e..a9ef766660e 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts @@ -11,6 +11,7 @@ import { IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/exte import { ViewsWelcomeExtensionPoint, ViewWelcome, ViewIdentifierMap } from './viewsWelcomeExtensionPoint'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as ViewContainerExtensions, IViewContentDescriptor, IViewsRegistry } from 'vs/workbench/common/views'; +import { isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; const viewsRegistry = Registry.as(ViewContainerExtensions.ViewsRegistry); @@ -72,7 +73,7 @@ function parseGroupAndOrder(welcome: ViewWelcome, contribution: IExtensionPointU let group: string | undefined; let order: number | undefined; if (welcome.group) { - if (!contribution.description.enableProposedApi) { + if (!isProposedApiEnabled(contribution.description)) { contribution.collector.warn(nls.localize('ViewsWelcomeExtensionPoint.proposedAPI', "The viewsWelcome contribution in '{0}' requires 'enableProposedApi' to be enabled.", contribution.description.identifier.value)); return { group, order }; } diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 9713a42faa4..ce65f021533 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -319,12 +319,6 @@ export interface ProfileSession { stop(): Promise; } -export function checkProposedApiEnabled(extension: IExtensionDescription): void { - if (!extension.enableProposedApi) { - throw new Error(`[${extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.identifier.value}`); - } -} - export function toExtension(extensionDescription: IExtensionDescription): IExtension { return { type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User, diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index e4b4985aa02..43a42e6001c 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -13,7 +13,7 @@ import { MainThreadTelemetryShape, IInitData } from 'vs/workbench/api/common/ext import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; import { LogLevel, createHttpPatch, ProxyResolveEvent, createProxyResolver, createTlsPatch, ProxySupportSetting } from 'vscode-proxy-agent'; export function connectProxyResolver( @@ -129,7 +129,7 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku } if (!cache[request]) { let mod = modules.default; - if (ext && ext.enableProposedApi) { + if (ext && isProposedApiEnabled(ext)) { mod = (modules as any)[(ext).proxySupport] || modules.onRequest; } cache[request] = { ...mod }; // Copy to work around #93167. diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 7d2afcf6724..54112c8b342 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -21,6 +21,7 @@ import { match } from 'vs/base/common/glob'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; const resourceLabelFormattersExtPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'resourceLabelFormatters', @@ -83,7 +84,7 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution { constructor(@ILabelService labelService: ILabelService) { resourceLabelFormattersExtPoint.setHandler((extensions, delta) => { delta.added.forEach(added => added.value.forEach(formatter => { - if (!added.description.enableProposedApi && formatter.formatting.workspaceTooltip) { + if (!isProposedApiEnabled(added.description) && formatter.formatting.workspaceTooltip) { // workspaceTooltip is only proposed formatter.formatting.workspaceTooltip = undefined; } diff --git a/src/vs/workbench/services/themes/common/iconExtensionPoint.ts b/src/vs/workbench/services/themes/common/iconExtensionPoint.ts index 586122a58e4..152345e43f9 100644 --- a/src/vs/workbench/services/themes/common/iconExtensionPoint.ts +++ b/src/vs/workbench/services/themes/common/iconExtensionPoint.ts @@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { CSSIcon } from 'vs/base/common/codicons'; import { fontIdRegex } from 'vs/workbench/services/themes/common/productIconThemeSchema'; import * as resources from 'vs/base/common/resources'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, isProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; interface IIconExtensionPoint { id: string; @@ -125,7 +125,7 @@ export class IconExtensionPoint { const extensionValue = extension.value; const collector = extension.collector; - if (!extension.description.enableProposedApi) { + if (!isProposedApiEnabled(extension.description)) { collector.error(nls.localize('invalid.icons.proposedAPI', "'configuration.icons is a proposed contribution point and only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value)); return; } @@ -179,7 +179,7 @@ export class IconFontExtensionPoint { const extensionValue = extension.value; const collector = extension.collector; - if (!extension.description.enableProposedApi) { + if (!isProposedApiEnabled(extension.description)) { collector.error(nls.localize('invalid.iconFonts.proposedAPI', "'configuration.iconFonts is a proposed contribution point and only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value)); return; } From 2bd6e0089637296827528d8ea9dfbc9940ef6fb2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 14:45:29 +0100 Subject: [PATCH 39/83] fix #136731 --- src/vs/workbench/api/common/extHostOutput.ts | 47 +++++++------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 8d7158e8778..551bbb17973 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -146,57 +146,44 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { } private createExtHostOutputChannel(name: string, channelPromise: Promise, extensionDescription: IExtensionDescription): vscode.OutputChannel { - const validate = (channel: ExtHostOutputChannel, checkProposedApi?: boolean) => { + let disposed = false; + const validate = (checkProposedApi?: boolean) => { if (checkProposedApi) { checkProposedApiEnabled(extensionDescription); } - if (channel.disposed) { + if (disposed) { throw new Error('Channel has been closed'); } }; return { get name(): string { return name; }, append(value: string): void { - channelPromise.then(channel => { - validate(channel); - channel.append(value); - }); + validate(); + channelPromise.then(channel => channel.append(value)); }, appendLine(value: string): void { - channelPromise.then(channel => { - validate(channel); - channel.appendLine(value); - }); + validate(); + channelPromise.then(channel => channel.appendLine(value)); }, clear(): void { - channelPromise.then(channel => { - validate(channel); - channel.clear(); - }); + validate(); + channelPromise.then(channel => channel.clear()); }, replace(value: string): void { - channelPromise.then(channel => { - validate(channel, true); - channel.replace(value); - }); + validate(true); + channelPromise.then(channel => channel.replace(value)); }, show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void { - channelPromise.then(channel => { - validate(channel); - channel.show(columnOrPreserveFocus, preserveFocus); - }); + validate(); + channelPromise.then(channel => channel.show(columnOrPreserveFocus, preserveFocus)); }, hide(): void { - channelPromise.then(channel => { - validate(channel); - channel.hide(); - }); + validate(); + channelPromise.then(channel => channel.hide()); }, dispose(): void { - channelPromise.then(channel => { - validate(channel); - channel.dispose(); - }); + disposed = true; + channelPromise.then(channel => channel.dispose()); } }; } From d7ee56c4a5436eed4fb3c8520896ae79ae8c2c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 13:27:29 +0100 Subject: [PATCH 40/83] style: :lipstick: --- src/vs/base/browser/ui/table/tableWidget.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts index c6c174c0d4b..0bb72ca5e6b 100644 --- a/src/vs/base/browser/ui/table/tableWidget.ts +++ b/src/vs/base/browser/ui/table/tableWidget.ts @@ -9,7 +9,7 @@ import { IListOptions, IListOptionsUpdate, IListStyles, List } from 'vs/base/bro import { ISplitViewDescriptor, IView, Orientation, SplitView } from 'vs/base/browser/ui/splitview/splitview'; import { ITableColumn, ITableContextMenuEvent, ITableEvent, ITableGestureEvent, ITableMouseEvent, ITableRenderer, ITableTouchEvent, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; import { ISpliceable } from 'vs/base/common/sequence'; import { IThemable } from 'vs/base/common/styler'; @@ -148,9 +148,9 @@ export class Table implements ISpliceable, IThemable, IDisposable { readonly domNode: HTMLElement; private splitview: SplitView; private list: List; - private columnLayoutDisposable: IDisposable; private cachedHeight: number = 0; private styleElement: HTMLStyleElement; + private disposables = new DisposableStore(); get onDidChangeFocus(): Event> { return this.list.onDidChangeFocus; } get onDidChangeSelection(): Event> { return this.list.onDidChangeSelection; } @@ -196,21 +196,21 @@ export class Table implements ISpliceable, IThemable, IDisposable { views: headers.map(view => ({ size: view.column.weight, view })) }; - this.splitview = new SplitView(this.domNode, { + this.splitview = this.disposables.add(new SplitView(this.domNode, { orientation: Orientation.HORIZONTAL, scrollbarVisibility: ScrollbarVisibility.Hidden, getSashOrthogonalSize: () => this.cachedHeight, descriptor - }); + })); this.splitview.el.style.height = `${virtualDelegate.headerRowHeight}px`; this.splitview.el.style.lineHeight = `${virtualDelegate.headerRowHeight}px`; const renderer = new TableListRenderer(columns, renderers, i => this.splitview.getViewSize(i)); - this.list = new List(user, this.domNode, asListVirtualDelegate(virtualDelegate), [renderer], _options); + this.list = this.disposables.add(new List(user, this.domNode, asListVirtualDelegate(virtualDelegate), [renderer], _options)); - this.columnLayoutDisposable = Event.any(...headers.map(h => h.onDidLayout)) - (([index, size]) => renderer.layoutColumn(index, size)); + Event.any(...headers.map(h => h.onDidLayout)) + (([index, size]) => renderer.layoutColumn(index, size), null, this.disposables); this.styleElement = createStyleSheet(this.domNode); this.style({}); @@ -337,8 +337,6 @@ export class Table implements ISpliceable, IThemable, IDisposable { } dispose(): void { - this.splitview.dispose(); - this.list.dispose(); - this.columnLayoutDisposable.dispose(); + this.disposables.dispose(); } } From 1c230ef1e3985ece7b1bf9b1e3d37bae437b9732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 15:01:30 +0100 Subject: [PATCH 41/83] fix(table): :bug: double clicking sashes should restore column's size Closes: #117398 --- src/vs/base/browser/ui/table/tableWidget.ts | 13 +++++++++++-- src/vs/platform/list/browser/listService.ts | 2 -- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts index 0bb72ca5e6b..eb298a582c7 100644 --- a/src/vs/base/browser/ui/table/tableWidget.ts +++ b/src/vs/base/browser/ui/table/tableWidget.ts @@ -148,9 +148,11 @@ export class Table implements ISpliceable, IThemable, IDisposable { readonly domNode: HTMLElement; private splitview: SplitView; private list: List; - private cachedHeight: number = 0; private styleElement: HTMLStyleElement; - private disposables = new DisposableStore(); + protected readonly disposables = new DisposableStore(); + + private cachedWidth: number = 0; + private cachedHeight: number = 0; get onDidChangeFocus(): Event> { return this.list.onDidChangeFocus; } get onDidChangeSelection(): Event> { return this.list.onDidChangeSelection; } @@ -212,6 +214,12 @@ export class Table implements ISpliceable, IThemable, IDisposable { Event.any(...headers.map(h => h.onDidLayout)) (([index, size]) => renderer.layoutColumn(index, size), null, this.disposables); + this.splitview.onDidSashReset(index => { + const totalWeight = columns.reduce((r, c) => r + c.weight, 0); + const size = columns[index].weight / totalWeight * this.cachedWidth; + this.splitview.resizeView(index, size); + }, null, this.disposables); + this.styleElement = createStyleSheet(this.domNode); this.style({}); } @@ -248,6 +256,7 @@ export class Table implements ISpliceable, IThemable, IDisposable { height = height ?? getContentHeight(this.domNode); width = width ?? getContentWidth(this.domNode); + this.cachedWidth = width; this.cachedHeight = height; this.splitview.layout(width); diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 875f8dc075f..3c14449399f 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -484,7 +484,6 @@ export class WorkbenchTable extends Table { private horizontalScrolling: boolean | undefined; private _styler: IDisposable | undefined; private _useAltAsMultipleSelectionModifier: boolean; - private readonly disposables: DisposableStore; private navigator: TableResourceNavigator; get onDidOpen(): Event> { return this.navigator.onDidOpen; } @@ -513,7 +512,6 @@ export class WorkbenchTable extends Table { } ); - this.disposables = new DisposableStore(); this.disposables.add(workbenchListOptionsDisposable); this.contextKeyService = createScopedContextKeyService(contextKeyService, this); From f18b29e132039246caebd4c6b52fcff06265c04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 15:11:11 +0100 Subject: [PATCH 42/83] fix(scm): :bug: do not await git repo status, just give the repo straight up to scm on repo discovery, the git extension would run `git status` and wait for that to finish before handing out the repository to scm. this was problematic since the scm default repo selection depends on repos being discovered in a timely fashion. there's no reason not to just hand out the repo to scm and let `git status` finish afterwards Closes: #120089 Closes: #113803 --- extensions/git/src/model.ts | 2 +- .../workbench/contrib/scm/browser/scmViewService.ts | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 9a2f9197378..a57e5f73fac 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -300,7 +300,7 @@ export class Model implements IRemoteSourceProviderRegistry, IPushErrorHandlerRe const repository = new Repository(this.git.open(repositoryRoot, dotGit), this, this, this.globalState, this.outputChannel); this.open(repository); - await repository.status(); + repository.status(); // do not await this, we want SCM to know about the repo asap } catch (ex) { // noop this.outputChannel.appendLine(`Opening repository for path='${repoPath}' failed; ex=${ex}`); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewService.ts b/src/vs/workbench/contrib/scm/browser/scmViewService.ts index f157881dc8c..6b4f6b471ad 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewService.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewService.ts @@ -100,8 +100,7 @@ export class SCMViewService implements ISCMViewService { constructor( @ISCMService private readonly scmService: ISCMService, @IInstantiationService instantiationService: IInstantiationService, - @IStorageService private readonly storageService: IStorageService, - @ILogService private readonly logService: ILogService + @IStorageService private readonly storageService: IStorageService ) { this.menus = instantiationService.createInstance(SCMMenus); @@ -123,8 +122,6 @@ export class SCMViewService implements ISCMViewService { } private onDidAddRepository(repository: ISCMRepository): void { - this.logService.trace('SCMViewService#onDidAddRepository', getProviderStorageKey(repository.provider)); - if (!this.didFinishLoading) { this.eventuallyFinishLoading(); } @@ -135,8 +132,6 @@ export class SCMViewService implements ISCMViewService { const index = this.previousState.all.indexOf(getProviderStorageKey(repository.provider)); if (index === -1) { // saw a repo we did not expect - this.logService.trace('SCMViewService#onDidAddRepository', 'This is a new repository, so we stop the heuristics'); - const added: ISCMRepository[] = []; for (const repo of this.scmService.repositories) { // all should be visible if (!this._visibleRepositoriesSet.has(repo)) { @@ -179,8 +174,6 @@ export class SCMViewService implements ISCMViewService { } private onDidRemoveRepository(repository: ISCMRepository): void { - this.logService.trace('SCMViewService#onDidRemoveRepository', getProviderStorageKey(repository.provider)); - if (!this.didFinishLoading) { this.eventuallyFinishLoading(); } @@ -257,7 +250,6 @@ export class SCMViewService implements ISCMViewService { @debounce(2000) private eventuallyFinishLoading(): void { - this.logService.trace('SCMViewService#eventuallyFinishLoading'); this.finishLoading(); } @@ -266,7 +258,6 @@ export class SCMViewService implements ISCMViewService { return; } - this.logService.trace('SCMViewService#finishLoading'); this.didFinishLoading = true; this.previousState = undefined; } From d019c24d5e0fb84d8a0cd98ebb7588aa830ab6ee Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 06:11:35 -0800 Subject: [PATCH 43/83] Use base _rows not rows when setting fixed --- .../terminal/browser/terminalInstance.ts | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 01e8691e2d2..820c5c37d6e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1650,15 +1650,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._initDimensions(); await this._resize(); } else { - // let maxLineLength = 0; - // if (!this.xterm.raw.buffer.active.getLine(0)) { - // return; - // } - // for (let i = this.xterm.raw.buffer.active.length - 1; i >= this.xterm.raw.buffer.active.viewportY; i--) { - // const lineInfo = this._getWrappedLineCount(i, this.xterm.raw.buffer.active); - // maxLineLength = Math.max(maxLineLength, ((lineInfo.lineCount * this.xterm.raw.cols) - lineInfo.endSpaces) || 0); - // i = lineInfo.currentIndex; - // } // Fixed columns should be at least xterm.js' regular column count const proposedCols = Math.max(this.maxCols, Math.min(this.xterm.getLongestViewportWrappedLineLength(), Constants.MaxSupportedCols)); // Don't switch to fixed dimensions if the content already fits as it makes the scroll @@ -1688,7 +1679,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._hasScrollBar = true; this._initDimensions(); // Always remove a row to make room for the scroll bar - this._fixedRows = this.rows - 1; + this._fixedRows = this._rows - 1; await this._resize(); this._terminalHasFixedWidth.set(true); if (!this._horizontalScrollbar) { @@ -1727,29 +1718,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._container.appendChild(this._wrapperElement); } - // TODO: Move into XtermTerminal and write tests - // private _getWrappedLineCount(index: number, buffer: IBuffer): { lineCount: number, currentIndex: number, endSpaces: number } { - // let line = buffer.getLine(index); - // if (!line) { - // throw new Error('Could not get line'); - // } - // let currentIndex = index; - // let endSpaces = 0; - // // line.length may exceed cols as it doesn't necessarily trim the backing array on resize - // for (let i = Math.min(line.length, this.xterm!.raw.cols) - 1; i >= 0; i--) { - // if (line && !line?.getCell(i)?.getChars()) { - // endSpaces++; - // } else { - // break; - // } - // } - // while (line?.isWrapped && currentIndex > 0) { - // currentIndex--; - // line = buffer.getLine(currentIndex); - // } - // return { lineCount: index - currentIndex + 1, currentIndex, endSpaces }; - // } - private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { this._shellLaunchConfig.args = shellLaunchConfig.args; this._shellLaunchConfig.cwd = shellLaunchConfig.cwd; From bf14040d7f81af2b4d0936682cc2416b492b7678 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 15:11:56 +0100 Subject: [PATCH 44/83] Fix #136732 --- .../contrib/logs/common/logs.contribution.ts | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 20eabfbdff4..aef0c3f87a1 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -15,7 +15,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IFileService, whenProviderRegistered } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { IOutputChannelRegistry, Extensions as OutputExt } from 'vs/workbench/services/output/common/output'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; @@ -24,8 +24,9 @@ import { LogsDataCleaner } from 'vs/workbench/contrib/logs/common/logsDataCleane import { IOutputService } from 'vs/workbench/contrib/output/common/output'; import { supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IProductService } from 'vs/platform/product/common/productService'; -import { timeout } from 'vs/base/common/async'; -import { getErrorMessage } from 'vs/base/common/errors'; +import { createCancelablePromise, timeout } from 'vs/base/common/async'; +import { canceled, getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; +import { CancellationToken } from 'vs/base/common/cancellation'; const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(SetLogLevelAction), 'Developer: Set Log Level...', CATEGORIES.Developer.value); @@ -99,24 +100,31 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { await whenProviderRegistered(file, this.fileService); const outputChannelRegistry = Registry.as(OutputExt.OutputChannels); try { - await this.whenFileExists(file, 1); + const promise = createCancelablePromise(token => this.whenFileExists(file, 1, token)); + this._register(toDisposable(() => promise.cancel())); + await promise; outputChannelRegistry.registerChannel({ id, label, file, log: true }); } catch (error) { - this.logService.error('Error while registering log channel', file.toString(), getErrorMessage(error)); + if (!isPromiseCanceledError(error)) { + this.logService.error('Error while registering log channel', file.toString(), getErrorMessage(error)); + } } } - private async whenFileExists(file: URI, trial: number): Promise { + private async whenFileExists(file: URI, trial: number, token: CancellationToken): Promise { const exists = await this.fileService.exists(file); if (exists) { return; } + if (token.isCancellationRequested) { + throw canceled(); + } if (trial > 10) { throw new Error(`Timed out while waiting for file to be created`); } this.logService.debug(`[Registering Log Channel] File does not exist. Waiting for 1s to retry.`, file.toString()); - await timeout(1000); - await this.whenFileExists(file, trial + 1); + await timeout(1000, token); + await this.whenFileExists(file, trial + 1, token); } } From 200309273045f4319433ef0012f77ecd1b42c376 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 06:19:58 -0800 Subject: [PATCH 45/83] Tweak z-index so split pane sash is above everything --- src/vs/workbench/contrib/terminal/browser/media/terminal.css | 4 ++-- src/vs/workbench/contrib/terminal/browser/media/widgets.css | 2 +- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 07b3b70a9c6..33f5df34ea6 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -63,12 +63,12 @@ .monaco-workbench .editor-instance .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { - z-index: 100; + z-index: 30; } .monaco-workbench .editor-instance .xterm-screen, .monaco-workbench .pane-body.integrated-terminal .xterm-screen { - z-index: 101; + z-index: 31; } .xterm .xterm-screen { diff --git a/src/vs/workbench/contrib/terminal/browser/media/widgets.css b/src/vs/workbench/contrib/terminal/browser/media/widgets.css index 56704ea529b..3ed2086bebe 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/widgets.css +++ b/src/vs/workbench/contrib/terminal/browser/media/widgets.css @@ -31,7 +31,7 @@ width: 28px; height: 28px; text-align: center; - z-index: 102; + z-index: 32; opacity: 0.5; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 820c5c37d6e..bc58ba70462 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -443,7 +443,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } - const computedStyle = window.getComputedStyle(this._wrapperElement!); + const computedStyle = window.getComputedStyle(this._container); const width = parseInt(computedStyle.width); const height = parseInt(computedStyle.height); @@ -1679,6 +1679,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._hasScrollBar = true; this._initDimensions(); // Always remove a row to make room for the scroll bar + console.log('_rows', this._rows); this._fixedRows = this._rows - 1; await this._resize(); this._terminalHasFixedWidth.set(true); From bc9b6d1295bf9c4ddae48e1499170764b92c506c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 06:20:12 -0800 Subject: [PATCH 46/83] Clean up css --- .../contrib/terminal/browser/media/terminal.css | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 33f5df34ea6..e915f053e8d 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -103,15 +103,6 @@ padding-right: 20px; } -/* .monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .terminal-wrapper, -.monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:first-child .terminal-wrapper { - margin-left: 20px; -} -.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .terminal-wrapper, -.monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .terminal-wrapper { - margin-right: 20px; -} */ - .monaco-workbench .editor-instance .xterm a:not(.xterm-invalid-link), .monaco-workbench .pane-body.integrated-terminal .xterm a:not(.xterm-invalid-link) { /* To support message box sizing */ @@ -121,10 +112,6 @@ .monaco-workbench .editor-instance .terminal-wrapper > div, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper > div { height: 100%; - /* TODO: Align to bottom */ - /* Align the viewport and canvases to the bottom of the panel */ - /* display: flex; - align-items: flex-end; */ } .monaco-workbench .editor-instance .xterm-viewport, From 9bdefa7e9dfc9ab7d0e95da998899f20487974c5 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 06:31:22 -0800 Subject: [PATCH 47/83] Further clean up --- .../terminal/browser/media/terminal.css | 29 ++++++------------- .../terminal/browser/terminalInstance.ts | 4 +-- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index e915f053e8d..bd605002ca4 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -40,20 +40,19 @@ .monaco-workbench .editor-instance .terminal-wrapper, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper { display: none; - /* margin: 0 10px; */ height: 100%; - /* padding-bottom: 2px; */ box-sizing: border-box; } .monaco-workbench .editor-instance .xterm, .monaco-workbench .pane-body.integrated-terminal .xterm { + /* All terminals have at least 10px left/right edge padding and 2 padding on the bottom (so underscores on last line are visible */ padding: 0 10px 2px; /* Bottom align the terminal withing the split pane */ position: absolute; - bottom: 0; - left: 0; - right: 0; + bottom: 0; + left: 0; + right: 0; } .monaco-workbench .editor-instance .terminal-wrapper.fixed-dims .xterm, @@ -72,22 +71,13 @@ } .xterm .xterm-screen { - cursor: text; -} - -.xterm.enable-mouse-events .xterm-screen { - /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ - cursor: default; -} - -.xterm.xterm-cursor-pointer .xterm-screen { - cursor: pointer; + cursor: text; } -.xterm.column-select.focus .xterm-screen { - /* Column selection mode */ - cursor: crosshair; -} +/* Apply cursor styles to xterm-screen as well due to how .xterm-viewport/.xterm are positioned */ +.xterm.enable-mouse-events .xterm-screen { cursor: default; } +.xterm.xterm-cursor-pointer .xterm-screen { cursor: pointer; } +.xterm.column-select.focus .xterm-screen { cursor: crosshair; } .monaco-workbench .editor-instance .terminal-wrapper.active, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.active { @@ -125,7 +115,6 @@ position: relative; } -/* TODO: Add class for fixed dimensions */ .monaco-workbench .editor-instance .terminal-wrapper:not(.fixed-dims) .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper:not(.fixed-dims) .xterm-viewport { /* Override xterm.js' width as we want to size the viewport to fill the panel so the scrollbar is on the right edge */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index bc58ba70462..b59e904c056 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1679,7 +1679,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._hasScrollBar = true; this._initDimensions(); // Always remove a row to make room for the scroll bar - console.log('_rows', this._rows); this._fixedRows = this._rows - 1; await this._resize(); this._terminalHasFixedWidth.set(true); @@ -1695,8 +1694,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } this._horizontalScrollbar.setScrollDimensions({ width: this.xterm.raw.element.clientWidth, - // TODO: Use const/property for padding - scrollWidth: this._fixedCols * charWidth + 40 + scrollWidth: this._fixedCols * charWidth + 40 // Padding + scroll bar }); this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; From 7a938550cf6a975ba3975dc7e932557b601252c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 15:34:19 +0100 Subject: [PATCH 48/83] refactor: :coffin: remove dead code --- src/vs/base/browser/ui/sash/sash.ts | 18 ------------------ src/vs/editor/contrib/zoneWidget/zoneWidget.ts | 1 - 2 files changed, 19 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 334b238ed94..aa9bcfffc0a 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -163,7 +163,6 @@ export class Sash extends Disposable { private el: HTMLElement; private layoutProvider: ISashLayoutProvider; - private hidden: boolean; private orientation!: Orientation; private size: number; private hoverDelay = globalHoverDelay; @@ -317,7 +316,6 @@ export class Sash extends Disposable { this._register(onDidChangeHoverDelay.event(delay => this.hoverDelay = delay)); - this.hidden = false; this.layoutProvider = layoutProvider; this.orthogonalStartSash = options.orthogonalStartSash; @@ -504,22 +502,6 @@ export class Sash extends Disposable { } } - show(): void { - this.hidden = false; - this.el.style.removeProperty('display'); - this.el.setAttribute('aria-hidden', 'false'); - } - - hide(): void { - this.hidden = true; - this.el.style.display = 'none'; - this.el.setAttribute('aria-hidden', 'true'); - } - - isHidden(): boolean { - return this.hidden; - } - private getOrthogonalSash(e: PointerEvent): Sash | undefined { if (!e.target || !(e.target instanceof HTMLElement)) { return undefined; diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index cf1a2e73370..671f8e39ad3 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -491,7 +491,6 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this._resizeSash = this._disposables.add(new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL })); if (!this.options.isResizeable) { - this._resizeSash.hide(); this._resizeSash.state = SashState.Disabled; } From 5417e2aea2cd107054784e5c85a544c8be53c650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 9 Nov 2021 15:37:02 +0100 Subject: [PATCH 49/83] remove unused import --- src/vs/workbench/contrib/scm/browser/scmViewService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/scm/browser/scmViewService.ts b/src/vs/workbench/contrib/scm/browser/scmViewService.ts index 6b4f6b471ad..78ac23a1588 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewService.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewService.ts @@ -11,7 +11,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { SCMMenus } from 'vs/workbench/contrib/scm/browser/menus'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { debounce } from 'vs/base/common/decorators'; -import { ILogService } from 'vs/platform/log/common/log'; function getProviderStorageKey(provider: ISCMProvider): string { return `${provider.contextValue}:${provider.label}${provider.rootUri ? `:${provider.rootUri.toString()}` : ''}`; From 4b5611b433460a6e2735c8d50756045de127fb5b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 9 Nov 2021 15:40:23 +0100 Subject: [PATCH 50/83] fix #136734 --- .../workbench/electron-sandbox/parts/dialogs/dialogHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts index 40094f38189..a4728e73b7d 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts @@ -166,8 +166,8 @@ export class NativeDialogHandler implements IDialogHandler { const osProps = await this.nativeHostService.getOSProperties(); const detailString = (useAgo: boolean): string => { - return localize({ key: 'aboutDetail', comment: ['Electron, Chrome, Node.js and V8 are product names that need no translation'] }, - "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", + return localize({ key: 'aboutDetail', comment: ['Electron, Chromium, Node.js and V8 are product names that need no translation'] }, + "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChromium: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", version, this.productService.commit || 'Unknown', this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', From 93ce4397a2cbc88707c3ed8b34a813b87457568c Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 9 Nov 2021 15:47:17 +0100 Subject: [PATCH 51/83] Bump distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e0c2e6edd8..ea5df190b60 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.63.0", - "distro": "f4a21145f5ec390f681f48c7140bf4f60d2987ac", + "distro": "58644f0352f74eff29f9d920573b8e6fffb1cfac", "author": { "name": "Microsoft Corporation" }, From 918ebda21b9c2dda0c3f0b64321da7b2e77057f1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 06:48:17 -0800 Subject: [PATCH 52/83] Don't stop wheel event propagation --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index b59e904c056..99b0ebec471 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -771,13 +771,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { xterm.raw.focus(); })); - this._register(dom.addDisposableListener(xterm.raw.element, 'wheel', (e) => { - if (this._hasScrollBar && e.shiftKey) { - e.stopImmediatePropagation(); - e.preventDefault(); - } - })); - // xterm.js currently drops selection on keyup as we need to handle this case. this._register(dom.addDisposableListener(xterm.raw.element, 'keyup', () => { // Wait until keyup has propagated through the DOM before evaluating From fc9167052f5167d27866f95f2a0420abb58d20b4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 07:26:14 -0800 Subject: [PATCH 53/83] Only use isWrapped workaround on Windows --- .../contrib/terminal/browser/terminalInstance.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 99b0ebec471..21b0350a611 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1692,9 +1692,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._horizontalScrollbar.getDomNode().style.paddingBottom = '16px'; // work around for https://github.com/xtermjs/xterm.js/issues/3482 - for (let i = this.xterm.raw.buffer.active.viewportY; i < this.xterm.raw.buffer.active.length; i++) { - let line = this.xterm.raw.buffer.active.getLine(i); - (line as any)._line.isWrapped = false; + if (isWindows) { + for (let i = this.xterm.raw.buffer.active.viewportY; i < this.xterm.raw.buffer.active.length; i++) { + let line = this.xterm.raw.buffer.active.getLine(i); + (line as any)._line.isWrapped = false; + } } } From dd8a0996e83bd7ed77c447c14589c8240ceefe6a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 07:35:57 -0800 Subject: [PATCH 54/83] Ignore errors when terminal is disposed during fetching xterm ctor Fixes #135002 --- .../contrib/terminal/browser/terminalInstance.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 21b0350a611..8e1db030c63 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -365,6 +365,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._fixedCols) { await this._addScrollbar(); } + }).catch((err) => { + // Ignore exceptions if the terminal is already disposed + if (!this._isDisposed) { + throw err; + } }); this.addDisposable(this._configurationService.onDidChangeConfiguration(async e => { @@ -551,8 +556,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { */ protected async _createXterm(): Promise { const Terminal = await this._getXtermConstructor(); + if (this._isDisposed) { + throw new Error('Terminal disposed of during xterm.js creation'); + } - // TODO: Move cols/rows over to XtermTerminal const xterm = this._instantiationService.createInstance(XtermTerminal, Terminal, this._configHelper, this._cols, this._rows); this.xterm = xterm; const lineDataEventAddon = new LineDataEventAddon(); From a9bf40f2176505f7bff1fd60c665707d5b3fff0e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 07:56:33 -0800 Subject: [PATCH 55/83] Update xterm Commit: 0bc02d6838a2a75048001003617bf172efcf622b --- package.json | 12 ++++----- remote/package.json | 12 ++++----- remote/web/package.json | 8 +++--- remote/web/yarn.lock | 38 +++++++++++++-------------- remote/yarn.lock | 58 ++++++++++++++++++++--------------------- yarn.lock | 58 ++++++++++++++++++++--------------------- 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/package.json b/package.json index 7c025a0338b..7c6cf3da05f 100644 --- a/package.json +++ b/package.json @@ -84,12 +84,12 @@ "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.12.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.13", - "xterm-addon-search": "0.9.0-beta.5", - "xterm-addon-serialize": "0.7.0-beta.2", - "xterm-addon-unicode11": "0.3.0", - "xterm-addon-webgl": "0.12.0-beta.15", - "xterm-headless": "4.15.0-beta.13", + "xterm": "4.16.0-beta.2", + "xterm-addon-search": "0.9.0-beta.6", + "xterm-addon-serialize": "0.7.0-beta.3", + "xterm-addon-unicode11": "0.4.0-beta.1", + "xterm-addon-webgl": "0.12.0-beta.16", + "xterm-headless": "4.16.0-beta.2", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index f2659758d02..fe96ab7237f 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,12 +24,12 @@ "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.12.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.13", - "xterm-addon-search": "0.9.0-beta.5", - "xterm-addon-serialize": "0.7.0-beta.2", - "xterm-addon-unicode11": "0.3.0", - "xterm-addon-webgl": "0.12.0-beta.15", - "xterm-headless": "4.15.0-beta.13", + "xterm": "4.16.0-beta.2", + "xterm-addon-search": "0.9.0-beta.6", + "xterm-addon-serialize": "0.7.0-beta.3", + "xterm-addon-unicode11": "0.4.0-beta.1", + "xterm-addon-webgl": "0.12.0-beta.16", + "xterm-headless": "4.16.0-beta.2", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index 1cd5ff1f204..f69e0798f01 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -10,9 +10,9 @@ "tas-client-umd": "0.1.4", "vscode-oniguruma": "1.5.1", "vscode-textmate": "5.4.1", - "xterm": "4.15.0-beta.13", - "xterm-addon-search": "0.9.0-beta.5", - "xterm-addon-unicode11": "0.3.0", - "xterm-addon-webgl": "0.12.0-beta.15" + "xterm": "4.16.0-beta.2", + "xterm-addon-search": "0.9.0-beta.6", + "xterm-addon-unicode11": "0.4.0-beta.1", + "xterm-addon-webgl": "0.12.0-beta.16" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 4d08c124a7a..4bf3abe60b5 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -113,22 +113,22 @@ vscode-textmate@5.4.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.4.1.tgz#09d566724fc76b60b3ad9791eebf1f0b50f29e5a" integrity sha512-4CvPHmfuZQaXrcCpathdh6jo7myuR+MU8BvscgQADuponpbqfmu2rwTOtCXhGwwEgStvJF8V4s9FwMKRVLNmKQ== -xterm-addon-search@0.9.0-beta.5: - version "0.9.0-beta.5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.5.tgz#e0e60a203d1c9d6c8af933648a46865dba299302" - integrity sha512-ylfqim0ISBvuuX83LQwgu/06p5GC545QsAo9SssXw03TPpIrcd0zwaVMEnhOftSIzM9EKRRsyx3GbBjgUdiF5w== - -xterm-addon-unicode11@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0.tgz#e4435c3c91a5294a7eb8b79c380acbb28a659463" - integrity sha512-x5fHDZT2j9tlTlHnzPHt++9uKZ2kJ/lYQOj3L6xJA22xoJsS8UQRw/5YIFg2FUHqEAbV77Z1fZij/9NycMSH/A== - -xterm-addon-webgl@0.12.0-beta.15: - version "0.12.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" - integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== - -xterm@4.15.0-beta.13: - version "4.15.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" - integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== +xterm-addon-search@0.9.0-beta.6: + version "0.9.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.6.tgz#8b016baac5580dc0ba93bb52610bc4f5776d3b17" + integrity sha512-UAEzas4O+NrF7BSGf0C9N5ngAkmbtr/hSTFvLAM/Rw7EfLUatf8aLMqAWZTggRGMwDjuqR0GXJI4+e5QrJhQfw== + +xterm-addon-unicode11@0.4.0-beta.1: + version "0.4.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.1.tgz#aeefd26e87bad15d8dfd8a1e0b804fe408c9b882" + integrity sha512-pG8mpxnqpYDry0e20vuEFKhd4kKIcLLNwdNftNvfo+R/EjYRnTYnF+H8L+7eQHq6hqDH61xCEP4H4qR2CyT4pg== + +xterm-addon-webgl@0.12.0-beta.16: + version "0.12.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.16.tgz#63a0f1f5be9e66286e035448e2011e3065769ad5" + integrity sha512-g6v3RegOhSsD9Zt8ArWBMNT30QyPUlIWEIvP/xLHAluUZ1S5sDjFyZDB0nJAyn9MwQozJpwb0ylYO1nznN/TzA== + +xterm@4.16.0-beta.2: + version "4.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.16.0-beta.2.tgz#251beef21a232143f272da74c7005bc4d832ca79" + integrity sha512-PD0agueJ7qvbn1/QhZriAQXf+ykaoPKgQN9qiIGf88VMxHs8T47MYHW/+qPsrXagTmbrENtncughTIzOzv8Q5Q== diff --git a/remote/yarn.lock b/remote/yarn.lock index 39f0e8f9aac..b63e411e7ec 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -541,35 +541,35 @@ xregexp@2.0.0: resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= -xterm-addon-search@0.9.0-beta.5: - version "0.9.0-beta.5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.5.tgz#e0e60a203d1c9d6c8af933648a46865dba299302" - integrity sha512-ylfqim0ISBvuuX83LQwgu/06p5GC545QsAo9SssXw03TPpIrcd0zwaVMEnhOftSIzM9EKRRsyx3GbBjgUdiF5w== - -xterm-addon-serialize@0.7.0-beta.2: - version "0.7.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.2.tgz#ced9f664c74ab88448e7b63850721bc272aa6806" - integrity sha512-KuSwdx2AAliUv7SvjKYUKHrB7vscbHLv8QsmwSDI3pgL1BpjyLJ8LR99iFFfuNpPW9CG4TX6adKPIJXtqiN3Vg== - -xterm-addon-unicode11@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0.tgz#e4435c3c91a5294a7eb8b79c380acbb28a659463" - integrity sha512-x5fHDZT2j9tlTlHnzPHt++9uKZ2kJ/lYQOj3L6xJA22xoJsS8UQRw/5YIFg2FUHqEAbV77Z1fZij/9NycMSH/A== - -xterm-addon-webgl@0.12.0-beta.15: - version "0.12.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" - integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== - -xterm-headless@4.15.0-beta.13: - version "4.15.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.13.tgz#f9f8e3799209817e89a2961b3fe643d2ed4b71d5" - integrity sha512-csvpnLqaTi9ULNPcIWAh+o5xIswBYuD30fEmnOd6Az1tZhNaZVp27FnI1vszKdZ37DO8SxN7R1agvnz8II9QLw== - -xterm@4.15.0-beta.13: - version "4.15.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" - integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== +xterm-addon-search@0.9.0-beta.6: + version "0.9.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.6.tgz#8b016baac5580dc0ba93bb52610bc4f5776d3b17" + integrity sha512-UAEzas4O+NrF7BSGf0C9N5ngAkmbtr/hSTFvLAM/Rw7EfLUatf8aLMqAWZTggRGMwDjuqR0GXJI4+e5QrJhQfw== + +xterm-addon-serialize@0.7.0-beta.3: + version "0.7.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.3.tgz#a8ce52a59685041bd3b6d6a2a77a3df8bc3daf29" + integrity sha512-fgB0h8JiSN1cOMh3slenysprnGfFwbDZ/D38WA0Pdjxf3YDy4j2SwoUajlvXpkFWR7sHjVHmgpw/nHggO731KA== + +xterm-addon-unicode11@0.4.0-beta.1: + version "0.4.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.1.tgz#aeefd26e87bad15d8dfd8a1e0b804fe408c9b882" + integrity sha512-pG8mpxnqpYDry0e20vuEFKhd4kKIcLLNwdNftNvfo+R/EjYRnTYnF+H8L+7eQHq6hqDH61xCEP4H4qR2CyT4pg== + +xterm-addon-webgl@0.12.0-beta.16: + version "0.12.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.16.tgz#63a0f1f5be9e66286e035448e2011e3065769ad5" + integrity sha512-g6v3RegOhSsD9Zt8ArWBMNT30QyPUlIWEIvP/xLHAluUZ1S5sDjFyZDB0nJAyn9MwQozJpwb0ylYO1nznN/TzA== + +xterm-headless@4.16.0-beta.2: + version "4.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.16.0-beta.2.tgz#62e66a655a30c814e3a311f3542d42c87446cecd" + integrity sha512-g92HDaIZcu1TQFlrjq2CHtt7A2qAwSD6s8RwncU/7u1kaq2e7rc9O3OKfu5v3QzgaRSKuugtquMr0OTKjkmLUg== + +xterm@4.16.0-beta.2: + version "4.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.16.0-beta.2.tgz#251beef21a232143f272da74c7005bc4d832ca79" + integrity sha512-PD0agueJ7qvbn1/QhZriAQXf+ykaoPKgQN9qiIGf88VMxHs8T47MYHW/+qPsrXagTmbrENtncughTIzOzv8Q5Q== yauzl@^2.9.2: version "2.10.0" diff --git a/yarn.lock b/yarn.lock index 20ff629d085..e923691c537 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10874,35 +10874,35 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.9.0-beta.5: - version "0.9.0-beta.5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.5.tgz#e0e60a203d1c9d6c8af933648a46865dba299302" - integrity sha512-ylfqim0ISBvuuX83LQwgu/06p5GC545QsAo9SssXw03TPpIrcd0zwaVMEnhOftSIzM9EKRRsyx3GbBjgUdiF5w== - -xterm-addon-serialize@0.7.0-beta.2: - version "0.7.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.2.tgz#ced9f664c74ab88448e7b63850721bc272aa6806" - integrity sha512-KuSwdx2AAliUv7SvjKYUKHrB7vscbHLv8QsmwSDI3pgL1BpjyLJ8LR99iFFfuNpPW9CG4TX6adKPIJXtqiN3Vg== - -xterm-addon-unicode11@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0.tgz#e4435c3c91a5294a7eb8b79c380acbb28a659463" - integrity sha512-x5fHDZT2j9tlTlHnzPHt++9uKZ2kJ/lYQOj3L6xJA22xoJsS8UQRw/5YIFg2FUHqEAbV77Z1fZij/9NycMSH/A== - -xterm-addon-webgl@0.12.0-beta.15: - version "0.12.0-beta.15" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.15.tgz#9ae82127f2a39b3cb7f5ae45a6af223810c933d4" - integrity sha512-LWZ3iLspQOCc26OoT8qa+SuyuIcn2cAMRbBkinOuQCk4aW5kjovIrGovj9yVAcXNvOBnPm3sUqmnwGlN579kDA== - -xterm-headless@4.15.0-beta.13: - version "4.15.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.15.0-beta.13.tgz#f9f8e3799209817e89a2961b3fe643d2ed4b71d5" - integrity sha512-csvpnLqaTi9ULNPcIWAh+o5xIswBYuD30fEmnOd6Az1tZhNaZVp27FnI1vszKdZ37DO8SxN7R1agvnz8II9QLw== - -xterm@4.15.0-beta.13: - version "4.15.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.15.0-beta.13.tgz#a78af26e7065d64b8b49ab7a606ca63a3189af72" - integrity sha512-kz4U7dPIDxOvAZkXutsjju1cR7rJmOvI0oWXl337d2WnfY8qlnKDgu5DCSlfHSzDH8qaSQodzZaArd0/6RVdiQ== +xterm-addon-search@0.9.0-beta.6: + version "0.9.0-beta.6" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.6.tgz#8b016baac5580dc0ba93bb52610bc4f5776d3b17" + integrity sha512-UAEzas4O+NrF7BSGf0C9N5ngAkmbtr/hSTFvLAM/Rw7EfLUatf8aLMqAWZTggRGMwDjuqR0GXJI4+e5QrJhQfw== + +xterm-addon-serialize@0.7.0-beta.3: + version "0.7.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.3.tgz#a8ce52a59685041bd3b6d6a2a77a3df8bc3daf29" + integrity sha512-fgB0h8JiSN1cOMh3slenysprnGfFwbDZ/D38WA0Pdjxf3YDy4j2SwoUajlvXpkFWR7sHjVHmgpw/nHggO731KA== + +xterm-addon-unicode11@0.4.0-beta.1: + version "0.4.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.1.tgz#aeefd26e87bad15d8dfd8a1e0b804fe408c9b882" + integrity sha512-pG8mpxnqpYDry0e20vuEFKhd4kKIcLLNwdNftNvfo+R/EjYRnTYnF+H8L+7eQHq6hqDH61xCEP4H4qR2CyT4pg== + +xterm-addon-webgl@0.12.0-beta.16: + version "0.12.0-beta.16" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.16.tgz#63a0f1f5be9e66286e035448e2011e3065769ad5" + integrity sha512-g6v3RegOhSsD9Zt8ArWBMNT30QyPUlIWEIvP/xLHAluUZ1S5sDjFyZDB0nJAyn9MwQozJpwb0ylYO1nznN/TzA== + +xterm-headless@4.16.0-beta.2: + version "4.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.16.0-beta.2.tgz#62e66a655a30c814e3a311f3542d42c87446cecd" + integrity sha512-g92HDaIZcu1TQFlrjq2CHtt7A2qAwSD6s8RwncU/7u1kaq2e7rc9O3OKfu5v3QzgaRSKuugtquMr0OTKjkmLUg== + +xterm@4.16.0-beta.2: + version "4.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.16.0-beta.2.tgz#251beef21a232143f272da74c7005bc4d832ca79" + integrity sha512-PD0agueJ7qvbn1/QhZriAQXf+ykaoPKgQN9qiIGf88VMxHs8T47MYHW/+qPsrXagTmbrENtncughTIzOzv8Q5Q== y18n@^3.2.1: version "3.2.2" From a315fd8f2efa1d2aba7d88f9115eabd0d6a30d73 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 16:57:10 +0100 Subject: [PATCH 56/83] #133201 add more logging --- src/vs/platform/userDataSync/common/userDataSyncAccount.ts | 6 ++++-- .../userDataSync/browser/userDataSyncWorkbenchService.ts | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncAccount.ts b/src/vs/platform/userDataSync/common/userDataSyncAccount.ts index 514e3d00e6c..1c5c6894c74 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncAccount.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncAccount.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncLogService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; export interface IUserDataSyncAccount { readonly authenticationProviderId: string; @@ -39,10 +39,12 @@ export class UserDataSyncAccountService extends Disposable implements IUserDataS private wasTokenFailed: boolean = false; constructor( - @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService + @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, + @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, ) { super(); this._register(userDataSyncStoreService.onTokenFailed(() => { + this.logService.info('Settings Sync auth token failed', this.account?.authenticationProviderId, this.wasTokenFailed); this.updateAccount(undefined); this._onTokenFailed.fire(this.wasTokenFailed); this.wasTokenFailed = true; diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 667b02954c4..d156f7dfea1 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -657,8 +657,10 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat if (this._cachedCurrentSessionId !== cachedSessionId) { this._cachedCurrentSessionId = cachedSessionId; if (cachedSessionId === undefined) { + this.logService.info('Settings Sync: Reset current session'); this.storageService.remove(UserDataSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY, StorageScope.GLOBAL); } else { + this.logService.info('Settings Sync: Updated current session', cachedSessionId); this.storageService.store(UserDataSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY, cachedSessionId, StorageScope.GLOBAL, StorageTarget.MACHINE); } } From 1cbf69d996f17e6212516b8c6ded4188e6e20a08 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 08:24:38 -0800 Subject: [PATCH 57/83] Document --headless in smoke tests --- test/smoke/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/test/smoke/README.md b/test/smoke/README.md index 93e35e4c1f7..84c2030a336 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -62,6 +62,7 @@ xattr -d com.apple.quarantine - `--verbose` logs all the low level driver calls made to Code; - `-f PATTERN` (alias `-g PATTERN`) filters the tests to be run. You can also use pretty much any mocha argument; - `--screenshots SCREENSHOT_DIR` captures screenshots when tests fail. +- `--headless` will run playwright in headless mode when `--web` is used. **Note**: you can enable verbose logging of playwright library by setting a `DEBUG` environment variable before running the tests (https://playwright.dev/docs/debug#verbose-api-logs) From 281bacb0748a3bf221e020df2e0b79aa75a6db02 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 08:25:15 -0800 Subject: [PATCH 58/83] Stub out some terminal smoke tests Part of #136064 --- .../areas/terminal/terminal-profiles.test.ts | 20 +++++++++++++++++++ .../terminal/terminal-reconnection.test.ts | 20 +++++++++++++++++++ test/smoke/src/main.ts | 4 ++++ 3 files changed, 44 insertions(+) create mode 100644 test/smoke/src/areas/terminal/terminal-profiles.test.ts create mode 100644 test/smoke/src/areas/terminal/terminal-reconnection.test.ts diff --git a/test/smoke/src/areas/terminal/terminal-profiles.test.ts b/test/smoke/src/areas/terminal/terminal-profiles.test.ts new file mode 100644 index 00000000000..17c5d3d3525 --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal-profiles.test.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ParsedArgs } from 'minimist'; +import { Application } from '../../../../automation'; +import { afterSuite, beforeSuite } from '../../utils'; + +export function setup(opts: ParsedArgs) { + describe.skip('Terminal Profiles', () => { + beforeSuite(opts); + afterSuite(opts); + + it.skip('should launch the default profile', async () => { + const app = this.app as Application; + console.log(app); + }); + }); +} diff --git a/test/smoke/src/areas/terminal/terminal-reconnection.test.ts b/test/smoke/src/areas/terminal/terminal-reconnection.test.ts new file mode 100644 index 00000000000..6a6db40a623 --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal-reconnection.test.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ParsedArgs } from 'minimist'; +import { Application } from '../../../../automation'; +import { afterSuite, beforeSuite } from '../../utils'; + +export function setup(opts: ParsedArgs) { + describe('Terminal Reconnection', () => { + beforeSuite(opts); + afterSuite(opts); + + it.skip('should reconnect to a single terminal on reload', async () => { + const app = this.app as Application; + console.log(app); + }); + }); +} diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index b05d6742d01..7e8a7aef181 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -27,6 +27,7 @@ import { setup as setupDataExtensionTests } from './areas/extensions/extensions. import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test'; import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test'; import { setup as setupLaunchTests } from './areas/workbench/launch.test'; +import { setup as setupTerminalProfileTests } from './areas/terminal/terminal-profiles.test'; const testDataPath = path.join(os.tmpdir(), 'vscsmoke'); if (fs.existsSync(testDataPath)) { @@ -352,4 +353,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (!opts.web) { setupDataMultirootTests(opts); } if (!opts.web) { setupDataLocalizationTests(opts); } if (!opts.web) { setupLaunchTests(); } + + // TODO: Enable terminal tests for non-web + if (opts.web) { setupTerminalProfileTests(opts); } }); From 28da3051b37340e4cbde29e5ef979eac5bd2b4cc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 9 Nov 2021 08:26:39 -0800 Subject: [PATCH 59/83] Tidy up smoke test imports --- test/smoke/src/main.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 7e8a7aef181..54462bd7792 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -17,15 +17,15 @@ import { Quality, ApplicationOptions, MultiLogger, Logger, ConsoleLogger, FileLo import { setup as setupDataMigrationTests } from './areas/workbench/data-migration.test'; import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; -import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test'; -import { setup as setupDataSearchTests } from './areas/search/search.test'; -import { setup as setupDataNotebookTests } from './areas/notebook/notebook.test'; -import { setup as setupDataLanguagesTests } from './areas/languages/languages.test'; -import { setup as setupDataEditorTests } from './areas/editor/editor.test'; -import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test'; -import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test'; -import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test'; -import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test'; +import { setup as setupPreferencesTests } from './areas/preferences/preferences.test'; +import { setup as setupSearchTests } from './areas/search/search.test'; +import { setup as setupNotebookTests } from './areas/notebook/notebook.test'; +import { setup as setupLanguagesTests } from './areas/languages/languages.test'; +import { setup as setupEditorTests } from './areas/editor/editor.test'; +import { setup as setupStatusbarTests } from './areas/statusbar/statusbar.test'; +import { setup as setupExtensionTests } from './areas/extensions/extensions.test'; +import { setup as setupMultirootTests } from './areas/multiroot/multiroot.test'; +import { setup as setupLocalizationTests } from './areas/workbench/localization.test'; import { setup as setupLaunchTests } from './areas/workbench/launch.test'; import { setup as setupTerminalProfileTests } from './areas/terminal/terminal-profiles.test'; @@ -343,15 +343,15 @@ if (!opts.web && opts['build'] && !opts['remote']) { describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (!opts.web) { setupDataLossTests(opts); } - if (!opts.web) { setupDataPreferencesTests(opts); } - setupDataSearchTests(opts); - setupDataNotebookTests(opts); - setupDataLanguagesTests(opts); - setupDataEditorTests(opts); - setupDataStatusbarTests(opts); - setupDataExtensionTests(opts); - if (!opts.web) { setupDataMultirootTests(opts); } - if (!opts.web) { setupDataLocalizationTests(opts); } + if (!opts.web) { setupPreferencesTests(opts); } + setupSearchTests(opts); + setupNotebookTests(opts); + setupLanguagesTests(opts); + setupEditorTests(opts); + setupStatusbarTests(opts); + setupExtensionTests(opts); + if (!opts.web) { setupMultirootTests(opts); } + if (!opts.web) { setupLocalizationTests(opts); } if (!opts.web) { setupLaunchTests(); } // TODO: Enable terminal tests for non-web From 60fe8d955383d946385af0602ce5eba2ca729f69 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 9 Nov 2021 17:31:18 +0100 Subject: [PATCH 60/83] fix #132183 - finalize api --- src/vs/vscode.d.ts | 7 +++++++ src/vs/vscode.proposed.d.ts | 10 ---------- src/vs/workbench/api/common/extHostOutput.ts | 13 +++++-------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 02f02c68f19..f5f66342439 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5656,6 +5656,13 @@ declare module 'vscode' { */ appendLine(value: string): void; + /** + * Replaces all output from the channel with the given value. + * + * @param value A string, falsy values will not be printed. + */ + replace(value: string): void; + /** * Removes all output from the channel. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index f5f1304f3d9..259e42d1d4b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2834,14 +2834,4 @@ declare module 'vscode' { //#endregion - //#region @sandy081 https://github.com/microsoft/vscode/issues/132183 - - export interface OutputChannel { - /* - * Replaces the existing contents of the channel with the given value. - */ - replace(value: string): void; - } - - //#endregion } diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 551bbb17973..186031d7205 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { Disposable } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -import { IExtensionDescription, checkProposedApiEnabled } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; import { OutputChannelUpdateMode } from 'vs/workbench/contrib/output/common/output'; import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer'; @@ -127,7 +127,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { this.channels.set(channel.id, channel); channel.visible = channel.id === this.visibleChannelId; }); - return this.createExtHostOutputChannel(name, extHostOutputChannel, extension); + return this.createExtHostOutputChannel(name, extHostOutputChannel); } private async doCreateOutputChannel(name: string, extension: IExtensionDescription): Promise { @@ -145,12 +145,9 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { return this.outputDirectoryPromise; } - private createExtHostOutputChannel(name: string, channelPromise: Promise, extensionDescription: IExtensionDescription): vscode.OutputChannel { + private createExtHostOutputChannel(name: string, channelPromise: Promise): vscode.OutputChannel { let disposed = false; - const validate = (checkProposedApi?: boolean) => { - if (checkProposedApi) { - checkProposedApiEnabled(extensionDescription); - } + const validate = () => { if (disposed) { throw new Error('Channel has been closed'); } @@ -170,7 +167,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { channelPromise.then(channel => channel.clear()); }, replace(value: string): void { - validate(true); + validate(); channelPromise.then(channel => channel.replace(value)); }, show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void { From 9fbabfcd4c80dcb0ce01b976b6f2236d77cbac4a Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 9 Nov 2021 17:45:51 +0100 Subject: [PATCH 61/83] Implements #136764 by not triggering inline suggestions on undo/redo. --- .../editor/contrib/inlineCompletions/inlineCompletionsModel.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts index 279c419a56c..129a4a9f58f 100644 --- a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts @@ -11,7 +11,6 @@ import { Disposable, IDisposable, MutableDisposable, toDisposable } from 'vs/bas import { commonPrefixLength, commonSuffixLength } from 'vs/base/common/strings'; import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; @@ -43,8 +42,6 @@ export class InlineCompletionsModel extends Disposable implements GhostTextWidge this._register(commandService.onDidExecuteCommand(e => { // These commands don't trigger onDidType. const commands = new Set([ - UndoCommand.id, - RedoCommand.id, CoreEditingCommands.Tab.id, CoreEditingCommands.DeleteLeft.id, CoreEditingCommands.DeleteRight.id, From 9472f261093ca7a1a6ac7b07c03614db2a707b27 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 9 Nov 2021 08:46:26 -0800 Subject: [PATCH 62/83] Fix #136700 --- .../contrib/welcome/gettingStarted/browser/gettingStarted.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css index 26d4d8a30db..85b0163d359 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css @@ -717,6 +717,8 @@ .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .openAWalkthrough>button, .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .showOnStartup { text-align: center; + display: flex; + justify-content: center; } .monaco-workbench .part.editor>.content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox { From d2587206e45be30cc398f3173285f424bb635878 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 4 Nov 2021 22:45:43 +0100 Subject: [PATCH 63/83] Fixes microsoft/monaco-editor#2650: Move scrollbar style participant down to the editor layer --- .../browser/ui/scrollbar/media/scrollbars.css | 58 ------------------- .../editorScrollbar/editorScrollbar.ts | 51 +++++++++++++++- src/vs/workbench/browser/style.ts | 47 +-------------- 3 files changed, 51 insertions(+), 105 deletions(-) diff --git a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css index 5d7a2dc705a..d50aa58526c 100644 --- a/src/vs/base/browser/ui/scrollbar/media/scrollbars.css +++ b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css @@ -36,7 +36,6 @@ left: 3px; height: 3px; width: 100%; - box-shadow: #DDD 0 6px 6px -6px inset; } .monaco-scrollable-element > .shadow.left { display: block; @@ -44,7 +43,6 @@ left: 0; height: 100%; width: 3px; - box-shadow: #DDD 6px 0 6px -6px inset; } .monaco-scrollable-element > .shadow.top-left-corner { display: block; @@ -53,59 +51,3 @@ height: 3px; width: 3px; } -.monaco-scrollable-element > .shadow.top.left { - box-shadow: #DDD 6px 6px 6px -6px inset; -} - -/* ---------- Default Style ---------- */ - -.vs .monaco-scrollable-element > .scrollbar > .slider { - background: rgba(100, 100, 100, .4); -} -.vs-dark .monaco-scrollable-element > .scrollbar > .slider { - background: rgba(121, 121, 121, .4); -} -.hc-black .monaco-scrollable-element > .scrollbar > .slider { - background: rgba(111, 195, 223, .6); -} - -.monaco-scrollable-element > .scrollbar > .slider:hover { - background: rgba(100, 100, 100, .7); -} -.hc-black .monaco-scrollable-element > .scrollbar > .slider:hover { - background: rgba(111, 195, 223, .8); -} - -.monaco-scrollable-element > .scrollbar > .slider.active { - background: rgba(0, 0, 0, .6); -} -.vs-dark .monaco-scrollable-element > .scrollbar > .slider.active { - background: rgba(191, 191, 191, .4); -} -.hc-black .monaco-scrollable-element > .scrollbar > .slider.active { - background: rgba(111, 195, 223, 1); -} - -.vs-dark .monaco-scrollable-element .shadow.top { - box-shadow: none; -} - -.vs-dark .monaco-scrollable-element .shadow.left { - box-shadow: #000 6px 0 6px -6px inset; -} - -.vs-dark .monaco-scrollable-element .shadow.top.left { - box-shadow: #000 6px 6px 6px -6px inset; -} - -.hc-black .monaco-scrollable-element .shadow.top { - box-shadow: none; -} - -.hc-black .monaco-scrollable-element .shadow.left { - box-shadow: none; -} - -.hc-black .monaco-scrollable-element .shadow.top.left { - box-shadow: none; -} diff --git a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts index b7025539667..3736489d8fc 100644 --- a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts +++ b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts @@ -13,8 +13,9 @@ import { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; -import { getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant, getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; export class EditorScrollbar extends ViewPart { @@ -180,3 +181,51 @@ export class EditorScrollbar extends ViewPart { this.scrollbar.renderNow(); } } + +registerThemingParticipant((theme, collector) => { + + // Scrollbars + const scrollbarShadowColor = theme.getColor(scrollbarShadow); + if (scrollbarShadowColor) { + collector.addRule(` + .monaco-scrollable-element > .shadow.top { + box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset; + } + + .monaco-scrollable-element > .shadow.left { + box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset; + } + + .monaco-scrollable-element > .shadow.top.left { + box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset; + } + `); + } + + const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground); + if (scrollbarSliderBackgroundColor) { + collector.addRule(` + .monaco-scrollable-element > .scrollbar > .slider { + background: ${scrollbarSliderBackgroundColor}; + } + `); + } + + const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground); + if (scrollbarSliderHoverBackgroundColor) { + collector.addRule(` + .monaco-scrollable-element > .scrollbar > .slider:hover { + background: ${scrollbarSliderHoverBackgroundColor}; + } + `); + } + + const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground); + if (scrollbarSliderActiveBackgroundColor) { + collector.addRule(` + .monaco-scrollable-element > .scrollbar > .slider.active { + background: ${scrollbarSliderActiveBackgroundColor}; + } + `); + } +}); diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index 6971905465e..d7472ac31b2 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/style'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground, toolbarHoverBackground, toolbarActiveBackground, toolbarHoverOutline, listFocusHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; +import { iconForeground, foreground, selectionBackground, focusBorder, listHighlightForeground, inputPlaceholderForeground, toolbarHoverBackground, toolbarActiveBackground, toolbarHoverOutline, listFocusHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { isWeb, isIOS, isMacintosh, isWindows } from 'vs/base/common/platform'; import { createMetaElement } from 'vs/base/browser/dom'; @@ -71,51 +71,6 @@ registerThemingParticipant((theme, collector) => { `); } - // Scrollbars - const scrollbarShadowColor = theme.getColor(scrollbarShadow); - if (scrollbarShadowColor) { - collector.addRule(` - .monaco-workbench .monaco-scrollable-element > .shadow.top { - box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset; - } - - .monaco-workbench .monaco-scrollable-element > .shadow.left { - box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset; - } - - .monaco-workbench .monaco-scrollable-element > .shadow.top.left { - box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset; - } - `); - } - - const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground); - if (scrollbarSliderBackgroundColor) { - collector.addRule(` - .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider { - background: ${scrollbarSliderBackgroundColor}; - } - `); - } - - const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground); - if (scrollbarSliderHoverBackgroundColor) { - collector.addRule(` - .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider:hover { - background: ${scrollbarSliderHoverBackgroundColor}; - } - `); - } - - const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground); - if (scrollbarSliderActiveBackgroundColor) { - collector.addRule(` - .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider.active { - background: ${scrollbarSliderActiveBackgroundColor}; - } - `); - } - // Focus outline const focusOutline = theme.getColor(focusBorder); if (focusOutline) { From 5a0d53823bf643399df80e20132f53c929d63aa5 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 4 Nov 2021 22:59:49 +0100 Subject: [PATCH 64/83] Fixes microsoft/monaco-editor#2660: If available, create a rule for default tokens using the `editor.foreground` and `editor.background` colors --- .../browser/standaloneThemeServiceImpl.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 779f91ebf31..9feb2e1bcb3 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -132,6 +132,19 @@ class StandaloneTheme implements IStandaloneTheme { encodedTokensColors = baseData.encodedTokensColors; } } + // Pick up default colors from `editor.foreground` and `editor.background` if available + const editorForeground = this.themeData.colors['editor.foreground']; + const editorBackground = this.themeData.colors['editor.background']; + if (editorForeground || editorBackground) { + const rule: ITokenThemeRule = { token: '' }; + if (editorForeground) { + rule.foreground = editorForeground; + } + if (editorBackground) { + rule.background = editorBackground; + } + rules.push(rule); + } rules = rules.concat(this.themeData.rules); if (this.themeData.encodedTokensColors) { encodedTokensColors = this.themeData.encodedTokensColors; From 7bd792a094ff1870b8dcd76b68f702db9d4a6a5b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 4 Nov 2021 23:17:29 +0100 Subject: [PATCH 65/83] `monaco-editor-core@0.30.0` --- build/monaco/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/monaco/package.json b/build/monaco/package.json index b987a610d72..2e30e04628e 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.29.2", + "version": "0.30.0", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", From 36b7d6e8bc24533c9b649f3811949ee9f80f241b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 9 Nov 2021 10:03:32 +0100 Subject: [PATCH 66/83] Fixes microsoft/monaco-editor#2750 --- src/vs/editor/standalone/browser/standaloneLanguages.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 1d8403c185b..14b5bbb886a 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -49,8 +49,8 @@ export function getEncodedLanguageId(languageId: string): number { * @event */ export function onLanguage(languageId: string, callback: () => void): IDisposable { - let disposable = StaticServices.modeService.get().onDidEncounterLanguage((languageId) => { - if (languageId === languageId) { + let disposable = StaticServices.modeService.get().onDidEncounterLanguage((encounteredLanguageId) => { + if (encounteredLanguageId === languageId) { // stop listening disposable.dispose(); // invoke actual listener From ac29daaf3b35fe21fb9121312b1f37851d650ce8 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 9 Nov 2021 19:09:26 +0100 Subject: [PATCH 67/83] Fixes #136771: update to Electron v13.5.2 and pass `--ms-enable-run-as-node` together with `ELECTRON_RUN_AS_NODE` --- .yarnrc | 2 +- extensions/git/src/askpass.sh | 2 +- extensions/git/src/askpass.ts | 1 + resources/darwin/bin/code.sh | 2 +- resources/linux/bin/code.sh | 2 +- resources/win32/bin/code.cmd | 4 ++-- resources/win32/bin/code.sh | 4 ++-- scripts/code-cli.bat | 2 +- scripts/code-cli.sh | 2 +- scripts/code.sh | 2 +- scripts/node-electron.bat | 4 ++-- scripts/node-electron.sh | 2 ++ src/vs/platform/environment/node/shellEnv.ts | 4 ++-- src/vs/server/remoteCli.ts | 1 + 14 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.yarnrc b/.yarnrc index 0e39a85f525..481bf7bfa46 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,4 +1,4 @@ disturl "https://electronjs.org/headers" -target "13.5.1" +target "13.5.2" runtime "electron" build_from_source "true" diff --git a/extensions/git/src/askpass.sh b/extensions/git/src/askpass.sh index d19b62affa3..c85c64ad2fd 100755 --- a/extensions/git/src/askpass.sh +++ b/extensions/git/src/askpass.sh @@ -1,5 +1,5 @@ #!/bin/sh VSCODE_GIT_ASKPASS_PIPE=`mktemp` -ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $* +ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_EXTRA_ARGS" "$VSCODE_GIT_ASKPASS_MAIN" $* cat $VSCODE_GIT_ASKPASS_PIPE rm $VSCODE_GIT_ASKPASS_PIPE diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts index 7fc29a371ad..11c8e367649 100644 --- a/extensions/git/src/askpass.ts +++ b/extensions/git/src/askpass.ts @@ -83,6 +83,7 @@ export class Askpass implements IIPCHandler { ...this.ipc.getEnv(), GIT_ASKPASS: path.join(__dirname, 'askpass.sh'), VSCODE_GIT_ASKPASS_NODE: process.execPath, + VSCODE_GIT_ASKPASS_EXTRA_ARGS: !!process.versions['electron'] ? '--ms-enable-electron-run-as-node' : '', VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js') }; } diff --git a/resources/darwin/bin/code.sh b/resources/darwin/bin/code.sh index 6a9a9ec737c..eae80f95d57 100755 --- a/resources/darwin/bin/code.sh +++ b/resources/darwin/bin/code.sh @@ -7,5 +7,5 @@ function realpath() { python -c "import os,sys; print(os.path.realpath(sys.argv[ CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")" ELECTRON="$CONTENTS/MacOS/Electron" CLI="$CONTENTS/Resources/app/out/cli.js" -ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" +ELECTRON_RUN_AS_NODE=1 "$ELECTRON" --ms-enable-electron-run-as-node "$CLI" "$@" exit $? diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 06973937f14..5d9fb6edefd 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -50,5 +50,5 @@ fi ELECTRON="$VSCODE_PATH/@@NAME@@" CLI="$VSCODE_PATH/resources/app/out/cli.js" -ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" +ELECTRON_RUN_AS_NODE=1 "$ELECTRON" --ms-enable-electron-run-as-node "$CLI" "$@" exit $? diff --git a/resources/win32/bin/code.cmd b/resources/win32/bin/code.cmd index 33c640f5dd1..890767b226a 100644 --- a/resources/win32/bin/code.cmd +++ b/resources/win32/bin/code.cmd @@ -2,5 +2,5 @@ setlocal set VSCODE_DEV= set ELECTRON_RUN_AS_NODE=1 -"%~dp0..\@@NAME@@.exe" "%~dp0..\resources\app\out\cli.js" %* -endlocal \ No newline at end of file +"%~dp0..\@@NAME@@.exe" --ms-enable-electron-run-as-node "%~dp0..\resources\app\out\cli.js" %* +endlocal diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 23fbbc9bf20..25fa85b7b3d 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -43,7 +43,7 @@ if [ $IN_WSL = true ]; then # use the Remote WSL extension if installed WSL_EXT_ID="ms-vscode-remote.remote-wsl" - ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID >/tmp/remote-wsl-loc.txt 2>/dev/null /tmp/remote-wsl-loc.txt 2>/dev/null Date: Tue, 9 Nov 2021 19:13:05 +0100 Subject: [PATCH 68/83] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7c6cf3da05f..19bc2bcd08e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.63.0", - "distro": "58644f0352f74eff29f9d920573b8e6fffb1cfac", + "distro": "cc8976e5470edb06e4b3abd29841ffe7bf5042d2", "author": { "name": "Microsoft Corporation" }, From 2368392b9b3b2bb5ff430bc7ff42c03ab64e4854 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Tue, 9 Nov 2021 10:31:11 -0800 Subject: [PATCH 69/83] finalize silent option for getSession --- src/vs/vscode.d.ts | 25 +++++++++++++++---- src/vs/vscode.proposed.d.ts | 9 ------- .../workbench/api/common/extHost.api.impl.ts | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index f5f66342439..6dfa46c6a97 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -13855,6 +13855,17 @@ declare module 'vscode' { * Options to be used when getting an {@link AuthenticationSession} from an {@link AuthenticationProvider}. */ export interface AuthenticationGetSessionOptions { + /** + * Whether the existing user session preference should be cleared. + * + * For authentication providers that support being signed into multiple accounts at once, the user will be + * prompted to select an account to use when {@link authentication.getSession getSession} is called. This preference + * is remembered until {@link authentication.getSession getSession} is called with this flag. + * + * Defaults to false. + */ + clearSessionPreference?: boolean; + /** * Whether login should be performed if there is no matching session. * @@ -13866,19 +13877,23 @@ declare module 'vscode' { * will also result in an immediate modal dialog, and false will add a numbered badge to the accounts icon. * * Defaults to false. + * + * Note: you cannot use this option with {@link silent}. */ createIfNone?: boolean; + /** - * Whether the existing user session preference should be cleared. + * Whether we should show the indication to sign in in the Accounts menu. * - * For authentication providers that support being signed into multiple accounts at once, the user will be - * prompted to select an account to use when {@link authentication.getSession getSession} is called. This preference - * is remembered until {@link authentication.getSession getSession} is called with this flag. + * If false, the user will be shown a badge on the Accounts menu with an option to sign in for the extension. + * If true, no indication will be shown. * * Defaults to false. + * + * Note: you cannot use this option with any other options that prompt the user like {@link createIfNone}. */ - clearSessionPreference?: boolean; + silent?: boolean; } /** diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 259e42d1d4b..7c2f1cf9d0c 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -184,15 +184,6 @@ declare module 'vscode' { * Defaults to false. */ forceNewSession?: boolean | { detail: string }; - /** - * Whether we should show the indication to sign in in the Accounts menu. - * - * If false, the user will be shown a badge on the Accounts menu with an option to sign in for the extension. - * If true, no indication will be shown. - * - * Defaults to false. - */ - silent?: boolean; } export namespace authentication { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 3313761cc00..84e2a4eb04a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -226,7 +226,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const authentication: typeof vscode.authentication = { getSession(providerId: string, scopes: readonly string[], options?: vscode.AuthenticationGetSessionOptions) { - if (options?.forceNewSession || options?.silent) { + if (options?.forceNewSession) { checkProposedApiEnabled(extension); } return extHostAuthentication.getSession(extension, providerId, scopes, options as any); From d5d87b8fab865d9fb67741ad31c97be069a6d68a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 9 Nov 2021 12:45:29 -0600 Subject: [PATCH 70/83] fix #135798 (#136776) --- .../terminal/browser/terminalInstance.ts | 41 +++++++-------- .../terminal/browser/xterm/xtermTerminal.ts | 51 ++++++++----------- 2 files changed, 39 insertions(+), 53 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 8e1db030c63..08ffd2a1e3a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -615,7 +615,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { lineDataEventAddon.setOperatingSystem(this._processManager.os); } if (this._processManager.os === OperatingSystem.Windows) { - xterm.raw.setOption('windowsMode', processTraits.requiresWindowsMode || false); + xterm.raw.options.windowsMode = processTraits.requiresWindowsMode || false; } this._linkManager = this._instantiationService.createInstance(TerminalLinkManager, xterm.raw, this._processManager!); this._areLinksReady = true; @@ -1088,7 +1088,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); this._processManager.onPtyDisconnect(() => { - this._safeSetOption('disableStdin', true); + if (this.xterm) { + this.xterm.raw.options.disableStdin = true; + } this.statusList.add({ id: TerminalStatus.Disconnected, severity: Severity.Error, @@ -1097,7 +1099,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); }); this._processManager.onPtyReconnect(() => { - this._safeSetOption('disableStdin', false); + if (this.xterm) { + this.xterm.raw.options.disableStdin = false; + } this.statusList.remove(TerminalStatus.Disconnected); }); } @@ -1231,7 +1235,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { xterm.raw.write(formatMessageForTerminal(this._shellLaunchConfig.waitOnExit)); } // Disable all input if the terminal is exiting and listen for next keypress - xterm.raw.setOption('disableStdin', true); + xterm.raw.options.disableStdin = true; if (xterm.raw.textarea) { this._attachPressAnyKeyToCloseListener(xterm.raw); } @@ -1313,7 +1317,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Clean up waitOnExit state if (this._isExiting && this._shellLaunchConfig.waitOnExit) { - this.xterm.raw.setOption('disableStdin', false); + this.xterm.raw.options.disableStdin = false; this._isExiting = false; } } @@ -1397,7 +1401,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._navigationModeAddon?.dispose(); this._navigationModeAddon = undefined; } - this.xterm!.raw.setOption('screenReaderMode', isEnabled); + this.xterm!.raw.options.screenReaderMode = isEnabled; } private _setCommandsToSkipShell(commands: string[]): void { @@ -1407,16 +1411,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }).concat(commands); } - private _safeSetOption(key: string, value: any): void { - if (!this.xterm) { - return; - } - - if (this.xterm.raw.getOption(key) !== value) { - this.xterm.raw.setOption(key, value); - } - } - layout(dimension: dom.Dimension): void { this._lastLayoutDimensions = dimension; if (this.disableLayout) { @@ -1456,12 +1450,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._isVisible && this._layoutSettingsChanged) { const font = this.xterm.getFont(); const config = this._configHelper.config; - this._safeSetOption('letterSpacing', font.letterSpacing); - this._safeSetOption('lineHeight', font.lineHeight); - this._safeSetOption('fontSize', font.fontSize); - this._safeSetOption('fontFamily', font.fontFamily); - this._safeSetOption('fontWeight', config.fontWeight); - this._safeSetOption('fontWeightBold', config.fontWeightBold); + this.xterm.raw.options.letterSpacing = font.letterSpacing; + this.xterm.raw.options.lineHeight = font.lineHeight; + this.xterm.raw.options.fontSize = font.fontSize; + this.xterm.raw.options.fontFamily = font.fontFamily; + this.xterm.raw.options.fontWeight = config.fontWeight; + this.xterm.raw.options.fontWeightBold = config.fontWeightBold; // Any of the above setting changes could have changed the dimensions of the // terminal, re-evaluate now. @@ -1787,8 +1781,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { async toggleEscapeSequenceLogging(): Promise { const xterm = await this._xtermReadyPromise; - const isDebug = xterm.raw.getOption('logLevel') === 'debug'; - xterm.raw.setOption('logLevel', isDebug ? 'info' : 'debug'); + xterm.raw.options.logLevel = xterm.raw.options.logLevel === 'debug' ? 'info' : 'debug'; } async getInitialCwd(): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 213eea3cde1..3b5aa91c7fe 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -157,27 +157,27 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { updateConfig(): void { const config = this._configHelper.config; - this._safeSetOption('altClickMovesCursor', config.altClickMovesCursor); + this.raw.options.altClickMovesCursor = config.altClickMovesCursor; this._setCursorBlink(config.cursorBlinking); this._setCursorStyle(config.cursorStyle); this._setCursorWidth(config.cursorWidth); - this._safeSetOption('scrollback', config.scrollback); - this._safeSetOption('drawBoldTextInBrightColors', config.drawBoldTextInBrightColors); - this._safeSetOption('minimumContrastRatio', config.minimumContrastRatio); - this._safeSetOption('fastScrollSensitivity', config.fastScrollSensitivity); - this._safeSetOption('scrollSensitivity', config.mouseWheelScrollSensitivity); - this._safeSetOption('macOptionIsMeta', config.macOptionIsMeta); + this.raw.options.scrollback = config.scrollback; + this.raw.options.drawBoldTextInBrightColors = config.drawBoldTextInBrightColors; + this.raw.options.minimumContrastRatio = config.minimumContrastRatio; + this.raw.options.fastScrollSensitivity = config.fastScrollSensitivity; + this.raw.options.scrollSensitivity = config.mouseWheelScrollSensitivity; + this.raw.options.macOptionIsMeta = config.macOptionIsMeta; const editorOptions = this._configurationService.getValue('editor'); - this._safeSetOption('altClickMovesCursor', config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt'); - this._safeSetOption('macOptionClickForcesSelection', config.macOptionClickForcesSelection); - this._safeSetOption('rightClickSelectsWord', config.rightClickBehavior === 'selectWord'); - this._safeSetOption('wordSeparator', config.wordSeparators); - this._safeSetOption('customGlyphs', config.customGlyphs); + this.raw.options.altClickMovesCursor = config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt'; + this.raw.options.macOptionClickForcesSelection = config.macOptionClickForcesSelection; + this.raw.options.rightClickSelectsWord = config.rightClickBehavior === 'selectWord'; + this.raw.options.wordSeparator = config.wordSeparators; + this.raw.options.customGlyphs = config.customGlyphs; if ((!isSafari && config.gpuAcceleration === 'auto' && XtermTerminal._suggestedRendererType === undefined) || config.gpuAcceleration === 'on') { this._enableWebglRenderer(); } else { this._disposeOfWebglRenderer(); - this._safeSetOption('rendererType', this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType)); + this.raw.options.rendererType = this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType); } } @@ -282,30 +282,23 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { this.raw.clear(); } - private _safeSetOption(key: string, value: any): void { - if (this.raw.getOption(key) !== value) { - this.raw.setOption(key, value); - } - } - private _setCursorBlink(blink: boolean): void { - if (this.raw.getOption('cursorBlink') !== blink) { - this.raw.setOption('cursorBlink', blink); + if (this.raw.options.cursorBlink !== blink) { + this.raw.options.cursorBlink = blink; this.raw.refresh(0, this.raw.rows - 1); } } - private _setCursorStyle(style: string): void { - if (this.raw.getOption('cursorStyle') !== style) { + private _setCursorStyle(style: 'block' | 'underline' | 'bar' | 'line'): void { + if (this.raw.options.cursorStyle !== style) { // 'line' is used instead of bar in VS Code to be consistent with editor.cursorStyle - const xtermOption = style === 'line' ? 'bar' : style; - this.raw.setOption('cursorStyle', xtermOption); + this.raw.options.cursorStyle = (style === 'line') ? 'bar' : style; } } private _setCursorWidth(width: number): void { - if (this.raw.getOption('cursorWidth') !== width) { - this.raw.setOption('cursorWidth', width); + if (this.raw.options.cursorWidth !== width) { + this.raw.options.cursorWidth = width; } } @@ -328,7 +321,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { this._webglAddon.onContextLoss(() => { this._logService.info(`Webgl lost context, disposing of webgl renderer`); this._disposeOfWebglRenderer(); - this._safeSetOption('rendererType', 'dom'); + this.raw.options.rendererType = 'dom'; }); } catch (e) { this._logService.warn(`Webgl could not be loaded. Falling back to the canvas renderer type.`, e); @@ -337,7 +330,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') { this._measureRenderTime(); } - this._safeSetOption('rendererType', 'canvas'); + this.raw.options.rendererType = 'canvas'; XtermTerminal._suggestedRendererType = 'canvas'; this._disposeOfWebglRenderer(); } From 5fa4c888e648dcae3c048187a651a626dc6a8d41 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 9 Nov 2021 12:46:09 -0600 Subject: [PATCH 71/83] fix #133741 (#136763) --- src/vs/server/remoteTerminalChannel.ts | 13 ++----- .../terminal/browser/remoteTerminalBackend.ts | 2 +- .../terminal/browser/terminalService.ts | 34 +++++++++---------- .../terminal/common/remoteTerminalChannel.ts | 4 +-- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/vs/server/remoteTerminalChannel.ts b/src/vs/server/remoteTerminalChannel.ts index 2c31f0cd99e..5c47282ff63 100644 --- a/src/vs/server/remoteTerminalChannel.ts +++ b/src/vs/server/remoteTerminalChannel.ts @@ -15,7 +15,7 @@ import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { createRandomIPCHandle } from 'vs/base/parts/ipc/node/ipc.net'; import { ILogService } from 'vs/platform/log/common/log'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { IPtyService, IShellLaunchConfig, ITerminalProfile, ITerminalsLayoutInfo } from 'vs/platform/terminal/common/terminal'; +import { IPtyService, IShellLaunchConfig, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; import { IGetTerminalLayoutInfoArgs, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { createRemoteURITransformer } from 'vs/server/remoteUriTransformer'; @@ -124,8 +124,8 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< case '$getProfiles': return this._getProfiles.apply(this, args); case '$getEnvironment': return this._getEnvironment(); case '$getWslPath': return this._getWslPath(args[0]); - case '$getTerminalLayoutInfo': return this._getTerminalLayoutInfo(args); - case '$setTerminalLayoutInfo': return this._setTerminalLayoutInfo(args); + case '$getTerminalLayoutInfo': return this._ptyService.getTerminalLayoutInfo(args); + case '$setTerminalLayoutInfo': return this._ptyService.setTerminalLayoutInfo(args); case '$serializeTerminalState': return this._ptyService.serializeTerminalState.apply(this._ptyService, args); case '$reviveTerminalProcesses': return this._ptyService.reviveTerminalProcesses.apply(this._ptyService, args); case '$setUnicodeVersion': return this._ptyService.setUnicodeVersion.apply(this._ptyService, args); @@ -315,13 +315,6 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< return this._ptyService.getWslPath(original); } - private _setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): void { - this._ptyService.setTerminalLayoutInfo(args); - } - - private async _getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise { - return this._ptyService.getTerminalLayoutInfo(args); - } private _reduceConnectionGraceTime(): Promise { return this._ptyService.reduceConnectionGraceTime(); diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts index d32a431a437..6ddd5af7baf 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts @@ -337,7 +337,7 @@ class RemoteTerminalBackend extends Disposable implements ITerminalBackend { return this._remoteTerminalChannel?.getWslPath(original) || original; } - setTerminalLayoutInfo(layout: ITerminalsLayoutInfoById): Promise { + async setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById): Promise { if (!this._remoteTerminalChannel) { throw new Error(`Cannot call setActiveInstanceId when there is no remote`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 05016499524..db31d395268 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -66,7 +66,7 @@ export class TerminalService implements ITerminalService { private _configHelper: TerminalConfigHelper; private _remoteTerminalsInitPromise: Promise | undefined; private _localTerminalsInitPromise: Promise | undefined; - private _connectionState: TerminalConnectionState; + private _connectionState: TerminalConnectionState = TerminalConnectionState.Connecting; private _nativeDelegate?: ITerminalServiceNativeDelegate; private _shutdownWindowCount?: number; @@ -236,22 +236,6 @@ export class TerminalService implements ITerminalService { } }); - const enableTerminalReconnection = this.configHelper.config.enablePersistentSessions; - - // Connect to the extension host if it's there, set the connection state to connected when - // it's done. This should happen even when there is no extension host. - this._connectionState = TerminalConnectionState.Connecting; - - const isPersistentRemote = !!this._environmentService.remoteAuthority && enableTerminalReconnection; - - if (isPersistentRemote) { - this._remoteTerminalsInitPromise = this._reconnectToRemoteTerminals(); - } else if (enableTerminalReconnection) { - this._localTerminalsInitPromise = this._reconnectToLocalTerminals(); - } else { - this._connectionState = TerminalConnectionState.Connected; - } - // Create async as the class depends on `this` timeout(0).then(() => this._instantiationService.createInstance(TerminalEditorStyle, document.head)); } @@ -259,6 +243,22 @@ export class TerminalService implements ITerminalService { handleNewRegisteredBackend(backend: ITerminalBackend) { if (backend.remoteAuthority === this._environmentService.remoteAuthority) { this._primaryBackend = backend; + const enableTerminalReconnection = this.configHelper.config.enablePersistentSessions; + + // Connect to the extension host if it's there, set the connection state to connected when + // it's done. This should happen even when there is no extension host. + this._connectionState = TerminalConnectionState.Connecting; + + const isPersistentRemote = !!this._environmentService.remoteAuthority && enableTerminalReconnection; + + if (isPersistentRemote) { + this._remoteTerminalsInitPromise = this._reconnectToRemoteTerminals(); + } else if (enableTerminalReconnection) { + this._localTerminalsInitPromise = this._reconnectToLocalTerminals(); + } else { + this._connectionState = TerminalConnectionState.Connected; + } + backend.onDidRequestDetach(async (e) => { const instanceToDetach = this.getInstanceFromResource(getTerminalUri(e.workspaceId, e.instanceId)); if (instanceToDetach) { diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index 6812a399682..6bc36af3107 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -261,11 +261,11 @@ export class RemoteTerminalChannelClient { return this._channel.call('$getWslPath', [original]); } - setTerminalLayoutInfo(layout: ITerminalsLayoutInfoById): Promise { + setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById): Promise { const workspace = this._workspaceContextService.getWorkspace(); const args: ISetTerminalLayoutInfoArgs = { workspaceId: workspace.id, - tabs: layout.tabs + tabs: layout ? layout.tabs : [] }; return this._channel.call('$setTerminalLayoutInfo', args); } From f8ed49c5d331378dfed8f31a6360bac76329bed4 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Tue, 9 Nov 2021 10:50:49 -0800 Subject: [PATCH 72/83] finalize quickpick APIs --- src/vs/vscode.d.ts | 32 +++++++++++++++++++ src/vs/vscode.proposed.d.ts | 26 --------------- .../workbench/api/common/extHostQuickOpen.ts | 21 ++++++------ 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 6dfa46c6a97..c2ea239f0df 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1672,6 +1672,12 @@ declare module 'vscode' { * Always show this item. */ alwaysShow?: boolean; + + /** + * Optional buttons that will be rendered on this particular item. These buttons will trigger + * an {@link QuickPickItemButtonEvent} when clicked. + */ + readonly buttons?: QuickInputButton[]; } /** @@ -10199,6 +10205,12 @@ declare module 'vscode' { */ readonly onDidTriggerButton: Event; + /** + * An event signaling when a button in a particular {@link QuickPickItem} was triggered. + * This event does not fire for buttons in the title bar. + */ + readonly onDidTriggerItemButton: Event>; + /** * Items to pick from. This can be read and updated by the extension. */ @@ -10219,6 +10231,11 @@ declare module 'vscode' { */ matchOnDetail: boolean; + /* + * An optional flag to maintain the scroll position of the quick pick when the quick pick items are updated. Defaults to false. + */ + keepScrollPosition?: boolean; + /** * Active items. This can be read and updated by the extension. */ @@ -10330,6 +10347,21 @@ declare module 'vscode' { private constructor(); } + /** + * An event signaling when a button in a particular {@link QuickPickItem} was triggered. + * This event does not fire for buttons in the title bar. + */ + export interface QuickPickItemButtonEvent { + /** + * The button that was clicked. + */ + readonly button: QuickInputButton; + /** + * The item that the button belongs to. + */ + readonly item: T; + } + /** * An event describing an individual change in the text of a {@link TextDocument document}. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7c2f1cf9d0c..2edc241ced7 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1120,18 +1120,6 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/132068 - - export interface QuickPick extends QuickInput { - - /* - * An optional flag to maintain the scroll position of the quick pick when the quick pick items are updated. Defaults to false. - */ - keepScrollPosition?: boolean; - } - - //#endregion - //#region https://github.com/microsoft/vscode/issues/124970, Cell Execution State /** @@ -2803,20 +2791,6 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/88716 - export interface QuickPickItem { - buttons?: QuickInputButton[]; - } - export interface QuickPick extends QuickInput { - readonly onDidTriggerItemButton: Event>; - } - export interface QuickPickItemButtonEvent { - button: QuickInputButton; - item: T; - } - - //#endregion - //#region @eamodio https://github.com/microsoft/vscode/issues/133935 export interface SourceControl { diff --git a/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts index f05cc14db02..96374d8e4be 100644 --- a/src/vs/workbench/api/common/extHostQuickOpen.ts +++ b/src/vs/workbench/api/common/extHostQuickOpen.ts @@ -193,7 +193,7 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx // ---- QuickInput createQuickPick(extensionId: ExtensionIdentifier, enableProposedApi: boolean): QuickPick { - const session: ExtHostQuickPick = new ExtHostQuickPick(extensionId, enableProposedApi, () => this._sessions.delete(session._id)); + const session: ExtHostQuickPick = new ExtHostQuickPick(extensionId, () => this._sessions.delete(session._id)); this._sessions.set(session._id, session); return session; } @@ -531,7 +531,7 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx private readonly _onDidChangeSelectionEmitter = new Emitter(); private readonly _onDidTriggerItemButtonEmitter = new Emitter>(); - constructor(extensionId: ExtensionIdentifier, private readonly enableProposedApi: boolean, onDispose: () => void) { + constructor(extensionId: ExtensionIdentifier, onDispose: () => void) { super(extensionId, onDispose); this._disposables.push( this._onDidChangeActiveEmitter, @@ -561,16 +561,13 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx detail: item.detail, picked: item.picked, alwaysShow: item.alwaysShow, - // Proposed API only at the moment - buttons: item.buttons && this.enableProposedApi - ? item.buttons.map((button, i) => { - return { - ...getIconPathOrClass(button), - tooltip: button.tooltip, - handle: i - }; - }) - : undefined, + buttons: item.buttons?.map((button, i) => { + return { + ...getIconPathOrClass(button), + tooltip: button.tooltip, + handle: i + }; + }), })) }); } From de17f447c348dfaab1b4a5584b070b78d813f5d1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 12:16:03 -0800 Subject: [PATCH 73/83] Remove built-in markdown output renderer (#136696) Fixes #136679 For rendering markdown, I believe we should always use the built-in contributed markdown renderer. Right now we also ship a renderer in core, but this one doesn't support some of the syntax/features as the one from the markdown extension --- .../view/output/transforms/richTransform.ts | 33 +------------------ .../contrib/notebook/common/notebookCommon.ts | 1 - 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index ea32085e655..5d0fcbd0a2a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -6,9 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { Mimes } from 'vs/base/common/mime'; -import { dirname } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; @@ -17,10 +15,10 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { ICellOutputViewModel, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookDelegateForOutput, IOutputTransformContribution as IOutputRendererContribution } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; import { OutputRendererRegistry } from 'vs/workbench/contrib/notebook/browser/view/output/rendererRegistry'; import { truncatedArrayOfString } from 'vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper'; import { IOutputItemDto, TextOutputLineLimit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { INotebookDelegateForOutput, IOutputTransformContribution as IOutputRendererContribution } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; class JavaScriptRendererContrib extends Disposable implements IOutputRendererContribution { @@ -213,34 +211,6 @@ class HTMLRendererContrib extends Disposable implements IOutputRendererContribut } } -class MdRendererContrib extends Disposable implements IOutputRendererContribution { - getType() { - return RenderOutputType.Mainframe; - } - - getMimetypes() { - return [Mimes.markdown, Mimes.latex]; - } - - constructor( - public notebookEditor: INotebookDelegateForOutput, - @IInstantiationService private readonly instantiationService: IInstantiationService, - ) { - super(); - } - - render(output: ICellOutputViewModel, item: IOutputItemDto, container: HTMLElement, notebookUri: URI): IRenderOutput { - const disposable = new DisposableStore(); - const str = getStringValue(item); - const mdOutput = document.createElement('div'); - const mdRenderer = this.instantiationService.createInstance(MarkdownRenderer, { baseUrl: dirname(notebookUri) }); - mdOutput.appendChild(mdRenderer.render({ value: str, isTrusted: true, supportThemeIcons: true }, undefined, { gfm: true }).element); - container.appendChild(mdOutput); - disposable.add(mdRenderer); - return { type: RenderOutputType.Mainframe, disposable }; - } -} - class ImgRendererContrib extends Disposable implements IOutputRendererContribution { getType() { return RenderOutputType.Mainframe; @@ -276,7 +246,6 @@ class ImgRendererContrib extends Disposable implements IOutputRendererContributi OutputRendererRegistry.registerOutputTransform(JavaScriptRendererContrib); OutputRendererRegistry.registerOutputTransform(HTMLRendererContrib); -OutputRendererRegistry.registerOutputTransform(MdRendererContrib); OutputRendererRegistry.registerOutputTransform(ImgRendererContrib); OutputRendererRegistry.registerOutputTransform(PlainTextRendererContrib); OutputRendererRegistry.registerOutputTransform(JSErrorRendererContrib); diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index badebb06286..e18b1b1e1e2 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -579,7 +579,6 @@ const _mimeTypeInfo = new Map([ ['image/svg+xml', { supportedByCore: true }], ['application/json', { alwaysSecure: true, supportedByCore: true }], [Mimes.latex, { alwaysSecure: true, supportedByCore: true }], - [Mimes.markdown, { alwaysSecure: true, supportedByCore: true }], [Mimes.text, { alwaysSecure: true, supportedByCore: true }], ['text/html', { supportedByCore: true }], ['text/x-javascript', { alwaysSecure: true, supportedByCore: true }], // secure because rendered as text, not executed From 4849b6ed4166211586d3a0cfec659db42f808b62 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 12:42:01 -0800 Subject: [PATCH 74/83] Fix variable spelling --- .../notebook/browser/view/renderers/backLayerWebView.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index d7fc86b2e6c..d4c873778b8 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -215,7 +215,7 @@ export class BackLayerWebView extends Disposable { 'notebook-output-width': `calc(100% - ${this.options.leftMargin + this.options.rightMargin + this.options.runGutter}px)`, 'notebook-output-node-padding': `${this.options.outputNodePadding}px`, 'notebook-run-gutter': `${this.options.runGutter}px`, - 'notebook-preivew-node-padding': `${this.options.previewNodePadding}px`, + 'notebook-preview-node-padding': `${this.options.previewNodePadding}px`, 'notebook-markdown-left-margin': `${this.options.markdownLeftMargin}px`, 'notebook-output-node-left-padding': `${this.options.outputNodeLeftPadding}px`, 'notebook-markdown-min-height': `${this.options.previewNodePadding * 2}px`, @@ -279,10 +279,10 @@ export class BackLayerWebView extends Disposable { /* markdown */ #container > div.preview { width: 100%; - padding-right: var(--notebook-preivew-node-padding); + padding-right: var(--notebook-preview-node-padding); padding-left: var(--notebook-markdown-left-margin); - padding-top: var(--notebook-preivew-node-padding); - padding-bottom: var(--notebook-preivew-node-padding); + padding-top: var(--notebook-preview-node-padding); + padding-bottom: var(--notebook-preview-node-padding); box-sizing: border-box; white-space: nowrap; From 2f6685acc4b3257ffb93215cccf4d89dc3825eda Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 12:44:59 -0800 Subject: [PATCH 75/83] Mark array readonly instead of property We only support fully replacing the buttons, not calling `.push` on the array --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index c2ea239f0df..6ee7e8240d8 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1677,7 +1677,7 @@ declare module 'vscode' { * Optional buttons that will be rendered on this particular item. These buttons will trigger * an {@link QuickPickItemButtonEvent} when clicked. */ - readonly buttons?: QuickInputButton[]; + buttons?: readonly QuickInputButton[]; } /** From 4b10eb130c2710b9d1a40135650b2f179aad9aa2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 13:00:43 -0800 Subject: [PATCH 76/83] Use Object.entries --- .../notebook/browser/view/renderers/webviewPreloads.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index c3bc9163d90..e2eb3731459 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -664,8 +664,8 @@ async function webviewPreloads(ctx: PreloadContext) { } // Re-add new properties - for (const variable of Object.keys(event.data.styles)) { - documentStyle.setProperty(`--${variable}`, event.data.styles[variable]); + for (const [name, value] of Object.entries(event.data.styles)) { + documentStyle.setProperty(`--${name}`, value); } break; case 'notebookOptions': From a88cbb54f877322ca67679ca609ca47e4fdec5ac Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 13:05:53 -0800 Subject: [PATCH 77/83] Marking a few types/objects readonly --- .../notebook/common/notebookOptions.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 387fabb158e..c284214ca19 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -64,25 +64,25 @@ export interface NotebookLayoutConfiguration { } export interface NotebookOptionsChangeEvent { - cellStatusBarVisibility?: boolean; - cellToolbarLocation?: boolean; - cellToolbarInteraction?: boolean; - editorTopPadding?: boolean; - compactView?: boolean; - focusIndicator?: boolean; - insertToolbarPosition?: boolean; - insertToolbarAlignment?: boolean; - globalToolbar?: boolean; - showFoldingControls?: boolean; - consolidatedOutputButton?: boolean; - consolidatedRunButton?: boolean; - dragAndDropEnabled?: boolean; - fontSize?: boolean; - editorOptionsCustomizations?: boolean; - cellBreakpointMargin?: boolean; + readonly cellStatusBarVisibility?: boolean; + readonly cellToolbarLocation?: boolean; + readonly cellToolbarInteraction?: boolean; + readonly editorTopPadding?: boolean; + readonly compactView?: boolean; + readonly focusIndicator?: boolean; + readonly insertToolbarPosition?: boolean; + readonly insertToolbarAlignment?: boolean; + readonly globalToolbar?: boolean; + readonly showFoldingControls?: boolean; + readonly consolidatedOutputButton?: boolean; + readonly consolidatedRunButton?: boolean; + readonly dragAndDropEnabled?: boolean; + readonly fontSize?: boolean; + readonly editorOptionsCustomizations?: boolean; + readonly cellBreakpointMargin?: boolean; } -const defaultConfigConstants = { +const defaultConfigConstants = Object.freeze({ codeCellLeftMargin: 28, cellRunGutter: 32, markdownCellTopMargin: 8, @@ -90,9 +90,9 @@ const defaultConfigConstants = { markdownCellLeftMargin: 0, markdownCellGutter: 32, focusIndicatorLeftMargin: 4 -}; +}); -const compactConfigConstants = { +const compactConfigConstants = Object.freeze({ codeCellLeftMargin: 8, cellRunGutter: 36, markdownCellTopMargin: 6, @@ -100,7 +100,7 @@ const compactConfigConstants = { markdownCellLeftMargin: 8, markdownCellGutter: 36, focusIndicatorLeftMargin: 4 -}; +}); export class NotebookOptions extends Disposable { private _layoutConfiguration: NotebookLayoutConfiguration; From 09dc62b558772c22f708c10e59678d70a49e1282 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 13:30:07 -0800 Subject: [PATCH 78/83] Add notebook markup fontSize setting Fixes #126294 --- .../notebook/browser/notebook.contribution.ts | 8 +++++++- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../browser/view/renderers/backLayerWebView.ts | 5 +++++ .../contrib/notebook/common/notebookCommon.ts | 1 + .../contrib/notebook/common/notebookOptions.ts | 16 ++++++++++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index f380458fb38..d9e3465f648 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -30,7 +30,7 @@ import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEd import { isCompositeNotebookEditorInput, NotebookEditorInput, NotebookEditorInputOptions } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { NotebookService } from 'vs/workbench/contrib/notebook/browser/notebookServiceImpl'; -import { CellKind, CellToolbarLocation, CellToolbarVisibility, CellUri, DisplayOrderKey, UndoRedoPerCell, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookTextDiffEditorPreview, NotebookWorkingCopyTypeIdentifier, ShowCellStatusBar, CompactView, FocusIndicator, InsertToolbarLocation, GlobalToolbar, ConsolidatedOutputButton, ShowFoldingControls, DragAndDropEnabled, NotebookCellEditorOptionsCustomizations, ConsolidatedRunButton, TextOutputLineLimit, GlobalToolbarShowLabel, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellToolbarLocation, CellToolbarVisibility, CellUri, DisplayOrderKey, UndoRedoPerCell, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookTextDiffEditorPreview, NotebookWorkingCopyTypeIdentifier, ShowCellStatusBar, CompactView, FocusIndicator, InsertToolbarLocation, GlobalToolbar, ConsolidatedOutputButton, ShowFoldingControls, DragAndDropEnabled, NotebookCellEditorOptionsCustomizations, ConsolidatedRunButton, TextOutputLineLimit, GlobalToolbarShowLabel, IOutputItemDto, NotebookMarkupFontSize } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; @@ -780,6 +780,12 @@ configurationRegistry.registerConfiguration({ default: 30, tags: ['notebookLayout'] }, + [NotebookMarkupFontSize]: { + markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size of rendered markup in notebooks. When set to `0`, the value of `#editor.fontSize#` is used."), + type: 'number', + default: 0, + tags: ['notebookLayout'] + }, [NotebookCellEditorOptionsCustomizations]: editorOptionsCustomizationSchema } }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index de441e639c2..33c5df88faf 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -412,7 +412,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD this._updateForNotebookConfiguration(); } - if (e.compactView || e.focusIndicator || e.insertToolbarPosition || e.cellToolbarLocation || e.dragAndDropEnabled || e.fontSize || e.insertToolbarAlignment) { + if (e.compactView || e.focusIndicator || e.insertToolbarPosition || e.cellToolbarLocation || e.dragAndDropEnabled || e.fontSize || e.markupFontSize || e.insertToolbarAlignment) { this._styleElement?.remove(); this._createLayoutStyles(); this._webview?.updateOptions(this.notebookOptions.computeWebviewOptions()); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index d4c873778b8..d4e31753528 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -120,6 +120,7 @@ export class BackLayerWebView extends Disposable { runGutter: number, dragAndDropEnabled: boolean, fontSize: number + markupFontSize: number }, private readonly rendererMessaging: IScopedRendererMessaging | undefined, @IWebviewService readonly webviewService: IWebviewService, @@ -187,6 +188,7 @@ export class BackLayerWebView extends Disposable { runGutter: number, dragAndDropEnabled: boolean, fontSize: number + markupFontSize: number }) { this.options = options; this._updateStyles(); @@ -219,6 +221,7 @@ export class BackLayerWebView extends Disposable { 'notebook-markdown-left-margin': `${this.options.markdownLeftMargin}px`, 'notebook-output-node-left-padding': `${this.options.outputNodeLeftPadding}px`, 'notebook-markdown-min-height': `${this.options.previewNodePadding * 2}px`, + 'notebook-markup-font-size': `${this.options.markupFontSize}px`, 'notebook-cell-output-font-size': `${this.options.fontSize}px`, 'notebook-cell-markup-empty-content': nls.localize('notebook.emptyMarkdownPlaceholder', "Empty markdown cell, double click or press enter to edit."), 'notebook-cell-renderer-not-found-error': nls.localize({ @@ -288,6 +291,8 @@ export class BackLayerWebView extends Disposable { white-space: nowrap; overflow: hidden; white-space: initial; + + font-size: var(--notebook-markup-font-size); color: var(--theme-ui-foreground); } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index e18b1b1e1e2..454d082a718 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -921,6 +921,7 @@ export const ConsolidatedRunButton = 'notebook.consolidatedRunButton'; export const OpenGettingStarted = 'notebook.experimental.openGettingStarted'; export const TextOutputLineLimit = 'notebook.output.textLineLimit'; export const GlobalToolbarShowLabel = 'notebook.globalToolbarShowLabel'; +export const NotebookMarkupFontSize = 'notebook.markup.fontSize'; export const enum CellStatusbarAlignment { Left = 1, diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index c284214ca19..4271ca890c3 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -6,7 +6,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CellToolbarLocation, CellToolbarVisibility, CompactView, ConsolidatedOutputButton, ConsolidatedRunButton, DragAndDropEnabled, ExperimentalInsertToolbarAlignment, FocusIndicator, GlobalToolbar, InsertToolbarLocation, NotebookCellEditorOptionsCustomizations, NotebookCellInternalMetadata, ShowCellStatusBar, ShowCellStatusBarType, ShowFoldingControls } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellToolbarLocation, CellToolbarVisibility, CompactView, ConsolidatedOutputButton, ConsolidatedRunButton, DragAndDropEnabled, ExperimentalInsertToolbarAlignment, FocusIndicator, GlobalToolbar, InsertToolbarLocation, NotebookCellEditorOptionsCustomizations, NotebookCellInternalMetadata, NotebookMarkupFontSize, ShowCellStatusBar, ShowCellStatusBarType, ShowFoldingControls } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const SCROLLABLE_ELEMENT_PADDING_TOP = 18; @@ -59,6 +59,7 @@ export interface NotebookLayoutConfiguration { showFoldingControls: 'always' | 'mouseover'; dragAndDropEnabled: boolean; fontSize: number; + markupFontSize: number; focusIndicatorLeftMargin: number; editorOptionsCustomizations: any | undefined; } @@ -78,6 +79,7 @@ export interface NotebookOptionsChangeEvent { readonly consolidatedRunButton?: boolean; readonly dragAndDropEnabled?: boolean; readonly fontSize?: boolean; + readonly markupFontSize?: boolean; readonly editorOptionsCustomizations?: boolean; readonly cellBreakpointMargin?: boolean; } @@ -123,6 +125,7 @@ export class NotebookOptions extends Disposable { const showFoldingControls = this._computeShowFoldingControlsOption(); // const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(compactView, insertToolbarPosition, insertToolbarAlignment); const fontSize = this.configurationService.getValue('editor.fontSize'); + const markupFontSize = this.configurationService.getValue(NotebookMarkupFontSize); const editorOptionsCustomizations = this.configurationService.getValue(NotebookCellEditorOptionsCustomizations); this._layoutConfiguration = { @@ -153,6 +156,7 @@ export class NotebookOptions extends Disposable { insertToolbarAlignment, showFoldingControls, fontSize, + markupFontSize: markupFontSize > 0 ? markupFontSize : fontSize, editorOptionsCustomizations, }; @@ -182,6 +186,7 @@ export class NotebookOptions extends Disposable { const showFoldingControls = e.affectsConfiguration(ShowFoldingControls); const dragAndDropEnabled = e.affectsConfiguration(DragAndDropEnabled); const fontSize = e.affectsConfiguration('editor.fontSize'); + const markupFontSize = e.affectsConfiguration(NotebookMarkupFontSize); const editorOptionsCustomizations = e.affectsConfiguration(NotebookCellEditorOptionsCustomizations); if ( @@ -198,6 +203,7 @@ export class NotebookOptions extends Disposable { && !showFoldingControls && !dragAndDropEnabled && !fontSize + && !markupFontSize && !editorOptionsCustomizations) { return; } @@ -260,6 +266,10 @@ export class NotebookOptions extends Disposable { configuration.fontSize = this.configurationService.getValue('editor.fontSize'); } + if (markupFontSize) { + configuration.markupFontSize = this.configurationService.getValue(NotebookMarkupFontSize) || configuration.fontSize; + } + if (editorOptionsCustomizations) { configuration.editorOptionsCustomizations = this.configurationService.getValue(NotebookCellEditorOptionsCustomizations); } @@ -281,6 +291,7 @@ export class NotebookOptions extends Disposable { consolidatedRunButton, dragAndDropEnabled, fontSize, + markupFontSize, editorOptionsCustomizations }); } @@ -456,7 +467,8 @@ export class NotebookOptions extends Disposable { rightMargin: this._layoutConfiguration.cellRightMargin, runGutter: this._layoutConfiguration.cellRunGutter, dragAndDropEnabled: this._layoutConfiguration.dragAndDropEnabled, - fontSize: this._layoutConfiguration.fontSize + fontSize: this._layoutConfiguration.fontSize, + markupFontSize: this._layoutConfiguration.markupFontSize, }; } From 13bf498e45ffa0a98d93db1bc2b1209f5062f6a8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 13:43:09 -0800 Subject: [PATCH 79/83] Fix compile error --- src/vs/workbench/contrib/notebook/common/notebookOptions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 4271ca890c3..f8dd24f3b84 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -482,7 +482,8 @@ export class NotebookOptions extends Disposable { rightMargin: 0, runGutter: 0, dragAndDropEnabled: false, - fontSize: this._layoutConfiguration.fontSize + fontSize: this._layoutConfiguration.fontSize, + markupFontSize: this._layoutConfiguration.markupFontSize, }; } From 8b0720dc5743d212605eb68840a46684fc407fe3 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Tue, 9 Nov 2021 16:20:28 -0600 Subject: [PATCH 80/83] Pull out and test TerminalProfileQuickpick (#136680) --- .../contrib/terminal/browser/terminal.ts | 8 +- .../browser/terminalProfileQuickpick.ts | 240 ++++++++++++++++ .../browser/terminalProfileService.ts | 30 +- .../terminal/browser/terminalService.ts | 263 +++--------------- .../contrib/terminal/common/terminal.ts | 7 +- .../browser/terminalProfileService.test.ts | 113 +++++++- 6 files changed, 420 insertions(+), 241 deletions(-) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 1fd36dbf73c..7f2d006ee3f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource, TerminalShellType, IExtensionTerminalProfile, TerminalLocation, ProcessPropertyType, ProcessCapability, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal'; -import { ICommandTracker, INavigationMode, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalFont, ITerminalBackend, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ICommandTracker, INavigationMode, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalFont, ITerminalBackend, ITerminalProcessExtHostProxy, IRegisterContributedProfileArgs } from 'vs/workbench/contrib/terminal/common/terminal'; import type { Terminal as XTermTerminal } from 'xterm'; import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11'; @@ -19,6 +19,7 @@ import { IEditableData } from 'vs/workbench/common/views'; import { DeserializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; +import { IKeyMods } from 'vs/platform/quickinput/common/quickInput'; export const ITerminalService = createDecorator('terminalService'); export const ITerminalEditorService = createDecorator('terminalEditorService'); @@ -73,6 +74,11 @@ export const enum Direction { Down = 3 } +export interface IQuickPickTerminalObject { + config: IRegisterContributedProfileArgs | ITerminalProfile | { profile: IExtensionTerminalProfile, options: { icon?: string, color?: string } } | undefined, + keyMods: IKeyMods | undefined +} + export interface ITerminalGroup { activeInstance: ITerminalInstance | undefined; terminalInstances: ITerminalInstance[]; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts new file mode 100644 index 00000000000..e7dac04a1c1 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts @@ -0,0 +1,240 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { iconRegistry, Codicon } from 'vs/base/common/codicons'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IQuickInputService, IKeyMods, IPickOptions, IQuickPickSeparator, IQuickInputButton, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IExtensionTerminalProfile, ITerminalProfile, ITerminalProfileObject, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal'; +import { getUriClasses, getColorClass, getColorStyleElement } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; +import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; +import * as nls from 'vs/nls'; +import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IQuickPickTerminalObject } from 'vs/workbench/contrib/terminal/browser/terminal'; + + +type DefaultProfileName = string; +export class TerminalProfileQuickpick { + constructor( + @ITerminalProfileService private readonly _terminalProfileService: ITerminalProfileService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IQuickInputService private readonly _quickInputService: IQuickInputService, + @IThemeService private readonly _themeService: IThemeService + ) { } + + async showAndGetResult(type: 'setDefault' | 'createInstance'): Promise { + const platformKey = await this._terminalProfileService.getPlatformKey(); + const profilesKey = TerminalSettingPrefix.Profiles + platformKey; + const result = await this._createAndShow(type); + const defaultProfileKey = `${TerminalSettingPrefix.DefaultProfile}${platformKey}`; + if (!result) { + return; + } + if (type === 'setDefault') { + if ('command' in result.profile) { + return; // Should never happen + } else if ('id' in result.profile) { + // extension contributed profile + await this._configurationService.updateValue(defaultProfileKey, result.profile.title, ConfigurationTarget.USER); + return { + config: { + extensionIdentifier: result.profile.extensionIdentifier, + id: result.profile.id, + title: result.profile.title, + options: { + color: result.profile.color, + icon: result.profile.icon + } + }, + keyMods: result.keyMods + }; + } + + // Add the profile to settings if necessary + if ('isAutoDetected' in result.profile) { + const profilesConfig = await this._configurationService.getValue(profilesKey); + if (typeof profilesConfig === 'object') { + const newProfile: ITerminalProfileObject = { + path: result.profile.path + }; + if (result.profile.args) { + newProfile.args = result.profile.args; + } + (profilesConfig as { [key: string]: ITerminalProfileObject })[result.profile.profileName] = newProfile; + } + await this._configurationService.updateValue(profilesKey, profilesConfig, ConfigurationTarget.USER); + } + // Set the default profile + await this._configurationService.updateValue(defaultProfileKey, result.profileName, ConfigurationTarget.USER); + } else if (type === 'createInstance') { + if ('id' in result.profile) { + return { + config: { + extensionIdentifier: result.profile.extensionIdentifier, + id: result.profile.id, + title: result.profile.title, + options: { + icon: result.profile.icon, + color: result.profile.color, + } + }, + keyMods: result.keyMods + }; + } else { + return { config: result.profile, keyMods: result.keyMods }; + } + } + // for tests + return 'profileName' in result.profile ? result.profile.profileName : result.profile.title; + } + + private async _createAndShow(type: 'setDefault' | 'createInstance'): Promise { + const platformKey = await this._terminalProfileService.getPlatformKey(); + const profiles = this._terminalProfileService.availableProfiles; + const profilesKey = TerminalSettingPrefix.Profiles + platformKey; + const defaultProfileName = this._terminalProfileService.getDefaultProfileName(); + let keyMods: IKeyMods | undefined; + const options: IPickOptions = { + placeHolder: type === 'createInstance' ? nls.localize('terminal.integrated.selectProfileToCreate', "Select the terminal profile to create") : nls.localize('terminal.integrated.chooseDefaultProfile', "Select your default terminal profile"), + onDidTriggerItemButton: async (context) => { + if ('command' in context.item.profile) { + return; + } + if ('id' in context.item.profile) { + return; + } + const configProfiles: { [key: string]: any } = this._configurationService.getValue(TerminalSettingPrefix.Profiles + platformKey); + const existingProfiles = !!configProfiles ? Object.keys(configProfiles) : []; + const name = await this._quickInputService.input({ + prompt: nls.localize('enterTerminalProfileName', "Enter terminal profile name"), + value: context.item.profile.profileName, + validateInput: async input => { + if (existingProfiles.includes(input)) { + return nls.localize('terminalProfileAlreadyExists', "A terminal profile already exists with that name"); + } + return undefined; + } + }); + if (!name) { + return; + } + const newConfigValue: { [key: string]: ITerminalProfileObject } = { ...configProfiles } ?? {}; + newConfigValue[name] = { + path: context.item.profile.path, + args: context.item.profile.args + }; + await this._configurationService.updateValue(profilesKey, newConfigValue, ConfigurationTarget.USER); + }, + onKeyMods: mods => keyMods = mods + }; + + // Build quick pick items + const quickPickItems: (IProfileQuickPickItem | IQuickPickSeparator)[] = []; + const configProfiles = profiles.filter(e => !e.isAutoDetected); + const autoDetectedProfiles = profiles.filter(e => e.isAutoDetected); + + if (configProfiles.length > 0) { + quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles', "profiles") }); + quickPickItems.push(...this._sortProfileQuickPickItems(configProfiles.map(e => this._createProfileQuickPickItem(e)), defaultProfileName!)); + } + + quickPickItems.push({ type: 'separator', label: nls.localize('ICreateContributedTerminalProfileOptions', "contributed") }); + const contributedProfiles: IProfileQuickPickItem[] = []; + for (const contributed of this._terminalProfileService.contributedProfiles) { + if (typeof contributed.icon === 'string' && contributed.icon.startsWith('$(')) { + contributed.icon = contributed.icon.substring(2, contributed.icon.length - 1); + } + const icon = contributed.icon && typeof contributed.icon === 'string' ? (iconRegistry.get(contributed.icon) || Codicon.terminal) : Codicon.terminal; + const uriClasses = getUriClasses(contributed, this._themeService.getColorTheme().type, true); + const colorClass = getColorClass(contributed); + const iconClasses = []; + if (uriClasses) { + iconClasses.push(...uriClasses); + } + if (colorClass) { + iconClasses.push(colorClass); + } + contributedProfiles.push({ + label: `$(${icon.id}) ${contributed.title}`, + profile: { + extensionIdentifier: contributed.extensionIdentifier, + title: contributed.title, + icon: contributed.icon, + id: contributed.id, + color: contributed.color + }, + profileName: contributed.title, + iconClasses + }); + } + + if (contributedProfiles.length > 0) { + quickPickItems.push(...this._sortProfileQuickPickItems(contributedProfiles, defaultProfileName!)); + } + + if (autoDetectedProfiles.length > 0) { + quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles.detected', "detected") }); + quickPickItems.push(...this._sortProfileQuickPickItems(autoDetectedProfiles.map(e => this._createProfileQuickPickItem(e)), defaultProfileName!)); + } + const styleElement = getColorStyleElement(this._themeService.getColorTheme()); + document.body.appendChild(styleElement); + + const result = await this._quickInputService.pick(quickPickItems, options); + document.body.removeChild(styleElement); + if (!result) { + return undefined; + } + if (keyMods) { + result.keyMods = keyMods; + } + return result; + } + + private _createProfileQuickPickItem(profile: ITerminalProfile): IProfileQuickPickItem { + const buttons: IQuickInputButton[] = [{ + iconClass: ThemeIcon.asClassName(configureTerminalProfileIcon), + tooltip: nls.localize('createQuickLaunchProfile', "Configure Terminal Profile") + }]; + const icon = (profile.icon && ThemeIcon.isThemeIcon(profile.icon)) ? profile.icon : Codicon.terminal; + const label = `$(${icon.id}) ${profile.profileName}`; + const colorClass = getColorClass(profile); + const iconClasses = []; + if (colorClass) { + iconClasses.push(colorClass); + } + + if (profile.args) { + if (typeof profile.args === 'string') { + return { label, description: `${profile.path} ${profile.args}`, profile, profileName: profile.profileName, buttons, iconClasses }; + } + const argsString = profile.args.map(e => { + if (e.includes(' ')) { + return `"${e.replace('/"/g', '\\"')}"`; + } + return e; + }).join(' '); + return { label, description: `${profile.path} ${argsString}`, profile, profileName: profile.profileName, buttons, iconClasses }; + } + return { label, description: profile.path, profile, profileName: profile.profileName, buttons, iconClasses }; + } + + private _sortProfileQuickPickItems(items: IProfileQuickPickItem[], defaultProfileName: string) { + return items.sort((a, b) => { + if (b.profileName === defaultProfileName) { + return 1; + } + if (a.profileName === defaultProfileName) { + return -1; + } + return a.profileName.localeCompare(b.profileName); + }); + } +} + +export interface IProfileQuickPickItem extends IQuickPickItem { + profile: ITerminalProfile | IExtensionTerminalProfile; + profileName: string; + keyMods?: IKeyMods | undefined; +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts index 7e30984367a..00f3aa099d6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts @@ -11,12 +11,12 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { isMacintosh, isWeb, isWindows, OperatingSystem, OS } from 'vs/base/common/platform'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ITerminalProfile, IExtensionTerminalProfile, TerminalSettingPrefix, TerminalSettingId, ICreateContributedTerminalProfileOptions, ITerminalProfileObject, IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; +import { ITerminalProfile, IExtensionTerminalProfile, TerminalSettingPrefix, TerminalSettingId, ITerminalProfileObject, IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; import { registerTerminalDefaultProfileConfiguration } from 'vs/platform/terminal/common/terminalPlatformConfiguration'; import { terminalIconsEqual, terminalProfileArgsMatch } from 'vs/platform/terminal/common/terminalProfiles'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { refreshTerminalActions } from 'vs/workbench/contrib/terminal/browser/terminalActions'; -import { ITerminalProfileProvider, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IRegisterContributedProfileArgs, ITerminalProfileProvider, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -61,7 +61,7 @@ export class TerminalProfileService implements ITerminalProfileService { this._extensionService.onDidChangeExtensions(() => this.refreshAvailableProfiles()); this._configurationService.onDidChangeConfiguration(async e => { - const platformKey = await this._getPlatformKey(); + const platformKey = await this.getPlatformKey(); if (e.affectsConfiguration(TerminalSettingPrefix.DefaultProfile + platformKey) || e.affectsConfiguration(TerminalSettingPrefix.Profiles + platformKey) || e.affectsConfiguration(TerminalSettingId.UseWslProfiles)) { @@ -112,7 +112,7 @@ export class TerminalProfileService implements ITerminalProfileService { } private async _updateContributedProfiles(): Promise { - const platformKey = await this._getPlatformKey(); + const platformKey = await this.getPlatformKey(); const excludedContributedProfiles: string[] = []; const configProfiles: { [key: string]: any } = this._configurationService.getValue(TerminalSettingPrefix.Profiles + platformKey); for (const [profileName, value] of Object.entries(configProfiles)) { @@ -136,7 +136,7 @@ export class TerminalProfileService implements ITerminalProfileService { if (!primaryBackend) { return this._availableProfiles || []; } - const platform = await this._getPlatformKey(); + const platform = await this.getPlatformKey(); this._defaultProfileName = this._configurationService.getValue(`${TerminalSettingPrefix.DefaultProfile}${platform}`) ?? undefined; return primaryBackend.getProfiles(this._configurationService.getValue(`${TerminalSettingPrefix.Profiles}${platform}`), this._defaultProfileName, includeDetectedProfiles); } @@ -151,7 +151,7 @@ export class TerminalProfileService implements ITerminalProfileService { refreshTerminalActions(profiles); } - private async _getPlatformKey(): Promise { + async getPlatformKey(): Promise { const env = await this._remoteAgentService.getEnvironment(); if (env) { return env.os === OperatingSystem.Windows ? 'windows' : (env.os === OperatingSystem.Macintosh ? 'osx' : 'linux'); @@ -169,19 +169,19 @@ export class TerminalProfileService implements ITerminalProfileService { return toDisposable(() => this._profileProviders.delete(id)); } - async registerContributedProfile(extensionIdentifier: string, id: string, title: string, options: ICreateContributedTerminalProfileOptions): Promise { - const platformKey = await this._getPlatformKey(); + async registerContributedProfile(args: IRegisterContributedProfileArgs): Promise { + const platformKey = await this.getPlatformKey(); const profilesConfig = await this._configurationService.getValue(`${TerminalSettingPrefix.Profiles}${platformKey}`); if (typeof profilesConfig === 'object') { const newProfile: IExtensionTerminalProfile = { - extensionIdentifier: extensionIdentifier, - icon: options.icon, - id, - title: title, - color: options.color + extensionIdentifier: args.extensionIdentifier, + icon: args.options.icon, + id: args.id, + title: args.title, + color: args.options.color }; - (profilesConfig as { [key: string]: ITerminalProfileObject })[title] = newProfile; + (profilesConfig as { [key: string]: ITerminalProfileObject })[args.title] = newProfile; } await this._configurationService.updateValue(`${TerminalSettingPrefix.Profiles}${platformKey}`, profilesConfig, ConfigurationTarget.USER); return; @@ -191,7 +191,7 @@ export class TerminalProfileService implements ITerminalProfileService { // prevents recursion with the MainThreadTerminalService call to create terminal // and defers to the provided launch config when an executable is provided if (shellLaunchConfig && !shellLaunchConfig.extHostTerminalId && !('executable' in shellLaunchConfig)) { - const key = await this._getPlatformKey(); + const key = await this.getPlatformKey(); const defaultProfileName = this._configurationService.getValue(`${TerminalSettingPrefix.DefaultProfile}${key}`); const contributedDefaultProfile = this.contributedProfiles.find(p => p.title === defaultProfileName); return contributedDefaultProfile; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index db31d395268..ef444259b8a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -10,18 +10,16 @@ import { debounce } from 'vs/base/common/decorators'; import { Emitter, Event } from 'vs/base/common/event'; import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; -import { isMacintosh, isWeb, isWindows, OperatingSystem } from 'vs/base/common/platform'; +import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import * as nls from 'vs/nls'; -import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IKeyMods, IPickOptions, IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ICreateContributedTerminalProfileOptions, IExtensionTerminalProfile, IShellLaunchConfig, ITerminalLaunchError, ITerminalProfile, ITerminalProfileObject, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalLocation, TerminalLocationString, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal'; +import { ICreateContributedTerminalProfileOptions, IShellLaunchConfig, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalLocation, TerminalLocationString } from 'vs/platform/terminal/common/terminal'; import { iconForeground } from 'vs/platform/theme/common/colorRegistry'; import { IconDefinition } from 'vs/platform/theme/common/iconRegistry'; import { ColorScheme } from 'vs/platform/theme/common/theme'; @@ -31,8 +29,7 @@ import { IEditableData, IViewsService } from 'vs/workbench/common/views'; import { ICreateTerminalOptions, IRequestAddInstanceToGroupEvent, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalFindHost, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalLocationOptions, ITerminalService, ITerminalServiceNativeDelegate, TerminalConnectionState, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor'; -import { getColorClass, getColorStyleContent, getColorStyleElement, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; -import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; +import { getColorStyleContent, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { getInstanceFromResource, getTerminalUri, parseTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri'; import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView'; import { IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalBackend, ITerminalProcessExtHostProxy, ITerminalProfileService, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -46,6 +43,8 @@ import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/ed import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { TerminalProfileQuickpick } from 'vs/workbench/contrib/terminal/browser/terminalProfileQuickpick'; +import { IKeyMods } from 'vs/base/parts/quickinput/common/quickInput'; export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; @@ -144,8 +143,6 @@ export class TerminalService implements ITerminalService { @IDialogService private _dialogService: IDialogService, @IInstantiationService private _instantiationService: IInstantiationService, @IRemoteAgentService private _remoteAgentService: IRemoteAgentService, - @IQuickInputService private _quickInputService: IQuickInputService, - @IConfigurationService private _configurationService: IConfigurationService, @IViewsService private _viewsService: IViewsService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @@ -154,7 +151,6 @@ export class TerminalService implements ITerminalService { @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, @IEditorResolverService editorResolverService: IEditorResolverService, @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, - @IThemeService private readonly _themeService: IThemeService, @ITerminalProfileService private readonly _terminalProfileService: ITerminalProfileService, @IExtensionService private readonly _extensionService: IExtensionService, @INotificationService private readonly _notificationService: INotificationService @@ -239,6 +235,44 @@ export class TerminalService implements ITerminalService { // Create async as the class depends on `this` timeout(0).then(() => this._instantiationService.createInstance(TerminalEditorStyle, document.head)); } + async showProfileQuickPick(type: 'setDefault' | 'createInstance', cwd?: string | URI): Promise { + const quickPick = this._instantiationService.createInstance(TerminalProfileQuickpick); + const result = await quickPick.showAndGetResult(type); + if (!result) { + return; + } + if (typeof result === 'string') { + return; + } + let keyMods: IKeyMods | undefined = result.keyMods; + if (type === 'createInstance') { + const activeInstance = this.getDefaultInstanceHost().activeInstance; + let instance; + + if (result.config && 'id' in result?.config) { + await this.createContributedTerminalProfile(result.config.extensionIdentifier, result.config.id, { + icon: result.config.options?.icon, + color: result.config.options?.color, + location: !!(keyMods?.alt && activeInstance) ? { splitActiveTerminal: true } : this.defaultLocation + }); + return; + } else if (result.config && 'profileName' in result.config) { + if (keyMods?.alt && activeInstance) { + // create split, only valid if there's an active instance + instance = await this.createTerminal({ location: { parentTerminal: activeInstance }, config: result.config }); + } else { + instance = await this.createTerminal({ location: this.defaultLocation, config: result.config, cwd }); + } + } + + if (instance && this.defaultLocation !== TerminalLocation.Editor) { + this._terminalGroupService.showPanel(true); + this.setActiveInstance(instance); + return instance; + } + } + return undefined; + } handleNewRegisteredBackend(backend: ITerminalBackend) { if (backend.remoteAuthority === this._environmentService.remoteAuthority) { @@ -848,172 +882,6 @@ export class TerminalService implements ITerminalService { return !res.confirmed; } - private async _getPlatformKey(): Promise { - const env = await this._remoteAgentService.getEnvironment(); - if (env) { - return env.os === OperatingSystem.Windows ? 'windows' : (env.os === OperatingSystem.Macintosh ? 'osx' : 'linux'); - } - return isWindows ? 'windows' : (isMacintosh ? 'osx' : 'linux'); - } - - async showProfileQuickPick(type: 'setDefault' | 'createInstance', cwd?: string | URI): Promise { - let keyMods: IKeyMods | undefined; - const profiles = this._terminalProfileService.availableProfiles; - const platformKey = await this._getPlatformKey(); - const profilesKey = `${TerminalSettingPrefix.Profiles}${platformKey}`; - const defaultProfileKey = `${TerminalSettingPrefix.DefaultProfile}${platformKey}`; - const defaultProfileName = this._configurationService.getValue(defaultProfileKey); - - const options: IPickOptions = { - placeHolder: type === 'createInstance' ? nls.localize('terminal.integrated.selectProfileToCreate', "Select the terminal profile to create") : nls.localize('terminal.integrated.chooseDefaultProfile', "Select your default terminal profile"), - onDidTriggerItemButton: async (context) => { - if ('command' in context.item.profile) { - return; - } - if ('id' in context.item.profile) { - return; - } - const configProfiles = this._configurationService.getValue<{ [key: string]: ITerminalProfileObject }>(profilesKey); - const existingProfiles = configProfiles ? Object.keys(configProfiles) : []; - const name = await this._quickInputService.input({ - prompt: nls.localize('enterTerminalProfileName', "Enter terminal profile name"), - value: context.item.profile.profileName, - validateInput: async input => { - if (existingProfiles.includes(input)) { - return nls.localize('terminalProfileAlreadyExists', "A terminal profile already exists with that name"); - } - return undefined; - } - }); - if (!name) { - return; - } - const newConfigValue: { [key: string]: ITerminalProfileObject } = { ...configProfiles } ?? {}; - newConfigValue[name] = { - path: context.item.profile.path, - args: context.item.profile.args - }; - await this._configurationService.updateValue(profilesKey, newConfigValue, ConfigurationTarget.USER); - }, - onKeyMods: mods => keyMods = mods - }; - - // Build quick pick items - const quickPickItems: (IProfileQuickPickItem | IQuickPickSeparator)[] = []; - const configProfiles = profiles.filter(e => !e.isAutoDetected); - const autoDetectedProfiles = profiles.filter(e => e.isAutoDetected); - - if (configProfiles.length > 0) { - quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles', "profiles") }); - quickPickItems.push(...this._sortProfileQuickPickItems(configProfiles.map(e => this._createProfileQuickPickItem(e)), defaultProfileName)); - } - - quickPickItems.push({ type: 'separator', label: nls.localize('ICreateContributedTerminalProfileOptions', "contributed") }); - const contributedProfiles: IProfileQuickPickItem[] = []; - for (const contributed of this._terminalProfileService.contributedProfiles) { - if (typeof contributed.icon === 'string' && contributed.icon.startsWith('$(')) { - contributed.icon = contributed.icon.substring(2, contributed.icon.length - 1); - } - const icon = contributed.icon && typeof contributed.icon === 'string' ? (iconRegistry.get(contributed.icon) || Codicon.terminal) : Codicon.terminal; - const uriClasses = getUriClasses(contributed, this._themeService.getColorTheme().type, true); - const colorClass = getColorClass(contributed); - const iconClasses = []; - if (uriClasses) { - iconClasses.push(...uriClasses); - } - if (colorClass) { - iconClasses.push(colorClass); - } - contributedProfiles.push({ - label: `$(${icon.id}) ${contributed.title}`, - profile: { - extensionIdentifier: contributed.extensionIdentifier, - title: contributed.title, - icon: contributed.icon, - id: contributed.id, - color: contributed.color - }, - profileName: contributed.title, - iconClasses - }); - } - - if (contributedProfiles.length > 0) { - quickPickItems.push(...this._sortProfileQuickPickItems(contributedProfiles, defaultProfileName)); - } - - if (autoDetectedProfiles.length > 0) { - quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles.detected', "detected") }); - quickPickItems.push(...this._sortProfileQuickPickItems(autoDetectedProfiles.map(e => this._createProfileQuickPickItem(e)), defaultProfileName)); - } - const styleElement = getColorStyleElement(this._themeService.getColorTheme()); - document.body.appendChild(styleElement); - - const value = await this._quickInputService.pick(quickPickItems, options); - document.body.removeChild(styleElement); - if (!value) { - return; - } - if (type === 'createInstance') { - const activeInstance = this.getDefaultInstanceHost().activeInstance; - let instance; - - if ('id' in value.profile) { - await this.createContributedTerminalProfile(value.profile.extensionIdentifier, value.profile.id, { - icon: value.profile.icon, - color: value.profile.color, - location: !!(keyMods?.alt && activeInstance) ? { splitActiveTerminal: true } : this.defaultLocation - }); - return; - } else { - if (keyMods?.alt && activeInstance) { - // create split, only valid if there's an active instance - instance = await this.createTerminal({ location: { parentTerminal: activeInstance }, config: value.profile }); - } else { - instance = await this.createTerminal({ location: this.defaultLocation, config: value.profile, cwd }); - } - } - - if (instance && this.defaultLocation !== TerminalLocation.Editor) { - this._terminalGroupService.showPanel(true); - this.setActiveInstance(instance); - return instance; - } - } else { // setDefault - if ('command' in value.profile) { - return; // Should never happen - } else if ('id' in value.profile) { - // extension contributed profile - await this._configurationService.updateValue(defaultProfileKey, value.profile.title, ConfigurationTarget.USER); - - this._terminalProfileService.registerContributedProfile(value.profile.extensionIdentifier, value.profile.id, value.profile.title, { - color: value.profile.color, - icon: value.profile.icon - }); - return; - } - } - - // Add the profile to settings if necessary - if (value.profile.isAutoDetected) { - const profilesConfig = await this._configurationService.getValue(profilesKey); - if (typeof profilesConfig === 'object') { - const newProfile: ITerminalProfileObject = { - path: value.profile.path - }; - if (value.profile.args) { - newProfile.args = value.profile.args; - } - (profilesConfig as { [key: string]: ITerminalProfileObject })[value.profile.profileName] = newProfile; - } - await this._configurationService.updateValue(profilesKey, profilesConfig, ConfigurationTarget.USER); - } - // Set the default profile - await this._configurationService.updateValue(defaultProfileKey, value.profile.profileName, ConfigurationTarget.USER); - return undefined; - } - - getDefaultInstanceHost(): ITerminalInstanceHost { if (this.defaultLocation === TerminalLocation.Editor) { return this._terminalEditorService; @@ -1042,46 +910,6 @@ export class TerminalService implements ITerminalService { return instance?.target === TerminalLocation.Editor ? this._terminalEditorService : this._terminalGroupService; } - private _createProfileQuickPickItem(profile: ITerminalProfile): IProfileQuickPickItem { - const buttons: IQuickInputButton[] = [{ - iconClass: ThemeIcon.asClassName(configureTerminalProfileIcon), - tooltip: nls.localize('createQuickLaunchProfile', "Configure Terminal Profile") - }]; - const icon = (profile.icon && ThemeIcon.isThemeIcon(profile.icon)) ? profile.icon : Codicon.terminal; - const label = `$(${icon.id}) ${profile.profileName}`; - const colorClass = getColorClass(profile); - const iconClasses = []; - if (colorClass) { - iconClasses.push(colorClass); - } - - if (profile.args) { - if (typeof profile.args === 'string') { - return { label, description: `${profile.path} ${profile.args}`, profile, profileName: profile.profileName, buttons, iconClasses }; - } - const argsString = profile.args.map(e => { - if (e.includes(' ')) { - return `"${e.replace('/"/g', '\\"')}"`; - } - return e; - }).join(' '); - return { label, description: `${profile.path} ${argsString}`, profile, profileName: profile.profileName, buttons, iconClasses }; - } - return { label, description: profile.path, profile, profileName: profile.profileName, buttons, iconClasses }; - } - - private _sortProfileQuickPickItems(items: IProfileQuickPickItem[], defaultProfileName: string) { - return items.sort((a, b) => { - if (b.profileName === defaultProfileName) { - return 1; - } - if (a.profileName === defaultProfileName) { - return -1; - } - return a.profileName.localeCompare(b.profileName); - }); - } - private _convertProfileToShellLaunchConfig(shellLaunchConfigOrProfile?: IShellLaunchConfig | ITerminalProfile, cwd?: string | URI): IShellLaunchConfig { if (shellLaunchConfigOrProfile && 'profileName' in shellLaunchConfigOrProfile) { const profile = shellLaunchConfigOrProfile; @@ -1297,11 +1125,6 @@ export class TerminalService implements ITerminalService { } } -interface IProfileQuickPickItem extends IQuickPickItem { - profile: ITerminalProfile | IExtensionTerminalProfile; - profileName: string; -} - class TerminalEditorStyle extends Themable { private _styleElement: HTMLElement; diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index bf99ce95676..35bdcce9826 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -57,17 +57,22 @@ export interface ITerminalProfileResolverService { createProfileFromShellAndShellArgs(shell?: unknown, shellArgs?: unknown): Promise; } +export interface IRegisterContributedProfileArgs { + extensionIdentifier: string, id: string, title: string, options: ICreateContributedTerminalProfileOptions; +} + export const ITerminalProfileService = createDecorator('terminalProfileService'); export interface ITerminalProfileService { readonly _serviceBrand: undefined; readonly availableProfiles: ITerminalProfile[]; readonly contributedProfiles: IExtensionTerminalProfile[]; readonly profilesReady: Promise; + getPlatformKey(): Promise; refreshAvailableProfiles(): void; getDefaultProfileName(): string | undefined; onDidChangeAvailableProfiles: Event; getContributedDefaultProfile(shellLaunchConfig: IShellLaunchConfig): Promise; - registerContributedProfile(extensionIdentifier: string, id: string, title: string, options: ICreateContributedTerminalProfileOptions): Promise; + registerContributedProfile(args: IRegisterContributedProfileArgs): Promise; getContributedProfileProvider(extensionIdentifier: string, id: string): ITerminalProfileProvider | undefined; registerTerminalProfileProvider(extensionIdentifier: string, id: string, profileProvider: ITerminalProfileProvider): IDisposable; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/terminalProfileService.test.ts b/src/vs/workbench/contrib/terminal/test/browser/terminalProfileService.test.ts index e5e070b430e..7a92132511c 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/terminalProfileService.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/terminalProfileService.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { ITerminalConfiguration, ITerminalBackend } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalConfiguration, ITerminalBackend, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices'; import { TerminalProfileService } from 'vs/workbench/contrib/terminal/browser/terminalProfileService'; @@ -19,12 +19,16 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { Codicon } from 'vs/base/common/codicons'; import { deepStrictEqual } from 'assert'; import { Emitter } from 'vs/base/common/event'; +import { IProfileQuickPickItem, TerminalProfileQuickpick } from 'vs/workbench/contrib/terminal/browser/terminalProfileQuickpick'; +import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; +import { IPickOptions, IQuickInputService, Omit, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; +import { CancellationToken } from 'vs/base/common/cancellation'; -class TestTerminalProfileService extends TerminalProfileService { +class TestTerminalProfileService extends TerminalProfileService implements Partial{ hasRefreshedProfiles: Promise | undefined; override refreshAvailableProfiles(): void { this.hasRefreshedProfiles = this._refreshAvailableProfilesNow(); @@ -38,6 +42,46 @@ class TestTerminalProfileService extends TerminalProfileService { } } +class MockTerminalProfileService implements Partial{ + hasRefreshedProfiles: Promise | undefined; + _defaultProfileName: string | undefined; + availableProfiles?: ITerminalProfile[] | undefined = []; + contributedProfiles?: IExtensionTerminalProfile[] | undefined = []; + async getPlatformKey(): Promise { + return 'linux'; + } + getDefaultProfileName(): string | undefined { + return this._defaultProfileName; + } + setProfiles(profiles: ITerminalProfile[], contributed: IExtensionTerminalProfile[]): void { + this.availableProfiles = profiles; + this.contributedProfiles = contributed; + } + setDefaultProfileName(name: string): void { + this._defaultProfileName = name; + } +} + + +class MockQuickInputService implements Partial { + _pick: IProfileQuickPickItem = powershellPick; + pick(picks: QuickPickInput[] | Promise[]>, options?: IPickOptions & { canPickMany: true; }, token?: CancellationToken): Promise; + pick(picks: QuickPickInput[] | Promise[]>, options?: IPickOptions & { canPickMany: false; }, token?: CancellationToken): Promise; + pick(picks: QuickPickInput[] | Promise[]>, options?: Omit, 'canPickMany'>, token?: CancellationToken): Promise; + async pick(picks: any, options?: any, token?: any): Promise { + Promise.resolve(picks); + return this._pick; + } + + setPick(pick: IProfileQuickPickItem) { + this._pick = pick; + } +} + +class TestTerminalProfileQuickpick extends TerminalProfileQuickpick { + +} + class TestTerminalExtensionService extends TestExtensionService { readonly _onDidChangeExtensions = new Emitter(); } @@ -96,7 +140,8 @@ let jsdebugProfile = { id: 'extension.js-debug.debugTerminal', title: 'JavaScript Debug Terminal' }; - +let powershellPick = { label: 'Powershell', profile: powershellProfile, profileName: powershellProfile.profileName }; +let jsdebugPick = { label: 'Javascript Debug Terminal', profile: jsdebugProfile, profileName: jsdebugProfile.title }; suite('TerminalProfileService', () => { let configurationService: TestConfigurationService; @@ -115,6 +160,7 @@ suite('TerminalProfileService', () => { environmentService = { configuration: {}, remoteAuthority: undefined } as IWorkbenchEnvironmentService; instantiationService = new TestInstantiationService(); + let themeService = new TestThemeService(); let terminalContributionService = new TestTerminalContributionService(); let contextKeyService = new MockContextKeyService(); @@ -125,6 +171,7 @@ suite('TerminalProfileService', () => { instantiationService.stub(ITerminalContributionService, terminalContributionService); instantiationService.stub(ITerminalInstanceService, terminalInstanceService); instantiationService.stub(IWorkbenchEnvironmentService, environmentService); + instantiationService.stub(IThemeService, themeService); terminalProfileService = instantiationService.createInstance(TestTerminalProfileService); @@ -283,4 +330,62 @@ suite('TerminalProfileService', () => { deepStrictEqual(terminalProfileService.availableProfiles, [powershellProfile]); deepStrictEqual(terminalProfileService.contributedProfiles, [jsdebugProfile]); }); + suite('Profiles Quickpick', () => { + let quickInputService: MockQuickInputService; + let mockTerminalProfileService: MockTerminalProfileService; + let terminalProfileQuickpick: TestTerminalProfileQuickpick; + setup(async () => { + quickInputService = new MockQuickInputService(); + mockTerminalProfileService = new MockTerminalProfileService(); + instantiationService.stub(IQuickInputService, quickInputService); + instantiationService.stub(ITerminalProfileService, mockTerminalProfileService); + terminalProfileQuickpick = instantiationService.createInstance(TestTerminalProfileQuickpick); + }); + test('setDefault', async () => { + powershellProfile.isDefault = false; + mockTerminalProfileService.setProfiles([powershellProfile], [jsdebugProfile]); + mockTerminalProfileService.setDefaultProfileName(jsdebugProfile.title); + const result = await terminalProfileQuickpick.showAndGetResult('setDefault'); + deepStrictEqual(result, powershellProfile.profileName); + }); + test('setDefault to contributed', async () => { + mockTerminalProfileService.setDefaultProfileName(powershellProfile.profileName); + quickInputService.setPick(jsdebugPick); + const result = await terminalProfileQuickpick.showAndGetResult('setDefault'); + const expected = { + config: { + extensionIdentifier: jsdebugProfile.extensionIdentifier, + id: jsdebugProfile.id, + options: { color: undefined, icon: 'debug' }, + title: jsdebugProfile.title, + }, + keyMods: undefined + }; + deepStrictEqual(result, expected); + }); + + test('createInstance', async () => { + mockTerminalProfileService.setDefaultProfileName(powershellProfile.profileName); + const pick = { ...powershellPick, keyMods: { alt: true, ctrlCmd: false } }; + quickInputService.setPick(pick); + const result = await terminalProfileQuickpick.showAndGetResult('createInstance'); + deepStrictEqual(result, { config: powershellProfile, keyMods: { alt: true, ctrlCmd: false } }); + }); + + test('createInstance with contributed', async () => { + const pick = { ...jsdebugPick, keyMods: { alt: true, ctrlCmd: false } }; + quickInputService.setPick(pick); + const result = await terminalProfileQuickpick.showAndGetResult('createInstance'); + const expected = { + config: { + extensionIdentifier: jsdebugProfile.extensionIdentifier, + id: jsdebugProfile.id, + options: { color: undefined, icon: 'debug' }, + title: jsdebugProfile.title, + }, + keyMods: { alt: true, ctrlCmd: false } + }; + deepStrictEqual(result, expected); + }); + }); }); From 87ea829ceffa8bfbe3ce69f5314b5e33a364615e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 13:55:56 -0800 Subject: [PATCH 81/83] Move notebook setting keys into a namespace Adds a new `NotebookSettings` namespace to hold notebook settings keys --- .../gettingStarted/notebookGettingStarted.ts | 6 +- .../browser/contrib/layout/layoutActions.ts | 6 +- .../contrib/profile/notebookProfile.ts | 64 +++++++-------- .../browser/controller/executeActions.ts | 10 +-- .../browser/controller/insertCellActions.ts | 4 +- .../browser/controller/layoutActions.ts | 8 +- .../notebook/browser/notebook.contribution.ts | 40 +++++----- .../notebook/browser/notebookServiceImpl.ts | 10 +-- .../view/output/transforms/richTransform.ts | 6 +- .../viewParts/notebookEditorToolbar.ts | 8 +- .../contrib/notebook/common/notebookCommon.ts | 43 +++++----- .../notebook/common/notebookOptions.ts | 78 +++++++++---------- .../common/gettingStartedContent.ts | 4 +- 13 files changed, 145 insertions(+), 142 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts index e13987153f8..18965b389d0 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts @@ -16,7 +16,7 @@ import { CATEGORIES } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Memento } from 'vs/workbench/common/memento'; import { HAS_OPENED_NOTEBOOK } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { OpenGettingStarted } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -45,7 +45,7 @@ export class NotebookGettingStarted extends Disposable implements IWorkbenchCont hasOpenedNotebook.set(true); } - const needToShowGettingStarted = _configurationService.getValue(OpenGettingStarted) && !storedValue[hasShownGettingStartedKey]; + const needToShowGettingStarted = _configurationService.getValue(NotebookSetting.openGettingStarted) && !storedValue[hasShownGettingStartedKey]; if (!storedValue[hasOpenedNotebookKey] || needToShowGettingStarted) { const onDidOpenNotebook = () => { hasOpenedNotebook.set(true); @@ -83,7 +83,7 @@ registerAction2(class NotebookClearNotebookLayoutAction extends Action2 { id: 'workbench.notebook.layout.gettingStarted', title: localize('workbench.notebook.layout.gettingStarted.label', "Reset notebook getting started"), f1: true, - precondition: ContextKeyExpr.equals(`config.${OpenGettingStarted}`, true), + precondition: ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true), category: CATEGORIES.Developer, }); } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts index c764085038f..fe1c2706c22 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts @@ -8,7 +8,7 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { INotebookActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; -import { CellToolbarLocation } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const TOGGLE_CELL_TOOLBAR_POSITION = 'notebook.toggleCellToolbarPosition'; @@ -33,9 +33,9 @@ export class ToggleCellToolbarPositionAction extends Action2 { // from toolbar const viewType = editor.textModel.viewType; const configurationService = accessor.get(IConfigurationService); - const toolbarPosition = configurationService.getValue(CellToolbarLocation); + const toolbarPosition = configurationService.getValue(NotebookSetting.cellToolbarLocation); const newConfig = this.togglePosition(viewType, toolbarPosition); - await configurationService.updateValue(CellToolbarLocation, newConfig); + await configurationService.updateValue(NotebookSetting.cellToolbarLocation, newConfig); } } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts index 090e1383270..350e3c7e7d1 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts @@ -9,7 +9,7 @@ import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CellToolbarLocation, CompactView, ConsolidatedRunButton, FocusIndicator, GlobalToolbar, InsertToolbarLocation, ShowCellStatusBar, UndoRedoPerCell } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -22,34 +22,34 @@ export enum NotebookProfileType { const profiles = { [NotebookProfileType.default]: { - [FocusIndicator]: 'gutter', - [InsertToolbarLocation]: 'both', - [GlobalToolbar]: true, - [CellToolbarLocation]: { default: 'right' }, - [CompactView]: true, - [ShowCellStatusBar]: 'visible', - [ConsolidatedRunButton]: true, - [UndoRedoPerCell]: false + [NotebookSetting.focusIndicator]: 'gutter', + [NotebookSetting.insertToolbarLocation]: 'both', + [NotebookSetting.globalToolbar]: true, + [NotebookSetting.cellToolbarLocation]: { default: 'right' }, + [NotebookSetting.compactView]: true, + [NotebookSetting.showCellStatusBar]: 'visible', + [NotebookSetting.consolidatedRunButton]: true, + [NotebookSetting.undoRedoPerCell]: false }, [NotebookProfileType.jupyter]: { - [FocusIndicator]: 'gutter', - [InsertToolbarLocation]: 'notebookToolbar', - [GlobalToolbar]: true, - [CellToolbarLocation]: { default: 'left' }, - [CompactView]: true, - [ShowCellStatusBar]: 'visible', - [ConsolidatedRunButton]: false, - [UndoRedoPerCell]: true + [NotebookSetting.focusIndicator]: 'gutter', + [NotebookSetting.insertToolbarLocation]: 'notebookToolbar', + [NotebookSetting.globalToolbar]: true, + [NotebookSetting.cellToolbarLocation]: { default: 'left' }, + [NotebookSetting.compactView]: true, + [NotebookSetting.showCellStatusBar]: 'visible', + [NotebookSetting.consolidatedRunButton]: false, + [NotebookSetting.undoRedoPerCell]: true }, [NotebookProfileType.colab]: { - [FocusIndicator]: 'border', - [InsertToolbarLocation]: 'betweenCells', - [GlobalToolbar]: false, - [CellToolbarLocation]: { default: 'right' }, - [CompactView]: false, - [ShowCellStatusBar]: 'hidden', - [ConsolidatedRunButton]: true, - [UndoRedoPerCell]: false + [NotebookSetting.focusIndicator]: 'border', + [NotebookSetting.insertToolbarLocation]: 'betweenCells', + [NotebookSetting.globalToolbar]: false, + [NotebookSetting.cellToolbarLocation]: { default: 'right' }, + [NotebookSetting.compactView]: false, + [NotebookSetting.showCellStatusBar]: 'hidden', + [NotebookSetting.consolidatedRunButton]: true, + [NotebookSetting.undoRedoPerCell]: false } }; @@ -101,13 +101,13 @@ export class NotebookProfileContribution extends Disposable { return; } else { // check if settings are already modified - const focusIndicator = configService.getValue(FocusIndicator); - const insertToolbarPosition = configService.getValue(InsertToolbarLocation); - const globalToolbar = configService.getValue(GlobalToolbar); - // const cellToolbarLocation = configService.getValue(CellToolbarLocation); - const compactView = configService.getValue(CompactView); - const showCellStatusBar = configService.getValue(ShowCellStatusBar); - const consolidatedRunButton = configService.getValue(ConsolidatedRunButton); + const focusIndicator = configService.getValue(NotebookSetting.focusIndicator); + const insertToolbarPosition = configService.getValue(NotebookSetting.insertToolbarLocation); + const globalToolbar = configService.getValue(NotebookSetting.globalToolbar); + // const cellToolbarLocation = configService.getValue(NotebookSetting.cellToolbarLocation); + const compactView = configService.getValue(NotebookSetting.compactView); + const showCellStatusBar = configService.getValue(NotebookSetting.showCellStatusBar); + const consolidatedRunButton = configService.getValue(NotebookSetting.consolidatedRunButton); if (focusIndicator === 'border' && insertToolbarPosition === 'both' && globalToolbar === false diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index 83cdd5c305d..a57d2d97203 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -17,7 +17,7 @@ import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cel import { cellExecutionArgs, CellToolbarOrder, CELL_TITLE_CELL_GROUP_ID, executeNotebookCondition, getContextFromActiveEditor, getContextFromUri, INotebookActionContext, INotebookCellActionContext, INotebookCellToolbarActionContext, INotebookCommandContext, NotebookAction, NotebookCellAction, NotebookMultiCellAction, NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT, parseMultiCellExecutionArgs } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_MISSING_KERNEL_EXTENSION } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { CellKind, ConsolidatedRunButton, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookSetting, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -207,7 +207,7 @@ registerAction2(class ExecuteAboveCells extends NotebookMultiCellAction { id: MenuId.NotebookCellExecute, when: ContextKeyExpr.and( executeCondition, - ContextKeyExpr.equals(`config.${ConsolidatedRunButton}`, true)) + ContextKeyExpr.equals(`config.${NotebookSetting.consolidatedRunButton}`, true)) }, { id: MenuId.NotebookCellTitle, @@ -215,7 +215,7 @@ registerAction2(class ExecuteAboveCells extends NotebookMultiCellAction { group: CELL_TITLE_CELL_GROUP_ID, when: ContextKeyExpr.and( executeCondition, - ContextKeyExpr.equals(`config.${ConsolidatedRunButton}`, false)) + ContextKeyExpr.equals(`config.${NotebookSetting.consolidatedRunButton}`, false)) } ], icon: icons.executeAboveIcon @@ -253,7 +253,7 @@ registerAction2(class ExecuteCellAndBelow extends NotebookMultiCellAction { id: MenuId.NotebookCellExecute, when: ContextKeyExpr.and( executeCondition, - ContextKeyExpr.equals(`config.${ConsolidatedRunButton}`, true)) + ContextKeyExpr.equals(`config.${NotebookSetting.consolidatedRunButton}`, true)) }, { id: MenuId.NotebookCellTitle, @@ -261,7 +261,7 @@ registerAction2(class ExecuteCellAndBelow extends NotebookMultiCellAction { group: CELL_TITLE_CELL_GROUP_ID, when: ContextKeyExpr.and( executeCondition, - ContextKeyExpr.equals(`config.${ConsolidatedRunButton}`, false)) + ContextKeyExpr.equals(`config.${NotebookSetting.consolidatedRunButton}`, false)) } ], icon: icons.executeBelowIcon diff --git a/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts index c15d0bfb871..c88434cf848 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts @@ -16,7 +16,7 @@ import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cel import { INotebookActionContext, NotebookAction } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_EDITOR_EDITABLE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { CellKind, GlobalToolbarShowLabel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const INSERT_CODE_CELL_ABOVE_COMMAND_ID = 'notebook.cell.insertCodeCellAbove'; const INSERT_CODE_CELL_BELOW_COMMAND_ID = 'notebook.cell.insertCodeCellBelow'; @@ -323,7 +323,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, { NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'betweenCells'), ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'hidden'), - ContextKeyExpr.notEquals(`config.${GlobalToolbarShowLabel}`, false) + ContextKeyExpr.notEquals(`config.${NotebookSetting.globalToolbarShowLabel}`, false) ) }); diff --git a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts index c3f39c3cb4e..9e16c29d0e4 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts @@ -13,7 +13,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { OpenGettingStarted } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; @@ -23,7 +23,7 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { id: 'workbench.notebook.layout.select', title: localize('workbench.notebook.layout.select.label', "Select between Notebook Layouts"), f1: true, - precondition: ContextKeyExpr.equals(`config.${OpenGettingStarted}`, true), + precondition: ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true), category: NOTEBOOK_ACTIONS_CATEGORY, menu: [ { @@ -32,7 +32,7 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { when: ContextKeyExpr.and( NOTEBOOK_IS_ACTIVE_EDITOR, ContextKeyExpr.notEquals('config.notebook.globalToolbar', true), - ContextKeyExpr.equals(`config.${OpenGettingStarted}`, true) + ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true) ), order: 0 }, @@ -41,7 +41,7 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { group: 'notebookLayout', when: ContextKeyExpr.and( ContextKeyExpr.equals('config.notebook.globalToolbar', true), - ContextKeyExpr.equals(`config.${OpenGettingStarted}`, true) + ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true) ), order: 0 } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index d9e3465f648..d70cb4a6b1b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -30,7 +30,7 @@ import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEd import { isCompositeNotebookEditorInput, NotebookEditorInput, NotebookEditorInputOptions } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { NotebookService } from 'vs/workbench/contrib/notebook/browser/notebookServiceImpl'; -import { CellKind, CellToolbarLocation, CellToolbarVisibility, CellUri, DisplayOrderKey, UndoRedoPerCell, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookTextDiffEditorPreview, NotebookWorkingCopyTypeIdentifier, ShowCellStatusBar, CompactView, FocusIndicator, InsertToolbarLocation, GlobalToolbar, ConsolidatedOutputButton, ShowFoldingControls, DragAndDropEnabled, NotebookCellEditorOptionsCustomizations, ConsolidatedRunButton, TextOutputLineLimit, GlobalToolbarShowLabel, IOutputItemDto, NotebookMarkupFontSize } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellUri, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookWorkingCopyTypeIdentifier, NotebookSetting, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; @@ -208,7 +208,7 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri ) { super(); - const undoRedoPerCell = configurationService.getValue(UndoRedoPerCell); + const undoRedoPerCell = configurationService.getValue(NotebookSetting.undoRedoPerCell); this._register(undoRedoService.registerUriComparisonKeyComputer(CellUri.scheme, { getComparisonKey: (uri: URI): string => { @@ -656,7 +656,7 @@ configurationRegistry.registerConfiguration({ title: nls.localize('notebookConfigurationTitle', "Notebook"), type: 'object', properties: { - [DisplayOrderKey]: { + [NotebookSetting.displayOrder]: { description: nls.localize('notebook.displayOrder.description', "Priority list for output mime types"), type: ['array'], items: { @@ -664,7 +664,7 @@ configurationRegistry.registerConfiguration({ }, default: [] }, - [CellToolbarLocation]: { + [NotebookSetting.cellToolbarLocation]: { description: nls.localize('notebook.cellToolbarLocation.description', "Where the cell toolbar should be shown, or whether it should be hidden."), type: 'object', additionalProperties: { @@ -677,7 +677,7 @@ configurationRegistry.registerConfiguration({ }, tags: ['notebookLayout'] }, - [ShowCellStatusBar]: { + [NotebookSetting.showCellStatusBar]: { description: nls.localize('notebook.showCellStatusbar.description', "Whether the cell status bar should be shown."), type: 'string', enum: ['hidden', 'visible', 'visibleAfterExecute'], @@ -688,39 +688,39 @@ configurationRegistry.registerConfiguration({ default: 'visible', tags: ['notebookLayout'] }, - [NotebookTextDiffEditorPreview]: { + [NotebookSetting.textDiffEditorPreview]: { description: nls.localize('notebook.diff.enablePreview.description', "Whether to use the enhanced text diff editor for notebook."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [CellToolbarVisibility]: { + [NotebookSetting.cellToolbarVisibility]: { markdownDescription: nls.localize('notebook.cellToolbarVisibility.description', "Whether the cell toolbar should appear on hover or click."), type: 'string', enum: ['hover', 'click'], default: 'click', tags: ['notebookLayout'] }, - [UndoRedoPerCell]: { + [NotebookSetting.undoRedoPerCell]: { description: nls.localize('notebook.undoRedoPerCell.description', "Whether to use separate undo/redo stack for each cell."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [CompactView]: { + [NotebookSetting.compactView]: { description: nls.localize('notebook.compactView.description', "Control whether the notebook editor should be rendered in a compact form. For example, when turned on, it will decrease the left margin width."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [FocusIndicator]: { + [NotebookSetting.focusIndicator]: { description: nls.localize('notebook.focusIndicator.description', "Controls where the focus indicator is rendered, either along the cell borders or on the left gutter"), type: 'string', enum: ['border', 'gutter'], default: 'gutter', tags: ['notebookLayout'] }, - [InsertToolbarLocation]: { + [NotebookSetting.insertToolbarLocation]: { description: nls.localize('notebook.insertToolbarPosition.description', "Control where the insert cell actions should appear."), type: 'string', enum: ['betweenCells', 'notebookToolbar', 'both', 'hidden'], @@ -733,19 +733,19 @@ configurationRegistry.registerConfiguration({ default: 'both', tags: ['notebookLayout'] }, - [GlobalToolbar]: { + [NotebookSetting.globalToolbar]: { description: nls.localize('notebook.globalToolbar.description', "Control whether to render a global toolbar inside the notebook editor."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [ConsolidatedOutputButton]: { + [NotebookSetting.consolidatedOutputButton]: { description: nls.localize('notebook.consolidatedOutputButton.description', "Control whether outputs action should be rendered in the output toolbar."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [ShowFoldingControls]: { + [NotebookSetting.showFoldingControls]: { description: nls.localize('notebook.showFoldingControls.description', "Controls when the Markdown header folding arrow is shown."), type: 'string', enum: ['always', 'mouseover'], @@ -756,36 +756,36 @@ configurationRegistry.registerConfiguration({ default: 'mouseover', tags: ['notebookLayout'] }, - [DragAndDropEnabled]: { + [NotebookSetting.dragAndDropEnabled]: { description: nls.localize('notebook.dragAndDrop.description', "Control whether the notebook editor should allow moving cells through drag and drop."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [ConsolidatedRunButton]: { + [NotebookSetting.consolidatedRunButton]: { description: nls.localize('notebook.consolidatedRunButton.description', "Control whether extra actions are shown in a dropdown next to the run button."), type: 'boolean', default: false, tags: ['notebookLayout'] }, - [GlobalToolbarShowLabel]: { + [NotebookSetting.globalToolbarShowLabel]: { description: nls.localize('notebook.globalToolbarShowLabel', "Control whether the actions on the notebook toolbar should render label or not."), type: 'boolean', default: true, tags: ['notebookLayout'] }, - [TextOutputLineLimit]: { + [NotebookSetting.textOutputLineLimit]: { description: nls.localize('notebook.textOutputLineLimit', "Control how many lines of text in a text output is rendered."), type: 'number', default: 30, tags: ['notebookLayout'] }, - [NotebookMarkupFontSize]: { + [NotebookSetting.markupFontSize]: { markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size of rendered markup in notebooks. When set to `0`, the value of `#editor.fontSize#` is used."), type: 'number', default: 0, tags: ['notebookLayout'] }, - [NotebookCellEditorOptionsCustomizations]: editorOptionsCustomizationSchema + [NotebookSetting.cellEditorOptionsCustomizations]: editorOptionsCustomizationSchema } }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index c1fd60d25a2..6f309a54847 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -30,7 +30,7 @@ import { INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/no import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, DisplayOrderKey, INotebookContributionData, INotebookExclusiveDocumentFilter, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, MimeTypeDisplayOrder, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookData, NotebookEditorPriority, NotebookRendererMatch, NotebookTextDiffEditorPreview, NOTEBOOK_DISPLAY_ORDER, RENDERER_EQUIVALENT_EXTENSIONS, RENDERER_NOT_AVAILABLE, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, NotebookSetting, INotebookContributionData, INotebookExclusiveDocumentFilter, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, MimeTypeDisplayOrder, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookData, NotebookEditorPriority, NotebookRendererMatch, NOTEBOOK_DISPLAY_ORDER, RENDERER_EQUIVALENT_EXTENSIONS, RENDERER_NOT_AVAILABLE, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { updateEditorTopPadding } from 'vs/workbench/contrib/notebook/common/notebookOptions'; @@ -161,7 +161,7 @@ export class NotebookProviderInfoStore extends Disposable { priority: notebookProviderInfo.exclusive ? RegisteredEditorPriority.exclusive : notebookProviderInfo.priority, }; const notebookEditorOptions = { - canHandleDiff: () => !!this._configurationService.getValue(NotebookTextDiffEditorPreview) && !this._accessibilityService.isScreenReaderOptimized(), + canHandleDiff: () => !!this._configurationService.getValue(NotebookSetting.textDiffEditorPreview) && !this._accessibilityService.isScreenReaderOptimized(), canSupportResource: (resource: URI) => resource.scheme === Schemas.untitled || resource.scheme === Schemas.vscodeNotebookCell || this._fileService.hasProvider(resource) }; const notebookEditorInputFactory: EditorInputFactoryFunction = ({ resource, options }) => { @@ -458,7 +458,7 @@ export class NotebookService extends Disposable implements INotebookService { const updateOrder = () => { this._displayOrder = new MimeTypeDisplayOrder( - this._configurationService.getValue(DisplayOrderKey) || [], + this._configurationService.getValue(NotebookSetting.displayOrder) || [], this._accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER, @@ -468,7 +468,7 @@ export class NotebookService extends Disposable implements INotebookService { updateOrder(); this._register(this._configurationService.onDidChangeConfiguration(e => { - if (e.affectedKeys.indexOf(DisplayOrderKey) >= 0) { + if (e.affectedKeys.indexOf(NotebookSetting.displayOrder) >= 0) { updateOrder(); } })); @@ -626,7 +626,7 @@ export class NotebookService extends Disposable implements INotebookService { } saveMimeDisplayOrder(target: ConfigurationTarget) { - this._configurationService.updateValue(DisplayOrderKey, this._displayOrder.toArray(), target); + this._configurationService.updateValue(NotebookSetting.displayOrder, this._displayOrder.toArray(), target); } getRenderers(): INotebookRendererInfo[] { diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index 5d0fcbd0a2a..57f448967a6 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -18,7 +18,7 @@ import { ICellOutputViewModel, IRenderOutput, RenderOutputType } from 'vs/workbe import { INotebookDelegateForOutput, IOutputTransformContribution as IOutputRendererContribution } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; import { OutputRendererRegistry } from 'vs/workbench/contrib/notebook/browser/view/output/rendererRegistry'; import { truncatedArrayOfString } from 'vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper'; -import { IOutputItemDto, TextOutputLineLimit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IOutputItemDto, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; class JavaScriptRendererContrib extends Disposable implements IOutputRendererContribution { @@ -74,7 +74,7 @@ class StreamRendererContrib extends Disposable implements IOutputRendererContrib const text = getStringValue(item); const contentNode = DOM.$('span.output-stream'); - const lineLimit = this.configurationService.getValue(TextOutputLineLimit) ?? 30; + const lineLimit = this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30; truncatedArrayOfString(notebookUri, output.cellViewModel, Math.max(lineLimit, 6), contentNode, [text], disposables, linkDetector, this.openerService, this.themeService); container.appendChild(contentNode); @@ -178,7 +178,7 @@ class PlainTextRendererContrib extends Disposable implements IOutputRendererCont const str = getStringValue(item); const contentNode = DOM.$('.output-plaintext'); - const lineLimit = this.configurationService.getValue(TextOutputLineLimit) ?? 30; + const lineLimit = this.configurationService.getValue(NotebookSetting.textOutputLineLimit) ?? 30; truncatedArrayOfString(notebookUri, output.cellViewModel, Math.max(lineLimit, 6), contentNode, [str], disposables, linkDetector, this.openerService, this.themeService); container.appendChild(contentNode); diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts index 8e1f4b086e7..2a32670df98 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts @@ -23,7 +23,7 @@ import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controll import { INotebookEditorDelegate, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebooKernelActionViewItem } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem'; import { ActionViewWithLabel } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; -import { GlobalToolbarShowLabel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService'; import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; @@ -114,7 +114,7 @@ export class NotebookEditorToolbar extends Disposable { this._register(this._notebookGlobalActionsMenu); this._useGlobalToolbar = this.notebookOptions.getLayoutConfiguration().globalToolbar; - this._renderLabel = this.configurationService.getValue(GlobalToolbarShowLabel); + this._renderLabel = this.configurationService.getValue(NotebookSetting.globalToolbarShowLabel); const context = { ui: true, @@ -184,8 +184,8 @@ export class NotebookEditorToolbar extends Disposable { })); this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(GlobalToolbarShowLabel)) { - this._renderLabel = this.configurationService.getValue(GlobalToolbarShowLabel); + if (e.affectsConfiguration(NotebookSetting.globalToolbarShowLabel)) { + this._renderLabel = this.configurationService.getValue(NotebookSetting.globalToolbarShowLabel); const oldElement = this._notebookLeftToolbar.getElement(); oldElement.parentElement?.removeChild(oldElement); this._notebookLeftToolbar.dispose(); diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 454d082a718..c495315f175 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -901,27 +901,30 @@ export interface INotebookCellStatusBarItemList { dispose?(): void; } -export const DisplayOrderKey = 'notebook.displayOrder'; -export const CellToolbarLocation = 'notebook.cellToolbarLocation'; -export const CellToolbarVisibility = 'notebook.cellToolbarVisibility'; export type ShowCellStatusBarType = 'hidden' | 'visible' | 'visibleAfterExecute'; -export const ShowCellStatusBar = 'notebook.showCellStatusBar'; -export const NotebookTextDiffEditorPreview = 'notebook.diff.enablePreview'; -export const ExperimentalInsertToolbarAlignment = 'notebook.experimental.insertToolbarAlignment'; -export const CompactView = 'notebook.compactView'; -export const FocusIndicator = 'notebook.cellFocusIndicator'; -export const InsertToolbarLocation = 'notebook.insertToolbarLocation'; -export const GlobalToolbar = 'notebook.globalToolbar'; -export const UndoRedoPerCell = 'notebook.undoRedoPerCell'; -export const ConsolidatedOutputButton = 'notebook.consolidatedOutputButton'; -export const ShowFoldingControls = 'notebook.showFoldingControls'; -export const DragAndDropEnabled = 'notebook.dragAndDropEnabled'; -export const NotebookCellEditorOptionsCustomizations = 'notebook.editorOptionsCustomizations'; -export const ConsolidatedRunButton = 'notebook.consolidatedRunButton'; -export const OpenGettingStarted = 'notebook.experimental.openGettingStarted'; -export const TextOutputLineLimit = 'notebook.output.textLineLimit'; -export const GlobalToolbarShowLabel = 'notebook.globalToolbarShowLabel'; -export const NotebookMarkupFontSize = 'notebook.markup.fontSize'; + +export const NotebookSetting = { + displayOrder: 'notebook.displayOrder', + cellToolbarLocation: 'notebook.cellToolbarLocation', + cellToolbarVisibility: 'notebook.cellToolbarVisibility', + showCellStatusBar: 'notebook.showCellStatusBar', + textDiffEditorPreview: 'notebook.diff.enablePreview', + experimentalInsertToolbarAlignment: 'notebook.experimental.insertToolbarAlignment', + compactView: 'notebook.compactView', + focusIndicator: 'notebook.cellFocusIndicator', + insertToolbarLocation: 'notebook.insertToolbarLocation', + globalToolbar: 'notebook.globalToolbar', + undoRedoPerCell: 'notebook.undoRedoPerCell', + consolidatedOutputButton: 'notebook.consolidatedOutputButton', + showFoldingControls: 'notebook.showFoldingControls', + dragAndDropEnabled: 'notebook.dragAndDropEnabled', + cellEditorOptionsCustomizations: 'notebook.editorOptionsCustomizations', + consolidatedRunButton: 'notebook.consolidatedRunButton', + openGettingStarted: 'notebook.experimental.openGettingStarted', + textOutputLineLimit: 'notebook.output.textLineLimit', + globalToolbarShowLabel: 'notebook.globalToolbarShowLabel', + markupFontSize: 'notebook.markup.fontSize', +} as const; export const enum CellStatusbarAlignment { Left = 1, diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index f8dd24f3b84..1c848245cac 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -6,7 +6,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CellToolbarLocation, CellToolbarVisibility, CompactView, ConsolidatedOutputButton, ConsolidatedRunButton, DragAndDropEnabled, ExperimentalInsertToolbarAlignment, FocusIndicator, GlobalToolbar, InsertToolbarLocation, NotebookCellEditorOptionsCustomizations, NotebookCellInternalMetadata, NotebookMarkupFontSize, ShowCellStatusBar, ShowCellStatusBarType, ShowFoldingControls } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookCellInternalMetadata, NotebookSetting, ShowCellStatusBarType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const SCROLLABLE_ELEMENT_PADDING_TOP = 18; @@ -111,22 +111,22 @@ export class NotebookOptions extends Disposable { constructor(private readonly configurationService: IConfigurationService, private readonly overrides?: { cellToolbarInteraction: string, globalToolbar: boolean }) { super(); - const showCellStatusBar = this.configurationService.getValue(ShowCellStatusBar); - const globalToolbar = overrides?.globalToolbar ?? this.configurationService.getValue(GlobalToolbar) ?? true; - const consolidatedOutputButton = this.configurationService.getValue(ConsolidatedOutputButton) ?? true; - const consolidatedRunButton = this.configurationService.getValue(ConsolidatedRunButton) ?? false; - const dragAndDropEnabled = this.configurationService.getValue(DragAndDropEnabled) ?? true; - const cellToolbarLocation = this.configurationService.getValue(CellToolbarLocation) ?? { 'default': 'right' }; - const cellToolbarInteraction = overrides?.cellToolbarInteraction ?? this.configurationService.getValue(CellToolbarVisibility); - const compactView = this.configurationService.getValue(CompactView) ?? true; + const showCellStatusBar = this.configurationService.getValue(NotebookSetting.showCellStatusBar); + const globalToolbar = overrides?.globalToolbar ?? this.configurationService.getValue(NotebookSetting.globalToolbar) ?? true; + const consolidatedOutputButton = this.configurationService.getValue(NotebookSetting.consolidatedOutputButton) ?? true; + const consolidatedRunButton = this.configurationService.getValue(NotebookSetting.consolidatedRunButton) ?? false; + const dragAndDropEnabled = this.configurationService.getValue(NotebookSetting.dragAndDropEnabled) ?? true; + const cellToolbarLocation = this.configurationService.getValue(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' }; + const cellToolbarInteraction = overrides?.cellToolbarInteraction ?? this.configurationService.getValue(NotebookSetting.cellToolbarVisibility); + const compactView = this.configurationService.getValue(NotebookSetting.compactView) ?? true; const focusIndicator = this._computeFocusIndicatorOption(); const insertToolbarPosition = this._computeInsertToolbarPositionOption(); const insertToolbarAlignment = this._computeInsertToolbarAlignmentOption(); const showFoldingControls = this._computeShowFoldingControlsOption(); // const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(compactView, insertToolbarPosition, insertToolbarAlignment); const fontSize = this.configurationService.getValue('editor.fontSize'); - const markupFontSize = this.configurationService.getValue(NotebookMarkupFontSize); - const editorOptionsCustomizations = this.configurationService.getValue(NotebookCellEditorOptionsCustomizations); + const markupFontSize = this.configurationService.getValue(NotebookSetting.markupFontSize); + const editorOptionsCustomizations = this.configurationService.getValue(NotebookSetting.cellEditorOptionsCustomizations); this._layoutConfiguration = { ...(compactView ? compactConfigConstants : defaultConfigConstants), @@ -173,21 +173,21 @@ export class NotebookOptions extends Disposable { } private _updateConfiguration(e: IConfigurationChangeEvent) { - const cellStatusBarVisibility = e.affectsConfiguration(ShowCellStatusBar); - const cellToolbarLocation = e.affectsConfiguration(CellToolbarLocation); - const cellToolbarInteraction = e.affectsConfiguration(CellToolbarVisibility); - const compactView = e.affectsConfiguration(CompactView); - const focusIndicator = e.affectsConfiguration(FocusIndicator); - const insertToolbarPosition = e.affectsConfiguration(InsertToolbarLocation); - const insertToolbarAlignment = e.affectsConfiguration(ExperimentalInsertToolbarAlignment); - const globalToolbar = e.affectsConfiguration(GlobalToolbar); - const consolidatedOutputButton = e.affectsConfiguration(ConsolidatedOutputButton); - const consolidatedRunButton = e.affectsConfiguration(ConsolidatedRunButton); - const showFoldingControls = e.affectsConfiguration(ShowFoldingControls); - const dragAndDropEnabled = e.affectsConfiguration(DragAndDropEnabled); + const cellStatusBarVisibility = e.affectsConfiguration(NotebookSetting.showCellStatusBar); + const cellToolbarLocation = e.affectsConfiguration(NotebookSetting.cellToolbarLocation); + const cellToolbarInteraction = e.affectsConfiguration(NotebookSetting.cellToolbarVisibility); + const compactView = e.affectsConfiguration(NotebookSetting.compactView); + const focusIndicator = e.affectsConfiguration(NotebookSetting.focusIndicator); + const insertToolbarPosition = e.affectsConfiguration(NotebookSetting.insertToolbarLocation); + const insertToolbarAlignment = e.affectsConfiguration(NotebookSetting.experimentalInsertToolbarAlignment); + const globalToolbar = e.affectsConfiguration(NotebookSetting.globalToolbar); + const consolidatedOutputButton = e.affectsConfiguration(NotebookSetting.consolidatedOutputButton); + const consolidatedRunButton = e.affectsConfiguration(NotebookSetting.consolidatedRunButton); + const showFoldingControls = e.affectsConfiguration(NotebookSetting.showFoldingControls); + const dragAndDropEnabled = e.affectsConfiguration(NotebookSetting.dragAndDropEnabled); const fontSize = e.affectsConfiguration('editor.fontSize'); - const markupFontSize = e.affectsConfiguration(NotebookMarkupFontSize); - const editorOptionsCustomizations = e.affectsConfiguration(NotebookCellEditorOptionsCustomizations); + const markupFontSize = e.affectsConfiguration(NotebookSetting.markupFontSize); + const editorOptionsCustomizations = e.affectsConfiguration(NotebookSetting.cellEditorOptionsCustomizations); if ( !cellStatusBarVisibility @@ -211,15 +211,15 @@ export class NotebookOptions extends Disposable { let configuration = Object.assign({}, this._layoutConfiguration); if (cellStatusBarVisibility) { - configuration.showCellStatusBar = this.configurationService.getValue(ShowCellStatusBar); + configuration.showCellStatusBar = this.configurationService.getValue(NotebookSetting.showCellStatusBar); } if (cellToolbarLocation) { - configuration.cellToolbarLocation = this.configurationService.getValue(CellToolbarLocation) ?? { 'default': 'right' }; + configuration.cellToolbarLocation = this.configurationService.getValue(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' }; } if (cellToolbarInteraction && !this.overrides?.cellToolbarInteraction) { - configuration.cellToolbarInteraction = this.configurationService.getValue(CellToolbarVisibility); + configuration.cellToolbarInteraction = this.configurationService.getValue(NotebookSetting.cellToolbarVisibility); } if (focusIndicator) { @@ -227,7 +227,7 @@ export class NotebookOptions extends Disposable { } if (compactView) { - const compactViewValue = this.configurationService.getValue(CompactView) ?? true; + const compactViewValue = this.configurationService.getValue(NotebookSetting.compactView) ?? true; configuration = Object.assign(configuration, { ...(compactViewValue ? compactConfigConstants : defaultConfigConstants), }); @@ -243,15 +243,15 @@ export class NotebookOptions extends Disposable { } if (globalToolbar && this.overrides?.globalToolbar === undefined) { - configuration.globalToolbar = this.configurationService.getValue(GlobalToolbar) ?? true; + configuration.globalToolbar = this.configurationService.getValue(NotebookSetting.globalToolbar) ?? true; } if (consolidatedOutputButton) { - configuration.consolidatedOutputButton = this.configurationService.getValue(ConsolidatedOutputButton) ?? true; + configuration.consolidatedOutputButton = this.configurationService.getValue(NotebookSetting.consolidatedOutputButton) ?? true; } if (consolidatedRunButton) { - configuration.consolidatedRunButton = this.configurationService.getValue(ConsolidatedRunButton) ?? true; + configuration.consolidatedRunButton = this.configurationService.getValue(NotebookSetting.consolidatedRunButton) ?? true; } if (showFoldingControls) { @@ -259,7 +259,7 @@ export class NotebookOptions extends Disposable { } if (dragAndDropEnabled) { - configuration.dragAndDropEnabled = this.configurationService.getValue(DragAndDropEnabled) ?? true; + configuration.dragAndDropEnabled = this.configurationService.getValue(NotebookSetting.dragAndDropEnabled) ?? true; } if (fontSize) { @@ -267,11 +267,11 @@ export class NotebookOptions extends Disposable { } if (markupFontSize) { - configuration.markupFontSize = this.configurationService.getValue(NotebookMarkupFontSize) || configuration.fontSize; + configuration.markupFontSize = this.configurationService.getValue(NotebookSetting.markupFontSize) || configuration.fontSize; } if (editorOptionsCustomizations) { - configuration.editorOptionsCustomizations = this.configurationService.getValue(NotebookCellEditorOptionsCustomizations); + configuration.editorOptionsCustomizations = this.configurationService.getValue(NotebookSetting.cellEditorOptionsCustomizations); } this._layoutConfiguration = Object.freeze(configuration); @@ -297,19 +297,19 @@ export class NotebookOptions extends Disposable { } private _computeInsertToolbarPositionOption() { - return this.configurationService.getValue<'betweenCells' | 'notebookToolbar' | 'both' | 'hidden'>(InsertToolbarLocation) ?? 'both'; + return this.configurationService.getValue<'betweenCells' | 'notebookToolbar' | 'both' | 'hidden'>(NotebookSetting.insertToolbarLocation) ?? 'both'; } private _computeInsertToolbarAlignmentOption() { - return this.configurationService.getValue<'left' | 'center'>(ExperimentalInsertToolbarAlignment) ?? 'center'; + return this.configurationService.getValue<'left' | 'center'>(NotebookSetting.experimentalInsertToolbarAlignment) ?? 'center'; } private _computeShowFoldingControlsOption() { - return this.configurationService.getValue<'always' | 'mouseover'>(ShowFoldingControls) ?? 'mouseover'; + return this.configurationService.getValue<'always' | 'mouseover'>(NotebookSetting.showFoldingControls) ?? 'mouseover'; } private _computeFocusIndicatorOption() { - return this.configurationService.getValue<'border' | 'gutter'>(FocusIndicator) ?? 'gutter'; + return this.configurationService.getValue<'border' | 'gutter'>(NotebookSetting.focusIndicator) ?? 'gutter'; } getLayoutConfiguration(): NotebookLayoutConfiguration { diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts index 62c5ac5b7fb..2218e71c907 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts @@ -9,7 +9,7 @@ import { localize } from 'vs/nls'; import { Codicon } from 'vs/base/common/codicons'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -import { OpenGettingStarted } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const setupIcon = registerIcon('getting-started-setup', Codicon.zap, localize('getting-started-setup-icon', "Icon used for the setup category of welcome page")); @@ -483,7 +483,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ description: '', icon: setupIcon, isFeatured: false, - when: `config.${OpenGettingStarted} && userHasOpenedNotebook`, + when: `config.${NotebookSetting.openGettingStarted} && userHasOpenedNotebook`, content: { type: 'steps', steps: [ From a4ad395f23ab80d535730574c3ac82b84c779d72 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 9 Nov 2021 14:22:47 -0800 Subject: [PATCH 82/83] Increase default markup font size For #126294 --- extensions/markdown-language-features/notebook/index.ts | 4 ---- .../contrib/notebook/browser/notebook.contribution.ts | 2 +- .../notebook/browser/view/renderers/backLayerWebView.ts | 2 +- src/vs/workbench/contrib/notebook/common/notebookOptions.ts | 4 ++-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 2586457e2c2..342fa97a954 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -29,10 +29,6 @@ export const activate: ActivationFunction = (ctx) => { const style = document.createElement('style'); style.textContent = ` - #preview { - font-size: 1.1em; - } - .emptyMarkdownCell::before { content: "${document.documentElement.style.getPropertyValue('--notebook-cell-markup-empty-content')}"; font-style: italic; diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index d70cb4a6b1b..5616612cf15 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -781,7 +781,7 @@ configurationRegistry.registerConfiguration({ tags: ['notebookLayout'] }, [NotebookSetting.markupFontSize]: { - markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size of rendered markup in notebooks. When set to `0`, the value of `#editor.fontSize#` is used."), + markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size of rendered markup in notebooks. When set to `0`, 120% `#editor.fontSize#` is used."), type: 'number', default: 0, tags: ['notebookLayout'] diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index d4e31753528..4697b6c5cd2 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -221,7 +221,7 @@ export class BackLayerWebView extends Disposable { 'notebook-markdown-left-margin': `${this.options.markdownLeftMargin}px`, 'notebook-output-node-left-padding': `${this.options.outputNodeLeftPadding}px`, 'notebook-markdown-min-height': `${this.options.previewNodePadding * 2}px`, - 'notebook-markup-font-size': `${this.options.markupFontSize}px`, + 'notebook-markup-font-size': typeof this.options.markupFontSize === 'number' && this.options.markupFontSize > 0 ? `${this.options.markupFontSize}px` : `calc(${this.options.fontSize}px * 1.2)`, 'notebook-cell-output-font-size': `${this.options.fontSize}px`, 'notebook-cell-markup-empty-content': nls.localize('notebook.emptyMarkdownPlaceholder', "Empty markdown cell, double click or press enter to edit."), 'notebook-cell-renderer-not-found-error': nls.localize({ diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 1c848245cac..040cedd0bd6 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -156,7 +156,7 @@ export class NotebookOptions extends Disposable { insertToolbarAlignment, showFoldingControls, fontSize, - markupFontSize: markupFontSize > 0 ? markupFontSize : fontSize, + markupFontSize, editorOptionsCustomizations, }; @@ -267,7 +267,7 @@ export class NotebookOptions extends Disposable { } if (markupFontSize) { - configuration.markupFontSize = this.configurationService.getValue(NotebookSetting.markupFontSize) || configuration.fontSize; + configuration.markupFontSize = this.configurationService.getValue(NotebookSetting.markupFontSize); } if (editorOptionsCustomizations) { From e08e4d3fe1079f6ccb1b781f6089d9e573b81ca6 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Wed, 10 Nov 2021 00:11:12 +0100 Subject: [PATCH 83/83] Move `--ms-enable-electron-run-as-node` to a later location (#136786) * Move `--ms-enable-electron-run-as-node` to a later location, which is not fatal in Electron builds that don't know it * undo bad change --- extensions/git/src/askpass.ts | 2 +- resources/darwin/bin/code.sh | 2 +- resources/linux/bin/code.sh | 2 +- resources/win32/bin/code.cmd | 2 +- resources/win32/bin/code.sh | 4 ++-- scripts/code-cli.bat | 2 +- scripts/code-cli.sh | 2 +- scripts/code.sh | 2 +- scripts/node-electron.bat | 2 +- scripts/node-electron.sh | 8 ++++---- src/vs/platform/environment/common/argv.ts | 3 +++ src/vs/platform/environment/node/argv.ts | 1 + src/vs/platform/environment/node/shellEnv.ts | 5 +++-- 13 files changed, 21 insertions(+), 16 deletions(-) diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts index 11c8e367649..e6c21efa9cb 100644 --- a/extensions/git/src/askpass.ts +++ b/extensions/git/src/askpass.ts @@ -83,7 +83,7 @@ export class Askpass implements IIPCHandler { ...this.ipc.getEnv(), GIT_ASKPASS: path.join(__dirname, 'askpass.sh'), VSCODE_GIT_ASKPASS_NODE: process.execPath, - VSCODE_GIT_ASKPASS_EXTRA_ARGS: !!process.versions['electron'] ? '--ms-enable-electron-run-as-node' : '', + VSCODE_GIT_ASKPASS_EXTRA_ARGS: (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : '', VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js') }; } diff --git a/resources/darwin/bin/code.sh b/resources/darwin/bin/code.sh index eae80f95d57..20aee89edf9 100755 --- a/resources/darwin/bin/code.sh +++ b/resources/darwin/bin/code.sh @@ -7,5 +7,5 @@ function realpath() { python -c "import os,sys; print(os.path.realpath(sys.argv[ CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")" ELECTRON="$CONTENTS/MacOS/Electron" CLI="$CONTENTS/Resources/app/out/cli.js" -ELECTRON_RUN_AS_NODE=1 "$ELECTRON" --ms-enable-electron-run-as-node "$CLI" "$@" +ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --ms-enable-electron-run-as-node "$@" exit $? diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 5d9fb6edefd..73ef78f62dc 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -50,5 +50,5 @@ fi ELECTRON="$VSCODE_PATH/@@NAME@@" CLI="$VSCODE_PATH/resources/app/out/cli.js" -ELECTRON_RUN_AS_NODE=1 "$ELECTRON" --ms-enable-electron-run-as-node "$CLI" "$@" +ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --ms-enable-electron-run-as-node "$@" exit $? diff --git a/resources/win32/bin/code.cmd b/resources/win32/bin/code.cmd index 890767b226a..c72e9e28333 100644 --- a/resources/win32/bin/code.cmd +++ b/resources/win32/bin/code.cmd @@ -2,5 +2,5 @@ setlocal set VSCODE_DEV= set ELECTRON_RUN_AS_NODE=1 -"%~dp0..\@@NAME@@.exe" --ms-enable-electron-run-as-node "%~dp0..\resources\app\out\cli.js" %* +"%~dp0..\@@NAME@@.exe" "%~dp0..\resources\app\out\cli.js" --ms-enable-electron-run-as-node %* endlocal diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 25fa85b7b3d..999a5b5445c 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -43,7 +43,7 @@ if [ $IN_WSL = true ]; then # use the Remote WSL extension if installed WSL_EXT_ID="ms-vscode-remote.remote-wsl" - ELECTRON_RUN_AS_NODE=1 "$ELECTRON" --ms-enable-electron-run-as-node "$CLI" --locate-extension $WSL_EXT_ID >/tmp/remote-wsl-loc.txt 2>/dev/null /tmp/remote-wsl-loc.txt 2>/dev/null > = { 'inspect-extensions': { type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, 'inspect-brk-extensions': { type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, 'disable-gpu': { type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, + 'ms-enable-electron-run-as-node': { type: 'boolean' }, 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes)."), args: 'memory' }, 'telemetry': { type: 'boolean', cat: 't', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, diff --git a/src/vs/platform/environment/node/shellEnv.ts b/src/vs/platform/environment/node/shellEnv.ts index 0033b39a907..a80d1f69863 100644 --- a/src/vs/platform/environment/node/shellEnv.ts +++ b/src/vs/platform/environment/node/shellEnv.ts @@ -127,13 +127,14 @@ async function doResolveUnixShellEnv(logService: ILogService, token: Cancellatio // handle popular non-POSIX shells const name = basename(systemShellUnix); let command: string, shellArgs: Array; + const extraArgs = (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : ''; if (/^pwsh(-preview)?$/.test(name)) { // Older versions of PowerShell removes double quotes sometimes so we use "double single quotes" which is how // you escape single quotes inside of a single quoted string. - command = `& '${process.execPath}' --ms-enable-electron-run-as-node -p '''${mark}'' + JSON.stringify(process.env) + ''${mark}'''`; + command = `& '${process.execPath}' ${extraArgs} -p '''${mark}'' + JSON.stringify(process.env) + ''${mark}'''`; shellArgs = ['-Login', '-Command']; } else { - command = `'${process.execPath}' --ms-enable-electron-run-as-node -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`; + command = `'${process.execPath}' ${extraArgs} -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`; if (name === 'tcsh') { shellArgs = ['-ic'];