diff --git a/.eslintrc.json b/.eslintrc.json index 8dfbf754ae9e..1c9dd12c305a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,10 @@ "ecmaVersion": 6, "sourceType": "module" }, - "plugins": ["@typescript-eslint", "jsdoc"], + "plugins": [ + "@typescript-eslint", + "jsdoc" + ], "rules": { "constructor-super": "warn", "curly": "warn", @@ -43,7 +46,9 @@ "warn", { "selector": "class", - "format": ["PascalCase"] + "format": [ + "PascalCase" + ] } ], "code-no-unused-expressions": [ @@ -60,11 +65,26 @@ "warn", { "common": [], - "node": ["common"], - "browser": ["common"], - "electron-sandbox": ["common", "browser"], - "electron-browser": ["common", "browser", "node", "electron-sandbox"], - "electron-main": ["common", "node"] + "node": [ + "common" + ], + "browser": [ + "common" + ], + "electron-sandbox": [ + "common", + "browser" + ], + "electron-browser": [ + "common", + "browser", + "node", + "electron-sandbox" + ], + "electron-main": [ + "common", + "node" + ] } ], "code-import-patterns": [ @@ -74,7 +94,10 @@ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! { "target": "**/vs/base/common/**", - "restrictions": ["vs/nls", "**/vs/base/common/**"] + "restrictions": [ + "vs/nls", + "**/vs/base/common/**" + ] }, { "target": "**/vs/base/test/common/**", @@ -432,7 +455,11 @@ }, { "target": "**/vs/workbench/api/worker/**", - "restrictions": ["vscode", "vs/nls", "**/vs/**/{common,worker}/**"] + "restrictions": [ + "vscode", + "vs/nls", + "**/vs/**/{common,worker}/**" + ] }, { "target": "**/vs/workbench/electron-sandbox/**", @@ -878,7 +905,13 @@ }, { "target": "**/api/**.test.ts", - "restrictions": ["**/vs/**", "assert", "sinon", "crypto", "vscode"] + "restrictions": [ + "**/vs/**", + "assert", + "sinon", + "crypto", + "vscode" + ] }, { "target": "**/{node,electron-browser,electron-main}/**/*.test.ts", @@ -903,28 +936,46 @@ }, { "target": "**/**.test.ts", - "restrictions": ["**/vs/**", "assert", "sinon", "crypto", "xterm*"] + "restrictions": [ + "**/vs/**", + "assert", + "sinon", + "crypto", + "xterm*" + ] }, { "target": "**/test/**", - "restrictions": ["**/vs/**", "assert", "sinon", "crypto", "xterm*"] + "restrictions": [ + "**/vs/**", + "assert", + "sinon", + "crypto", + "xterm*" + ] } ] }, "overrides": [ { - "files": ["*.js"], + "files": [ + "*.js" + ], "rules": { "jsdoc/no-types": "off" } }, { - "files": ["**/vscode.d.ts", "**/vscode.proposed.d.ts"], + "files": [ + "**/vscode.d.ts", + "**/vscode.proposed.d.ts" + ], "rules": { "vscode-dts-create-func": "warn", "vscode-dts-literal-or-types": "warn", "vscode-dts-interface-naming": "warn", "vscode-dts-cancellation": "warn", + "vscode-dts-use-thenable": "warn", "vscode-dts-provider-naming": [ "warn", { @@ -940,7 +991,10 @@ "vscode-dts-event-naming": [ "warn", { - "allowed": ["onCancellationRequested", "event"], + "allowed": [ + "onCancellationRequested", + "event" + ], "verbs": [ "accept", "change", diff --git a/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml index e0bb30a7e02c..22e2602d0aac 100644 --- a/build/azure-pipelines/exploration-build.yml +++ b/build/azure-pipelines/exploration-build.yml @@ -2,6 +2,7 @@ pool: vmImage: "Ubuntu-16.04" trigger: none +pr: none steps: - task: NodeTool@0 diff --git a/build/lib/eslint/vscode-dts-use-thenable.js b/build/lib/eslint/vscode-dts-use-thenable.js new file mode 100644 index 000000000000..7e23953cb69b --- /dev/null +++ b/build/lib/eslint/vscode-dts-use-thenable.js @@ -0,0 +1,24 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +module.exports = new class ApiEventNaming { + constructor() { + this.meta = { + messages: { + usage: 'Use the Thenable-type instead of the Promise type', + } + }; + } + create(context) { + return { + ['TSTypeAnnotation TSTypeReference Identifier[name="Promise"]']: (node) => { + context.report({ + node, + messageId: 'usage', + }); + } + }; + } +}; diff --git a/build/lib/eslint/vscode-dts-use-thenable.ts b/build/lib/eslint/vscode-dts-use-thenable.ts new file mode 100644 index 000000000000..511124820996 --- /dev/null +++ b/build/lib/eslint/vscode-dts-use-thenable.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as eslint from 'eslint'; + +export = new class ApiEventNaming implements eslint.Rule.RuleModule { + + readonly meta: eslint.Rule.RuleMetaData = { + messages: { + usage: 'Use the Thenable-type instead of the Promise type', + } + }; + + create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { + + + + return { + ['TSTypeAnnotation TSTypeReference Identifier[name="Promise"]']: (node: any) => { + + context.report({ + node, + messageId: 'usage', + }); + } + }; + } +}; diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 6e23f471f15b..b25c3713ea83 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -194,6 +194,7 @@ function fromMarketplace(extensionName, version, metadata) { exports.fromMarketplace = fromMarketplace; const excludedExtensions = [ 'vscode-api-tests', + 'vscode-colorize-tests', 'vscode-test-resolver', 'ms-vscode.node-debug', 'ms-vscode.node-debug2', diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js index 94dbb3b9e0d6..8d51e7a785d1 100644 --- a/build/npm/preinstall.js +++ b/build/npm/preinstall.js @@ -28,7 +28,41 @@ if (!/yarn[\w-.]*\.js$|yarnpkg$/.test(process.env['npm_execpath'])) { err = true; } +if (process.platform === 'win32') { + if (!hasSupportedVisualStudioVersion()) { + console.error('\033[1;31m*** Invalid C/C++ Compiler Toolchain. Please check https://github.com/microsoft/vscode/wiki/How-to-Contribute.\033[0;0m'); + err = true; + } +} + if (err) { console.error(''); process.exit(1); } + +function hasSupportedVisualStudioVersion() { + const fs = require('fs'); + const path = require('path'); + // Translated over from + // https://source.chromium.org/chromium/chromium/src/+/master:build/vs_toolchain.py;l=140-175 + const supportedVersions = ['2019', '2017']; + + const availableVersions = []; + for (const version of supportedVersions) { + let vsPath = process.env[`vs${version}_install`]; + if (vsPath && fs.existsSync(vsPath)) { + availableVersions.push(version); + break; + } + const programFiles86Path = process.env['ProgramFiles(x86)']; + if (programFiles86Path) { + vsPath = `${programFiles86Path}/Microsoft Visual Studio/${version}`; + const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools']; + if (vsTypes.some(vsType => fs.existsSync(path.join(vsPath, vsType)))) { + availableVersions.push(version); + break; + } + } + } + return availableVersions.length; +} diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 474623b9c4eb..b304e21ed5a6 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -467,7 +467,7 @@ export class Git { try { const networkPath = await new Promise(resolve => - realpath.native(`${letter}:`, { encoding: 'utf8' }, (err, resolvedPath) => + realpath.native(`${letter}:\\`, { encoding: 'utf8' }, (err, resolvedPath) => resolve(err !== null ? undefined : resolvedPath), ), ); diff --git a/extensions/github-authentication/src/common/keychain.ts b/extensions/github-authentication/src/common/keychain.ts index 4c7c8c93c300..d1dc0a32a640 100644 --- a/extensions/github-authentication/src/common/keychain.ts +++ b/extensions/github-authentication/src/common/keychain.ts @@ -34,7 +34,7 @@ export class Keychain { constructor(private context: vscode.ExtensionContext) { } async setToken(token: string): Promise { try { - return await this.context.secrets.set(SERVICE_ID, token); + return await this.context.secrets.store(SERVICE_ID, token); } catch (e) { // Ignore Logger.error(`Setting token failed: ${e}`); diff --git a/extensions/markdown-language-features/src/commands/renderDocument.ts b/extensions/markdown-language-features/src/commands/renderDocument.ts index f9ec89fce3d3..d46e10d52e9d 100644 --- a/extensions/markdown-language-features/src/commands/renderDocument.ts +++ b/extensions/markdown-language-features/src/commands/renderDocument.ts @@ -15,6 +15,6 @@ export class RenderDocument implements Command { ) { } public async execute(document: SkinnyTextDocument | string): Promise { - return this.engine.render(document); + return (await (this.engine.render(document))).html; } } diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index ac7f76c9271d..009f75ea840e 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -14,8 +14,9 @@ import { isMarkdownFile } from '../util/file'; import { normalizeResource, WebviewResourceProvider } from '../util/resources'; import { getVisibleLine, TopmostLineMonitor } from '../util/topmostLineMonitor'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; -import { MarkdownContentProvider } from './previewContentProvider'; +import { MarkdownContentProvider, MarkdownContentProviderOutput } from './previewContentProvider'; import { MarkdownEngine } from '../markdownEngine'; +import { urlToUri } from '../util/url'; const localize = nls.loadMessageBundle(); @@ -118,6 +119,8 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { private _disposed: boolean = false; private imageInfo: { readonly id: string, readonly width: number, readonly height: number; }[] = []; + private readonly _fileWatchersBySrc = new Map(); + constructor( webview: vscode.WebviewPanel, resource: vscode.Uri, @@ -208,6 +211,9 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { super.dispose(); this._disposed = true; clearTimeout(this.throttleTimer); + for (const entry of this._fileWatchersBySrc.values()) { + entry.dispose(); + } } public get resource(): vscode.Uri { @@ -224,6 +230,10 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { }; } + /** + * The first call immediately refreshes the preview, + * calls happening shortly thereafter are debounced. + */ public refresh() { // Schedule update if none is pending if (!this.throttleTimer) { @@ -360,7 +370,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { this._webviewPanel.webview.html = this._contentProvider.provideFileNotFoundContent(this._resource); } - private setContent(html: string): void { + private setContent(content: MarkdownContentProviderOutput): void { if (this._disposed) { return; } @@ -371,7 +381,30 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { this._webviewPanel.iconPath = this.iconPath; this._webviewPanel.webview.options = this.getWebviewOptions(); - this._webviewPanel.webview.html = html; + this._webviewPanel.webview.html = content.html; + + const srcs = new Set(content.containingImages.map(img => img.src)); + + // Delete stale file watchers. + for (const [src, watcher] of [...this._fileWatchersBySrc]) { + if (!srcs.has(src)) { + watcher.dispose(); + this._fileWatchersBySrc.delete(src); + } + } + + // Create new file watchers. + const root = vscode.Uri.joinPath(this._resource, '../'); + for (const src of srcs) { + const uri = urlToUri(src, root); + if (uri && uri.scheme === 'file' && !this._fileWatchersBySrc.has(src)) { + const watcher = vscode.workspace.createFileSystemWatcher(uri.fsPath); + watcher.onDidChange(() => { + this.refresh(); + }); + this._fileWatchersBySrc.set(src, watcher); + } + } } private getWebviewOptions(): vscode.WebviewOptions { diff --git a/extensions/markdown-language-features/src/features/previewContentProvider.ts b/extensions/markdown-language-features/src/features/previewContentProvider.ts index a8a64e5270da..1db106403d31 100644 --- a/extensions/markdown-language-features/src/features/previewContentProvider.ts +++ b/extensions/markdown-language-features/src/features/previewContentProvider.ts @@ -39,6 +39,12 @@ function escapeAttribute(value: string | vscode.Uri): string { return value.toString().replace(/"/g, '"'); } +export interface MarkdownContentProviderOutput { + html: string; + containingImages: { src: string }[]; +} + + export class MarkdownContentProvider { constructor( private readonly engine: MarkdownEngine, @@ -54,7 +60,7 @@ export class MarkdownContentProvider { previewConfigurations: MarkdownPreviewConfigurationManager, initialLine: number | undefined = undefined, state?: any - ): Promise { + ): Promise { const sourceUri = markdownDocument.uri; const config = previewConfigurations.loadAndCacheConfiguration(sourceUri); const initialData = { @@ -75,7 +81,7 @@ export class MarkdownContentProvider { const csp = this.getCsp(resourceProvider, sourceUri, nonce); const body = await this.engine.render(markdownDocument); - return ` + const html = ` @@ -89,11 +95,15 @@ export class MarkdownContentProvider { - ${body} + ${body.html}
${this.getScripts(resourceProvider, nonce)} `; + return { + html, + containingImages: body.containingImages, + }; } public provideFileNotFoundContent( diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index 8bb509d45657..80761e0ea3a0 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -54,6 +54,15 @@ class TokenCache { } } +export interface RenderOutput { + html: string; + containingImages: { src: string }[]; +} + +interface RenderEnv { + containingImages: { src: string }[]; +} + export class MarkdownEngine { private md?: Promise; @@ -141,7 +150,7 @@ export class MarkdownEngine { return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {}); } - public async render(input: SkinnyTextDocument | string): Promise { + public async render(input: SkinnyTextDocument | string): Promise { const config = this.getConfig(typeof input === 'string' ? undefined : input.uri); const engine = await this.getEngine(config); @@ -149,10 +158,19 @@ export class MarkdownEngine { ? this.tokenizeString(input, engine) : this.tokenizeDocument(input, config, engine); - return engine.renderer.render(tokens, { + const env: RenderEnv = { + containingImages: [] + }; + + const html = engine.renderer.render(tokens, { ...(engine as any).options, ...config - }, {}); + }, env); + + return { + html, + containingImages: env.containingImages + }; } public async parse(document: SkinnyTextDocument): Promise { @@ -192,12 +210,13 @@ export class MarkdownEngine { private addImageStabilizer(md: any): void { const original = md.renderer.rules.image; - md.renderer.rules.image = (tokens: any, idx: number, options: any, env: any, self: any) => { + md.renderer.rules.image = (tokens: any, idx: number, options: any, env: RenderEnv, self: any) => { const token = tokens[idx]; token.attrJoin('class', 'loading'); const src = token.attrGet('src'); if (src) { + env.containingImages.push({ src }); const imgHash = hash(src); token.attrSet('id', `image-hash-${imgHash}`); } @@ -231,6 +250,13 @@ export class MarkdownEngine { return normalizeLink(vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }).toString()); } + // Support file:// links + if (isOfScheme(Schemes.file, link)) { + // Ensure link is relative by prepending `/` so that it uses the element URI + // when resolving the absolute URL + return normalizeLink('/' + link.replace(/^file:/, 'file')); + } + // If original link doesn't look like a url with a scheme, assume it must be a link to a file in workspace if (!/^[a-z\-]+:/i.test(link)) { // Use a fake scheme for parsing @@ -241,12 +267,14 @@ export class MarkdownEngine { if (uri.path[0] === '/') { const root = vscode.workspace.getWorkspaceFolder(this.currentDocument!); if (root) { - const fileUri = vscode.Uri.joinPath(root.uri, uri.fsPath); - uri = fileUri.with({ - scheme: uri.scheme, + const fileUri = vscode.Uri.joinPath(root.uri, uri.fsPath).with({ fragment: uri.fragment, query: uri.query, }); + + // Ensure fileUri is relative by prepending `/` so that it uses the element URI + // when resolving the absolute URL + uri = vscode.Uri.parse('markdown-link:' + '/' + fileUri.toString(true).replace(/^\S+?:/, fileUri.scheme)); } } @@ -269,9 +297,7 @@ export class MarkdownEngine { private addLinkValidator(md: any): void { const validateLink = md.validateLink; md.validateLink = (link: string) => { - // support file:// links return validateLink(link) - || isOfScheme(Schemes.file, link) || isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link) || /^data:image\/.*?;/.test(link); diff --git a/extensions/markdown-language-features/src/test/engine.test.ts b/extensions/markdown-language-features/src/test/engine.test.ts index 3cd4f86693e5..c3eb7c850566 100644 --- a/extensions/markdown-language-features/src/test/engine.test.ts +++ b/extensions/markdown-language-features/src/test/engine.test.ts @@ -21,12 +21,31 @@ suite('markdown.engine', () => { test('Renders a document', async () => { const doc = new InMemoryDocument(testFileName, input); const engine = createNewMarkdownEngine(); - assert.strictEqual(await engine.render(doc), output); + assert.strictEqual((await engine.render(doc)).html, output); }); test('Renders a string', async () => { const engine = createNewMarkdownEngine(); - assert.strictEqual(await engine.render(input), output); + assert.strictEqual((await engine.render(input)).html, output); + }); + }); + + suite('image-caching', () => { + const input = '![](img.png) [](no-img.png) ![](http://example.org/img.png) ![](img.png) ![](./img2.png)'; + + test('Extracts all images', async () => { + const engine = createNewMarkdownEngine(); + assert.deepStrictEqual((await engine.render(input)), { + html: '

' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '

\n' + , + containingImages: [{ src: 'img.png' }, { src: 'http://example.org/img.png' }, { src: 'img.png' }, { src: './img2.png' }], + }); }); }); }); diff --git a/extensions/markdown-language-features/src/test/urlToUri.test.ts b/extensions/markdown-language-features/src/test/urlToUri.test.ts new file mode 100644 index 000000000000..6578d207e1a0 --- /dev/null +++ b/extensions/markdown-language-features/src/test/urlToUri.test.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { deepStrictEqual } from 'assert'; +import 'mocha'; +import { Uri } from 'vscode'; +import { urlToUri } from '../util/url'; + +suite('urlToUri', () => { + test('Absolute File', () => { + deepStrictEqual( + urlToUri('file:///root/test.txt', Uri.parse('file:///usr/home/')), + Uri.parse('file:///root/test.txt') + ); + }); + + test('Relative File', () => { + deepStrictEqual( + urlToUri('./file.ext', Uri.parse('file:///usr/home/')), + Uri.parse('file:///usr/home/file.ext') + ); + }); + + test('Http Basic', () => { + deepStrictEqual( + urlToUri('http://example.org?q=10&f', Uri.parse('file:///usr/home/')), + Uri.parse('http://example.org?q=10&f') + ); + }); + + test('Http Encoded Chars', () => { + deepStrictEqual( + urlToUri('http://example.org/%C3%A4', Uri.parse('file:///usr/home/')), + Uri.parse('http://example.org/%C3%A4') + ); + }); +}); diff --git a/extensions/markdown-language-features/src/util/url.ts b/extensions/markdown-language-features/src/util/url.ts new file mode 100644 index 000000000000..d91cb4ab06d7 --- /dev/null +++ b/extensions/markdown-language-features/src/util/url.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +declare const URL: typeof import('url').URL; + +/** + * Tries to convert an url into a vscode uri and returns undefined if this is not possible. + * `url` can be absolute or relative. +*/ +export function urlToUri(url: string, base: vscode.Uri): vscode.Uri | undefined { + try { + // `vscode.Uri.joinPath` cannot be used, since it understands + // `src` as path, not as relative url. This is problematic for query args. + const parsedUrl = new URL(url, base.toString()); + const uri = vscode.Uri.parse(parsedUrl.toString()); + return uri; + } catch (e) { + // Don't crash if `URL` cannot parse `src`. + return undefined; + } +} diff --git a/extensions/microsoft-authentication/src/keychain.ts b/extensions/microsoft-authentication/src/keychain.ts index e23603be0806..1a0001c117e3 100644 --- a/extensions/microsoft-authentication/src/keychain.ts +++ b/extensions/microsoft-authentication/src/keychain.ts @@ -48,7 +48,7 @@ export class Keychain { async setToken(token: string): Promise { try { - return await this.context.secrets.set(SERVICE_ID, token); + return await this.context.secrets.store(SERVICE_ID, token); } catch (e) { Logger.error(`Setting token failed: ${e}`); diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index 65bf1d66d92b..0f0528af8772 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -223,9 +223,18 @@ function parseSearchResults(document: vscode.TextDocument, token?: vscode.Cancel const metadataOffset = (indentation + _lineNumber + seperator).length; const targetRange = new vscode.Range(Math.max(lineNumber - 3, 0), 0, lineNumber + 3, line.length); + let locations: Required[] = []; + + // Allow line number, indentation, etc to take you to definition as well. + locations.push({ + targetRange, + targetSelectionRange: new vscode.Range(lineNumber, 0, lineNumber, 1), + targetUri: currentTarget, + originSelectionRange: new vscode.Range(i, 0, i, resultStart), + }); + let lastEnd = resultStart; let offset = 0; - let locations: Required[] = []; ELISION_REGEX.lastIndex = resultStart; for (let match: RegExpExecArray | null; (match = ELISION_REGEX.exec(line));) { locations.push({ diff --git a/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts b/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts index fc81cb57fbe3..ccd59d517735 100644 --- a/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts +++ b/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts @@ -31,7 +31,7 @@ const jsTsLanguageConfiguration: vscode.LanguageConfiguration = { }, { // e.g. * ...| beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, - oneLineAboveText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, + previousLineText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, action: { indentAction: vscode.IndentAction.None, appendText: '* ' }, }, { // e.g. */| diff --git a/package.json b/package.json index 4d0f2a243419..55abe8d5c83e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.53.0", - "distro": "dd764d38c8e0aa3914484c1e62300f51cdd7c5b8", + "distro": "826dce393851992f3b4af928e2bf7dd3813843cc", "author": { "name": "Microsoft Corporation" }, @@ -38,7 +38,7 @@ "smoketest-no-compile": "cd test/smoke && node test/index.js", "download-builtin-extensions": "node build/lib/builtInExtensions.js", "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", - "tsec-compile-check": "node node_modules/vscode-tsec/bin/tsec -p src/tsconfig.tsec.json", + "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", "valid-layers-check": "node build/lib/layersChecker.js", "strict-function-types-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictFunctionTypes", "update-distro": "node build/npm/update-distro.js", @@ -189,6 +189,7 @@ "source-map": "0.6.1", "source-map-support": "^0.3.2", "style-loader": "^1.0.0", + "tsec": "0.1.1", "ts-loader": "^6.2.1", "typescript": "4.2.0-dev.20201207", "typescript-formatter": "7.1.0", @@ -198,7 +199,6 @@ "vscode-debugprotocol": "1.43.0", "vscode-nls-dev": "^3.3.1", "vscode-telemetry-extractor": "^1.6.0", - "vscode-tsec": "0.0.3", "webpack": "^4.43.0", "webpack-cli": "^3.3.12", "webpack-stream": "^5.2.1", diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 533199b82751..39ca0a60807d 100644 Binary files a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf and b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 55858a5890be..6a304f9ffc28 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -126,9 +126,11 @@ export class MenuBar extends Disposable { let eventHandled = true; const key = !!e.key ? e.key.toLocaleLowerCase() : ''; - if (event.equals(KeyCode.LeftArrow) || (isMacintosh && event.equals(KeyCode.Tab | KeyMod.Shift))) { + const tabNav = isMacintosh && this.options.compactMode === undefined; + + if (event.equals(KeyCode.LeftArrow) || (tabNav && event.equals(KeyCode.Tab | KeyMod.Shift))) { this.focusPrevious(); - } else if (event.equals(KeyCode.RightArrow) || (isMacintosh && event.equals(KeyCode.Tab))) { + } else if (event.equals(KeyCode.RightArrow) || (tabNav && event.equals(KeyCode.Tab))) { this.focusNext(); } else if (event.equals(KeyCode.Escape) && this.isFocused && !this.isOpen) { this.setUnfocusedState(); diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts index 11e42d6524d0..825777c93855 100644 --- a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -152,7 +152,7 @@ export class CompressedObjectTreeModel, TFilterData e const diffIdentityProvider = options.diffIdentityProvider && wrapIdentityProvider(options.diffIdentityProvider); if (element === null) { const compressedChildren = Iterable.map(children, this.enabled ? compress : noCompress); - this._setChildren(null, compressedChildren, { diffIdentityProvider, diffDeep: Infinity }); + this._setChildren(null, compressedChildren, { diffIdentityProvider, diffDepth: Infinity }); return; } @@ -175,7 +175,7 @@ export class CompressedObjectTreeModel, TFilterData e this._setChildren(parent.element, parentChildren, { diffIdentityProvider, - diffDeep: node.depth - parent.depth, + diffDepth: node.depth - parent.depth, }); } @@ -199,7 +199,7 @@ export class CompressedObjectTreeModel, TFilterData e // provider is available, since we know the raw nodes are unchanged. this._setChildren(null, recompressedRootChildren, { diffIdentityProvider: this.identityProvider, - diffDeep: Infinity, + diffDepth: Infinity, }); } diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index 3497b96b89ca..056972d79d74 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -48,7 +48,7 @@ export interface IIndexedSpliceOptions { * If set, child updates will recurse the given number of levels even if * items in the splice operation are unchanged. `Infinity` is a valid value. */ - readonly diffDeep?: number; + readonly diffDepth?: number; /** * Identity provider used to optimize splice() calls in the IndexTree. If @@ -159,7 +159,7 @@ export class IndexTreeModel, TFilterData = voi deleteCount: number, toInsertIterable: Iterable> = Iterable.empty(), options: IIndexedSpliceOptions, - recurseLevels = options.diffDeep ?? 0, + recurseLevels = options.diffDepth ?? 0, ) { const { parentNode } = this.getParentNodeWithListIndex(location); const toInsert = [...toInsertIterable]; diff --git a/src/vs/base/common/codicons.ts b/src/vs/base/common/codicons.ts index 3555040f2890..c5f47a8507ac 100644 --- a/src/vs/base/common/codicons.ts +++ b/src/vs/base/common/codicons.ts @@ -531,6 +531,8 @@ export namespace Codicon { export const passFilled = new Codicon('pass-filled', { character: '\\ebb3' }); export const circleLargeFilled = new Codicon('circle-large-filled', { character: '\\ebb4' }); export const circleLargeOutline = new Codicon('circle-large-outline', { character: '\\ebb5' }); + export const combine = new Codicon('combine', { character: '\\ebb6' }); + export const gather = new Codicon('gather', { character: '\\ebb6' }); export const dropDownButton = new Codicon('drop-down-button', Codicon.chevronDown.definition); } diff --git a/src/vs/base/parts/ipc/electron-main/ipc.mp.ts b/src/vs/base/parts/ipc/electron-main/ipc.mp.ts index 34e159cecd1b..81187ec56a7f 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.mp.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.mp.ts @@ -37,6 +37,11 @@ export class Client extends MessagePortClient implements IDisposable { */ export async function connect(window: BrowserWindow): Promise { + // Assert healthy window to talk to + if (window.webContents.isDestroyed()) { + throw new Error('ipc.mp#connect: Cannot talk to window because it is closed or destroyed'); + } + // Ask to create message channel inside the window // and send over a UUID to correlate the response const nonce = generateUuid(); diff --git a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts index 52e7bb698d06..2a2241d4b57f 100644 --- a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts @@ -242,7 +242,7 @@ suite('IndexTreeModel', () => { { element: 0, children: [{ element: 0.1 }] }, { element: 1 }, { element: 2, children: [{ element: 2.1 }, { element: 2.2, children: [{ element: 2.21 }] }] }, - ], { diffIdentityProvider, diffDeep: Infinity }); + ], { diffIdentityProvider, diffDepth: Infinity }); assert.deepStrictEqual(list.filter(l => l.depth === 1).map(toElements), [ -0.5, diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 50000e930c8c..812f60d0aea6 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -270,8 +270,13 @@ export class CodeApplication extends Disposable { //#region Bootstrap IPC Handlers + let slowShellResolveWarningShown = false; ipcMain.on('vscode:fetchShellEnv', async event => { - const window = this.windowsMainService?.getWindowByWebContents(event.sender); + + // DO NOT remove: not only usual windows are fetching the + // shell environment but also shared process, issue reporter + // etc, so we need to reply via `webContents` always + const webContents = event.sender; let replied = false; @@ -282,15 +287,25 @@ export class CodeApplication extends Disposable { if (!replied) { replied = true; - window?.send('vscode:acceptShellEnv', env); + if (!webContents.isDestroyed()) { + webContents.send('vscode:acceptShellEnv', env); + } } } // Handle slow shell environment resolve calls: - // - a warning after 3s but continue to resolve - // - an error after 10s and stop trying to resolve + // - a warning after 3s but continue to resolve (only once in active window) + // - an error after 10s and stop trying to resolve (in every window where this happens) const cts = new CancellationTokenSource(); - const shellEnvSlowWarningHandle = setTimeout(() => window?.sendWhenReady('vscode:showShellEnvSlowWarning', cts.token), 3000); + + const shellEnvSlowWarningHandle = setTimeout(() => { + if (!slowShellResolveWarningShown) { + this.windowsMainService?.sendToFocused('vscode:showShellEnvSlowWarning', cts.token); + slowShellResolveWarningShown = true; + } + }, 3000); + + const window = this.windowsMainService?.getWindowByWebContents(event.sender); // Note: this can be `undefined` for the shared process!! const shellEnvTimeoutErrorHandle = setTimeout(() => { cts.dispose(true); window?.sendWhenReady('vscode:showShellEnvTimeoutError', CancellationToken.None); @@ -302,6 +317,9 @@ export class CodeApplication extends Disposable { // a first window was opened from the UI but a second // from the CLI and that has implications for whether to // resolve the shell environment or not. + // + // Window can be undefined for e.g. the shared process + // that is not part of our windows registry! let args: NativeParsedArgs; let env: NodeJS.ProcessEnv; if (window?.config) { diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index cba5630273e8..71323135c4cb 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -14,6 +14,7 @@ import { browserCodeLoadingCacheStrategy } from 'vs/base/common/platform'; import { ISharedProcess, ISharedProcessConfiguration } from 'vs/platform/sharedProcess/node/sharedProcess'; import { Disposable } from 'vs/base/common/lifecycle'; import { connect as connectMessagePort } from 'vs/base/parts/ipc/electron-main/ipc.mp'; +import { assertIsDefined } from 'vs/base/common/types'; export class SharedProcess extends Disposable implements ISharedProcess { @@ -49,8 +50,18 @@ export class SharedProcess extends Disposable implements ISharedProcess { // workbench window will communicate directly await this.whenReady(); + // connect to the shared process window const port = await this.connect(); + // Check back if the requesting window meanwhile closed + // Since shared process is delayed on startup there is + // a chance that the window close before the shared process + // was ready for a connection. + if (e.sender.isDestroyed()) { + return port.close(); + } + + // send the port back to the requesting window e.sender.postMessage('vscode:createSharedProcessMessageChannelResult', nonce, [port]); }); } @@ -208,13 +219,9 @@ export class SharedProcess extends Disposable implements ISharedProcess { // Wait for shared process being ready to accept connection await this.whenIpcReady; - // Assert healthy shared process window - if (!this.window || this.window.webContents.isDestroyed()) { - throw new Error('Cannot connect to shared process window because the window is closed or destroyed'); - } - // Connect and return message port - return connectMessagePort(this.window); + const window = assertIsDefined(this.window); + return connectMessagePort(window); } async toggle(): Promise { diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 068bbf03a8e2..be322e19bf9f 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -424,11 +424,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.dispose(); }); - // Prevent loading of svgs - this._win.webContents.session.webRequest.onBeforeRequest(null!, (details, callback) => { - if (details.url.indexOf('.svg') > 0) { + const svgFileSchemes = new Set([Schemas.file, Schemas.vscodeFileResource]); + this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => { + // Prevent loading of remote svgs + if (details.url.endsWith('.svg')) { const uri = URI.parse(details.url); - if (uri && !uri.scheme.match(/file/i) && uri.path.endsWith('.svg')) { + if (uri && !svgFileSchemes.has(uri.scheme)) { return callback({ cancel: true }); } } @@ -436,12 +437,24 @@ export class CodeWindow extends Disposable implements ICodeWindow { return callback({}); }); - this._win.webContents.session.webRequest.onHeadersReceived(null!, (details, callback) => { + this._win.webContents.session.webRequest.onHeadersReceived((details, callback) => { const responseHeaders = details.responseHeaders as Record; - const contentType = (responseHeaders['content-type'] || responseHeaders['Content-Type']); - if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) { - return callback({ cancel: true }); + + if (contentType && Array.isArray(contentType)) { + // https://github.com/microsoft/vscode/issues/97564 + // ensure local svg files have Content-Type image/svg+xml + if (details.url.endsWith('.svg')) { + const uri = URI.parse(details.url); + if (uri && svgFileSchemes.has(uri.scheme)) { + responseHeaders['Content-Type'] = ['image/svg+xml']; + return callback({ cancel: false, responseHeaders }); + } + } + + if (contentType.some(x => x.toLowerCase().includes('image/svg'))) { + return callback({ cancel: true }); + } } return callback({ cancel: false }); @@ -1254,7 +1267,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { send(channel: string, ...args: any[]): void { if (this._win) { - if (this._win.isDestroyed()) { + if (this._win.webContents.isDestroyed()) { this.logService.warn(`Sending IPC message to channel ${channel} for window that is destroyed`); return; } diff --git a/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-sandbox/workbench/workbench.html index 40737461d293..12f380b55d43 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.html +++ b/src/vs/code/electron-sandbox/workbench/workbench.html @@ -3,7 +3,8 @@ - + + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index 10eb9ab9faea..c5cb1debb260 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -56,9 +56,9 @@ if (value === '') { return value; } - // throw new Error('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); - console.trace('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); - return value; + throw new Error('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); + // console.trace('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); + // return value; } }); diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index c6415a551c8e..b9f36ce2c3e7 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -3,15 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as os from 'os'; -import * as fs from 'fs'; +import { homedir } from 'os'; +import { existsSync, statSync, unlinkSync, chmodSync, truncateSync, readFileSync } from 'fs'; import { spawn, ChildProcess, SpawnOptions } from 'child_process'; import { buildHelpMessage, buildVersionMessage, OPTIONS } from 'vs/platform/environment/node/argv'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { parseCLIProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile'; import product from 'vs/platform/product/common/product'; -import * as paths from 'vs/base/common/path'; +import { isAbsolute, join } from 'vs/base/common/path'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { isWindows, isLinux } from 'vs/base/common/platform'; @@ -69,10 +69,10 @@ export async function main(argv: string[]): Promise { // Validate if ( - !source || !target || source === target || // make sure source and target are provided and are not the same - !paths.isAbsolute(source) || !paths.isAbsolute(target) || // make sure both source and target are absolute paths - !fs.existsSync(source) || !fs.statSync(source).isFile() || // make sure source exists as file - !fs.existsSync(target) || !fs.statSync(target).isFile() // make sure target exists as file + !source || !target || source === target || // make sure source and target are provided and are not the same + !isAbsolute(source) || !isAbsolute(target) || // make sure both source and target are absolute paths + !existsSync(source) || !statSync(source).isFile() || // make sure source exists as file + !existsSync(target) || !statSync(target).isFile() // make sure target exists as file ) { throw new Error('Using --file-write with invalid arguments.'); } @@ -83,15 +83,15 @@ export async function main(argv: string[]): Promise { let targetMode: number = 0; let restoreMode = false; if (!!args['file-chmod']) { - targetMode = fs.statSync(target).mode; + targetMode = statSync(target).mode; if (!(targetMode & 128) /* readonly */) { - fs.chmodSync(target, targetMode | 128); + chmodSync(target, targetMode | 128); restoreMode = true; } } // Write source to target - const data = fs.readFileSync(source); + const data = readFileSync(source); if (isWindows) { // On Windows we use a different strategy of saving the file // by first truncating the file and then writing with r+ mode. @@ -99,7 +99,7 @@ export async function main(argv: string[]): Promise { // (see https://github.com/microsoft/vscode/issues/931) and // prevent removing alternate data streams // (see https://github.com/microsoft/vscode/issues/6363) - fs.truncateSync(target, 0); + truncateSync(target, 0); writeFileSync(target, data, { flag: 'r+' }); } else { writeFileSync(target, data); @@ -107,7 +107,7 @@ export async function main(argv: string[]): Promise { // Restore previous mode as needed if (restoreMode) { - fs.chmodSync(target, targetMode); + chmodSync(target, targetMode); } } catch (error) { error.message = `Error using --file-write: ${error.message}`; @@ -215,7 +215,7 @@ export async function main(argv: string[]): Promise { throw new Error('Failed to find free ports for profiler. Make sure to shutdown all instances of the editor first.'); } - const filenamePrefix = paths.join(os.homedir(), 'prof-' + Math.random().toString(16).slice(-4)); + const filenamePrefix = join(homedir(), 'prof-' + Math.random().toString(16).slice(-4)); addArg(argv, `--inspect-brk=${portMain}`); addArg(argv, `--remote-debugging-port=${portRenderer}`); @@ -338,7 +338,7 @@ export async function main(argv: string[]): Promise { // Make sure to delete the tmp stdin file if we have any if (stdinFilePath) { - fs.unlinkSync(stdinFilePath); + unlinkSync(stdinFilePath); } }); } diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 0df42b0518be..32a0fbf0bb47 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { release } from 'os'; +import * as fs from 'fs'; +import { gracefulify } from 'graceful-fs'; import { isAbsolute, join } from 'vs/base/common/path'; import { raceTimeout } from 'vs/base/common/async'; import product from 'vs/platform/product/common/product'; @@ -36,108 +38,119 @@ import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService'; import { URI } from 'vs/base/common/uri'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; -export class Main { +export class CliMain extends Disposable { constructor( - @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService, - @IExtensionManagementCLIService private readonly extensionManagementCLIService: IExtensionManagementCLIService - ) { } + private argv: NativeParsedArgs + ) { + super(); - async run(argv: NativeParsedArgs): Promise { - if (argv['install-source']) { - await this.setInstallSource(argv['install-source']); - return; + // Enable gracefulFs + gracefulify(fs); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Dispose on exit + process.once('exit', () => this.dispose()); + } + + async run(): Promise { + + // Services + const [instantiationService, appenders] = await this.initServices(); + + return instantiationService.invokeFunction(async accessor => { + const logService = accessor.get(ILogService); + const environmentService = accessor.get(INativeEnvironmentService); + const extensionManagementCLIService = accessor.get(IExtensionManagementCLIService); + + // Log info + logService.info('CLI main', this.argv); + + // Error handler + this.registerErrorHandler(logService); + + // Run based on argv + await this.doRun(environmentService, extensionManagementCLIService); + + // Flush the remaining data in AI adapter (with 1s timeout) + return raceTimeout(combinedAppender(...appenders).flush(), 1000); + }); + } + + private async initServices(): Promise<[IInstantiationService, AppInsightsAppender[]]> { + const services = new ServiceCollection(); + + // Environment + const environmentService = new NativeEnvironmentService(this.argv); + services.set(IEnvironmentService, environmentService); + services.set(INativeEnvironmentService, environmentService); + + // Init folders + await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(path => path ? mkdirp(path) : undefined)); + + // Log + const logLevel = getLogLevel(environmentService); + const loggers: ILogService[] = []; + loggers.push(new SpdLogService('cli', environmentService.logsPath, logLevel)); + if (logLevel === LogLevel.Trace) { + loggers.push(new ConsoleLogService(logLevel)); } - if (argv['list-extensions']) { - await this.extensionManagementCLIService.listExtensions(!!argv['show-versions'], argv['category']); - } else if (argv['install-extension'] || argv['install-builtin-extension']) { - await this.extensionManagementCLIService.installExtensions(this.asExtensionIdOrVSIX(argv['install-extension'] || []), argv['install-builtin-extension'] || [], !!argv['do-not-sync'], !!argv['force']); - } else if (argv['uninstall-extension']) { - await this.extensionManagementCLIService.uninstallExtensions(this.asExtensionIdOrVSIX(argv['uninstall-extension']), !!argv['force']); - } else if (argv['locate-extension']) { - await this.extensionManagementCLIService.locateExtension(argv['locate-extension']); - } else if (argv['telemetry']) { - console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath)); - } - } + const logService = this._register(new MultiplexLogService(loggers)); + services.set(ILogService, logService); - private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] { - return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(process.cwd(), input)) : input); - } + // Files + const fileService = this._register(new FileService(logService)); + services.set(IFileService, fileService); - private setInstallSource(installSource: string): Promise { - return writeFile(this.environmentService.installSourcePath, installSource.slice(0, 30)); - } + const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService)); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); -} + // Configuration + const configurationService = this._register(new ConfigurationService(environmentService.settingsResource, fileService)); + services.set(IConfigurationService, configurationService); -const eventPrefix = 'monacoworkbench'; + // Init config + await configurationService.initialize(); -export async function main(argv: NativeParsedArgs): Promise { - const services = new ServiceCollection(); - const disposables = new DisposableStore(); + // State + const stateService = new StateService(environmentService, logService); + services.set(IStateService, stateService); - const environmentService = new NativeEnvironmentService(argv); - const logLevel = getLogLevel(environmentService); - const loggers: ILogService[] = []; - loggers.push(new SpdLogService('cli', environmentService.logsPath, logLevel)); - if (logLevel === LogLevel.Trace) { - loggers.push(new ConsoleLogService(logLevel)); - } - const logService = new MultiplexLogService(loggers); - process.once('exit', () => logService.dispose()); - logService.info('main', argv); - - await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath] - .map((path): undefined | Promise => path ? mkdirp(path) : undefined)); - - // Files - const fileService = new FileService(logService); - disposables.add(fileService); - services.set(IFileService, fileService); - - const diskFileSystemProvider = new DiskFileSystemProvider(logService); - disposables.add(diskFileSystemProvider); - fileService.registerProvider(Schemas.file, diskFileSystemProvider); - - const configurationService = new ConfigurationService(environmentService.settingsResource, fileService); - disposables.add(configurationService); - await configurationService.initialize(); - - services.set(IEnvironmentService, environmentService); - services.set(INativeEnvironmentService, environmentService); - - services.set(ILogService, logService); - services.set(IConfigurationService, configurationService); - services.set(IStateService, new SyncDescriptor(StateService)); - services.set(IProductService, { _serviceBrand: undefined, ...product }); - - const instantiationService: IInstantiationService = new InstantiationService(services); - - return instantiationService.invokeFunction(async accessor => { - const stateService = accessor.get(IStateService); + // Product + services.set(IProductService, { _serviceBrand: undefined, ...product }); const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService; - const services = new ServiceCollection(); + // Request services.set(IRequestService, new SyncDescriptor(RequestService)); + + // Extensions services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); + + // Localizations services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + // Telemetry const appenders: AppInsightsAppender[] = []; if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) { if (product.aiConfig && product.aiConfig.asimovKey) { - appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey)); + appenders.push(new AppInsightsAppender('monacoworkbench', null, product.aiConfig.asimovKey)); } const config: ITelemetryServiceConfig = { @@ -153,17 +166,70 @@ export async function main(argv: NativeParsedArgs): Promise { services.set(ITelemetryService, NullTelemetryService); } - const instantiationService2 = instantiationService.createChild(services); - const main = instantiationService2.createInstance(Main); + return [new InstantiationService(services), appenders]; + } - try { - await main.run(argv); + private registerErrorHandler(logService: ILogService): void { - // Flush the remaining data in AI adapter. - // If it does not complete in 1 second, exit the process. - await raceTimeout(combinedAppender(...appenders).flush(), 1000); - } finally { - disposables.dispose(); + // Install handler for unexpected errors + setUnexpectedErrorHandler(error => { + const message = toErrorMessage(error, true); + if (!message) { + return; + } + + logService.error(message); + }); + } + + private async doRun(environmentService: INativeEnvironmentService, extensionManagementCLIService: IExtensionManagementCLIService): Promise { + + // Install Source + if (this.argv['install-source']) { + return this.setInstallSource(environmentService, this.argv['install-source']); } - }); + + // List Extensions + if (this.argv['list-extensions']) { + return extensionManagementCLIService.listExtensions(!!this.argv['show-versions'], this.argv['category']); + } + + // Install Extension + else if (this.argv['install-extension'] || this.argv['install-builtin-extension']) { + return extensionManagementCLIService.installExtensions(this.asExtensionIdOrVSIX(this.argv['install-extension'] || []), this.argv['install-builtin-extension'] || [], !!this.argv['do-not-sync'], !!this.argv['force']); + } + + // Uninstall Extension + else if (this.argv['uninstall-extension']) { + return extensionManagementCLIService.uninstallExtensions(this.asExtensionIdOrVSIX(this.argv['uninstall-extension']), !!this.argv['force']); + } + + // Locate Extension + else if (this.argv['locate-extension']) { + return extensionManagementCLIService.locateExtension(this.argv['locate-extension']); + } + + // Telemetry + else if (this.argv['telemetry']) { + console.log(buildTelemetryMessage(environmentService.appRoot, environmentService.extensionsPath)); + } + } + + private asExtensionIdOrVSIX(inputs: string[]): (string | URI)[] { + return inputs.map(input => /\.vsix$/i.test(input) ? URI.file(isAbsolute(input) ? input : join(process.cwd(), input)) : input); + } + + private setInstallSource(environmentService: INativeEnvironmentService, installSource: string): Promise { + return writeFile(environmentService.installSourcePath, installSource.slice(0, 30)); + } +} + +export async function main(argv: NativeParsedArgs): Promise { + const cliMain = new CliMain(argv); + + try { + await cliMain.run(); + } finally { + cliMain.dispose(); + } } diff --git a/src/vs/editor/browser/core/markdownRenderer.ts b/src/vs/editor/browser/core/markdownRenderer.ts index c29335966acd..ec24b6b5d225 100644 --- a/src/vs/editor/browser/core/markdownRenderer.ts +++ b/src/vs/editor/browser/core/markdownRenderer.ts @@ -103,7 +103,7 @@ export class MarkdownRenderer { }, asyncRenderCallback: () => this._onDidRenderAsync.fire(), actionHandler: { - callback: (content) => this._openerService.open(content, { fromUserGesture: true }).catch(onUnexpectedError), + callback: (content) => this._openerService.open(content, { fromUserGesture: true, allowContributedOpeners: true }).catch(onUnexpectedError), disposeables } }; diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 5479ec29bd64..dd329d44f022 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -211,10 +211,16 @@ export class OpenerService implements IOpenerService { href = encodeURI(resolved.toString(true)); } - for (const opener of this._externalOpeners) { - const didOpen = await opener.openExternal(href, { sourceUri: uri }, CancellationToken.None); - if (didOpen) { - return true; + if (options?.allowContributedOpeners) { + const preferredOpenerId = typeof options?.allowContributedOpeners === 'string' ? options?.allowContributedOpeners : undefined; + for (const opener of this._externalOpeners) { + const didOpen = await opener.openExternal(href, { + sourceUri: uri, + preferredOpenerId, + }, CancellationToken.None); + if (didOpen) { + return true; + } } } diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index a383c57e9702..3542fa74fec2 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -150,7 +150,7 @@ export interface OnEnterRule { /** * This rule will only execute if the text above the this line matches this regular expression. */ - oneLineAboveText?: RegExp; + previousLineText?: RegExp; /** * The action to execute. */ diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts index ccd20e3769f8..963fa5c25ef4 100644 --- a/src/vs/editor/common/modes/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -101,11 +101,11 @@ export class RichEditSupport { return this._electricCharacter; } - public onEnter(autoIndent: EditorAutoIndentStrategy, oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null { + public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null { if (!this._onEnterSupport) { return null; } - return this._onEnterSupport.onEnter(autoIndent, oneLineAboveText, beforeEnterText, afterEnterText); + return this._onEnterSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText); } private static _mergeConf(prev: LanguageConfiguration | null, current: LanguageConfiguration): LanguageConfiguration { @@ -700,17 +700,17 @@ export class LanguageConfigurationRegistryImpl { afterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset); } - let oneLineAboveText = ''; + let previousLineText = ''; if (range.startLineNumber > 1 && scopedLineTokens.firstCharOffset === 0) { // This is not the first line and the entire line belongs to this mode const oneLineAboveScopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber - 1); if (oneLineAboveScopedLineTokens.languageId === scopedLineTokens.languageId) { // The line above ends with text belonging to the same mode - oneLineAboveText = oneLineAboveScopedLineTokens.getLineContent(); + previousLineText = oneLineAboveScopedLineTokens.getLineContent(); } } - const enterResult = richEditSupport.onEnter(autoIndent, oneLineAboveText, beforeEnterText, afterEnterText); + const enterResult = richEditSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText); if (!enterResult) { return null; } diff --git a/src/vs/editor/common/modes/supports/onEnter.ts b/src/vs/editor/common/modes/supports/onEnter.ts index f42cc4a4da22..c03b524394c1 100644 --- a/src/vs/editor/common/modes/supports/onEnter.ts +++ b/src/vs/editor/common/modes/supports/onEnter.ts @@ -49,7 +49,7 @@ export class OnEnterSupport { this._regExpRules = opts.onEnterRules || []; } - public onEnter(autoIndent: EditorAutoIndentStrategy, oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null { + public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null { // (1): `regExpRules` if (autoIndent >= EditorAutoIndentStrategy.Advanced) { for (let i = 0, len = this._regExpRules.length; i < len; i++) { @@ -61,8 +61,8 @@ export class OnEnterSupport { reg: rule.afterText, text: afterEnterText }, { - reg: rule.oneLineAboveText, - text: oneLineAboveText + reg: rule.previousLineText, + text: previousLineText }].every((obj): boolean => { return obj.reg ? obj.reg.test(obj.text) : true; }); diff --git a/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts b/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts index 681c8f02732e..6cdc4a4d0cb9 100644 --- a/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts +++ b/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts @@ -299,13 +299,13 @@ export class MoveLinesCommand implements ICommand { } } - private matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, oneLineAboveText?: string) { + private matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, previousLineText?: string) { let validPrecedingLine = oneLineAbove; while (validPrecedingLine >= 1) { // ship empty lines as empty lines just inherit indentation let lineContent; - if (validPrecedingLine === oneLineAbove && oneLineAboveText !== undefined) { - lineContent = oneLineAboveText; + if (validPrecedingLine === oneLineAbove && previousLineText !== undefined) { + lineContent = previousLineText; } else { lineContent = model.getLineContent(validPrecedingLine); } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 17573b46ecdc..8997154cee50 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -327,7 +327,7 @@ export class LinkDetector implements IEditorContribution { } } - return this.openerService.open(uri, { openToSide, fromUserGesture }); + return this.openerService.open(uri, { openToSide, fromUserGesture, allowContributedOpeners: true }); }, err => { const messageOrError = diff --git a/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts b/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts index d513ef4b91c8..6cfa1e4200d2 100644 --- a/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts +++ b/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { first } from 'vs/base/common/async'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { ITextModel } from 'vs/editor/common/model'; @@ -20,19 +19,26 @@ export const Context = { MultipleSignatures: new RawContextKey('parameterHintsMultipleSignatures', false), }; -export function provideSignatureHelp( +export async function provideSignatureHelp( model: ITextModel, position: Position, context: modes.SignatureHelpContext, token: CancellationToken -): Promise { +): Promise { const supports = modes.SignatureHelpProviderRegistry.ordered(model); - return first(supports.map(support => () => { - return Promise.resolve(support.provideSignatureHelp(model, position, token, context)) - .catch(e => onUnexpectedExternalError(e)); - })); + for (const support of supports) { + try { + const result = await support.provideSignatureHelp(model, position, token, context); + if (result) { + return result; + } + } catch (err) { + onUnexpectedExternalError(err); + } + } + return undefined; } CommandsRegistry.registerCommand('_executeSignatureHelpProvider', async (accessor, ...args: [URI, IPosition, string?]) => { diff --git a/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts b/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts index 7222048074e6..83d8a6cedccb 100644 --- a/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts +++ b/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts @@ -18,7 +18,7 @@ export const javascriptOnEnterRules = [ }, { // e.g. * ...| beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, - oneLineAboveText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, + previousLineText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, action: { indentAction: IndentAction.None, appendText: '* ' } }, { // e.g. */| diff --git a/src/vs/editor/test/common/modes/supports/onEnter.test.ts b/src/vs/editor/test/common/modes/supports/onEnter.test.ts index 5e9794fc3581..1af36e9ef898 100644 --- a/src/vs/editor/test/common/modes/supports/onEnter.test.ts +++ b/src/vs/editor/test/common/modes/supports/onEnter.test.ts @@ -51,8 +51,8 @@ suite('OnEnter', () => { let support = new OnEnterSupport({ onEnterRules: javascriptOnEnterRules }); - let testIndentAction = (oneLineAboveText: string, beforeText: string, afterText: string, expectedIndentAction: IndentAction | null, expectedAppendText: string | null, removeText: number = 0) => { - let actual = support.onEnter(EditorAutoIndentStrategy.Advanced, oneLineAboveText, beforeText, afterText); + let testIndentAction = (previousLineText: string, beforeText: string, afterText: string, expectedIndentAction: IndentAction | null, expectedAppendText: string | null, removeText: number = 0) => { + let actual = support.onEnter(EditorAutoIndentStrategy.Advanced, previousLineText, beforeText, afterText); if (expectedIndentAction === null) { assert.strictEqual(actual, null, 'isNull:' + beforeText); } else { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 2d3e3969cdea..a44b6f671d61 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5417,7 +5417,7 @@ declare namespace monaco.languages { /** * This rule will only execute if the text above the this line matches this regular expression. */ - oneLineAboveText?: RegExp; + previousLineText?: RegExp; /** * The action to execute. */ diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index 20d24771d2b2..393745571d14 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -42,12 +42,16 @@ export class ExtensionIdentifierWithVersion implements IExtensionIdentifierWithV } } +export function getExtensionId(publisher: string, name: string): string { + return `${publisher}.${name}`; +} + export function adoptToGalleryExtensionId(id: string): string { return id.toLocaleLowerCase(); } export function getGalleryExtensionId(publisher: string, name: string): string { - return `${publisher.toLocaleLowerCase()}.${name.toLocaleLowerCase()}`; + return adoptToGalleryExtensionId(getExtensionId(publisher, name)); } export function groupByExtension(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] { diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 3f96fc90032e..ff6740cf677a 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -32,7 +32,11 @@ export type OpenInternalOptions = { readonly fromUserGesture?: boolean; }; -export type OpenExternalOptions = { readonly openExternal?: boolean; readonly allowTunneling?: boolean }; +export type OpenExternalOptions = { + readonly openExternal?: boolean; + readonly allowTunneling?: boolean; + readonly allowContributedOpeners?: boolean | string; +}; export type OpenOptions = OpenInternalOptions & OpenExternalOptions; @@ -47,7 +51,7 @@ export interface IOpener { } export interface IExternalOpener { - openExternal(href: string, ctx: { sourceUri: URI }, token: CancellationToken): Promise; + openExternal(href: string, ctx: { sourceUri: URI, preferredOpenerId?: string }, token: CancellationToken): Promise; dispose?(): void; } diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index 29b9a895a469..b4009323ba2e 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -42,6 +42,24 @@ export interface ITunnelProvider { forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise | undefined; } +export interface ITunnel { + remoteAddress: { port: number, host: string }; + + /** + * The complete local address(ex. localhost:1234) + */ + localAddress: string; + + public?: boolean; + + /** + * Implementers of Tunnel should fire onDidDispose when dispose is called. + */ + onDidDispose: Event; + + dispose(): Promise | void; +} + export interface ITunnelService { readonly _serviceBrand: undefined; @@ -166,6 +184,7 @@ export abstract class AbstractTunnelService implements ITunnelService { } openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded: boolean = false, isPublic: boolean = false): Promise | undefined { + this.logService.trace(`openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`); if (!addressProvider) { return undefined; } @@ -176,14 +195,17 @@ export abstract class AbstractTunnelService implements ITunnelService { const resolvedTunnel = this.retainOrCreateTunnel(addressProvider, remoteHost, remotePort, localPort, elevateIfNeeded, isPublic); if (!resolvedTunnel) { + this.logService.trace(`Tunnel was not created.`); return resolvedTunnel; } return resolvedTunnel.then(tunnel => { if (!tunnel) { + this.logService.trace('New tunnel is undefined.'); this.removeEmptyTunnelFromMap(remoteHost!, remotePort); return undefined; } + this.logService.trace('New tunnel established.'); const newTunnel = this.makeTunnel(tunnel); if (tunnel.tunnelRemoteHost !== remoteHost || tunnel.tunnelRemotePort !== remotePort) { this.logService.warn('Created tunnel does not match requirements of requested tunnel. Host or port mismatch.'); @@ -215,6 +237,7 @@ export abstract class AbstractTunnelService implements ITunnelService { private async tryDisposeTunnel(remoteHost: string, remotePort: number, tunnel: { refcount: number, readonly value: Promise }): Promise { if (tunnel.refcount <= 0) { + this.logService.trace(`Tunnel is being disposed ${remoteHost}:${remotePort}.`); const disposePromise: Promise = tunnel.value.then(async (tunnel) => { if (tunnel) { await tunnel.dispose(true); @@ -282,10 +305,13 @@ export abstract class AbstractTunnelService implements ITunnelService { protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise | undefined; protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise | undefined { + this.logService.trace(`Creating tunnel with provider ${remoteHost}:${remotePort} on local port ${localPort}.`); + const preferredLocalPort = localPort === undefined ? remotePort : localPort; const creationInfo = { elevationRequired: elevateIfNeeded ? isPortPrivileged(preferredLocalPort) : false }; const tunnelOptions: TunnelOptions = { remoteAddress: { host: remoteHost, port: remotePort }, localAddressPort: localPort, public: isPublic }; const tunnel = tunnelProvider.forwardPort(tunnelOptions, creationInfo); + this.logService.trace('Tunnel created by provider.'); if (tunnel) { this.addTunnelToMap(remoteHost, remotePort, tunnel); } diff --git a/src/vs/platform/remote/node/tunnelService.ts b/src/vs/platform/remote/node/tunnelService.ts index 4deae02504ac..80ef45f229e8 100644 --- a/src/vs/platform/remote/node/tunnelService.ts +++ b/src/vs/platform/remote/node/tunnelService.ts @@ -150,6 +150,7 @@ export class BaseTunnelService extends AbstractTunnelService { if (this._tunnelProvider) { return this.createWithProvider(this._tunnelProvider, remoteHost, remotePort, localPort, elevateIfNeeded, isPublic); } else { + this.logService.trace(`Creating tunnel without provider ${remoteHost}:${remotePort} on local port ${localPort}.`); const options: IConnectionOptions = { commit: this.productService.commit, socketFactory: this.socketFactory, @@ -160,6 +161,7 @@ export class BaseTunnelService extends AbstractTunnelService { }; const tunnel = createRemoteTunnel(options, remoteHost, remotePort, localPort); + this.logService.trace('Tunnel created without provider.'); this.addTunnelToMap(remoteHost, remotePort, tunnel); return tunnel; } diff --git a/src/vs/platform/state/node/state.ts b/src/vs/platform/state/node/state.ts index b07335f956f9..9fd896f914cc 100644 --- a/src/vs/platform/state/node/state.ts +++ b/src/vs/platform/state/node/state.ts @@ -12,6 +12,8 @@ export interface IStateService { getItem(key: string, defaultValue: T): T; getItem(key: string, defaultValue?: T): T | undefined; + setItem(key: string, data?: object | string | number | boolean | undefined | null): void; + removeItem(key: string): void; } diff --git a/src/vs/platform/state/node/stateService.ts b/src/vs/platform/state/node/stateService.ts index 0def1cf9c626..cb46b77fac66 100644 --- a/src/vs/platform/state/node/stateService.ts +++ b/src/vs/platform/state/node/stateService.ts @@ -143,7 +143,7 @@ export class StateService implements IStateService { } getItem(key: string, defaultValue: T): T; - getItem(key: string, defaultValue: T | undefined): T | undefined; + getItem(key: string, defaultValue?: T): T | undefined; getItem(key: string, defaultValue?: T): T | undefined { return this.fileStorage.getItem(key, defaultValue); } diff --git a/src/vs/platform/userDataSync/common/extensionsStorageSync.ts b/src/vs/platform/userDataSync/common/extensionsStorageSync.ts index 37846e053f32..3e8f5400e747 100644 --- a/src/vs/platform/userDataSync/common/extensionsStorageSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsStorageSync.ts @@ -5,6 +5,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -32,7 +33,7 @@ export class ExtensionsStorageSyncService extends Disposable implements IExtensi declare readonly _serviceBrand: undefined; private static toKey(extension: IExtensionIdWithVersion): string { - return `extensionKeys/${extension.id}@${extension.version}`; + return `extensionKeys/${adoptToGalleryExtensionId(extension.id)}@${extension.version}`; } private static fromKey(key: string): IExtensionIdWithVersion | undefined { diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index 2158147262b3..7e313f4fb1af 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -11,7 +11,7 @@ import { Event } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { areSameExtensions, getExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { merge } from 'vs/platform/userDataSync/common/extensionsMerge'; @@ -73,6 +73,15 @@ async function parseAndMigrateExtensions(syncData: ISyncData, extensionManagemen return extensions; } +function getExtensionStorageState(publisher: string, name: string, storageService: IStorageService): IStringDictionary { + const extensionStorageValue = storageService.get(getExtensionId(publisher, name) /* use the same id used in extension host */, StorageScope.GLOBAL) || '{}'; + return JSON.parse(extensionStorageValue); +} + +function storeExtensionStorageState(publisher: string, name: string, extensionState: IStringDictionary, storageService: IStorageService): void { + storageService.store(getExtensionId(publisher, name) /* use the same id used in extension host */, JSON.stringify(extensionState), StorageScope.GLOBAL, StorageTarget.MACHINE); +} + export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { private static readonly EXTENSIONS_DATA_URI = URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'extensions', path: `/extensions.json` }); @@ -99,7 +108,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse @IUserDataSyncBackupStoreService userDataSyncBackupStoreService: IUserDataSyncBackupStoreService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService, - @IIgnoredExtensionsManagementService private readonly extensionSyncManagementService: IIgnoredExtensionsManagementService, + @IIgnoredExtensionsManagementService private readonly ignoredExtensionsManagementService: IIgnoredExtensionsManagementService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService configurationService: IConfigurationService, @@ -125,7 +134,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const installedExtensions = await this.extensionManagementService.getInstalled(); const localExtensions = this.getLocalExtensions(installedExtensions); - const ignoredExtensions = this.extensionSyncManagementService.getIgnoredExtensions(installedExtensions); + const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); if (remoteExtensions) { this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`); @@ -209,7 +218,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse private async acceptLocal(resourcePreview: IExtensionResourcePreview): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(); - const ignoredExtensions = this.extensionSyncManagementService.getIgnoredExtensions(installedExtensions); + const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); const mergeResult = merge(resourcePreview.localExtensions, null, null, resourcePreview.skippedExtensions, ignoredExtensions); const { added, removed, updated, remote } = mergeResult; return { @@ -225,7 +234,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse private async acceptRemote(resourcePreview: IExtensionResourcePreview): Promise { const installedExtensions = await this.extensionManagementService.getInstalled(); - const ignoredExtensions = this.extensionSyncManagementService.getIgnoredExtensions(installedExtensions); + const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); const remoteExtensions = resourcePreview.remoteContent ? JSON.parse(resourcePreview.remoteContent) : null; if (remoteExtensions !== null) { const mergeResult = merge(resourcePreview.localExtensions, remoteExtensions, resourcePreview.localExtensions, [], ignoredExtensions); @@ -285,7 +294,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse async resolveContent(uri: URI): Promise { if (this.extUri.isEqual(uri, ExtensionsSynchroniser.EXTENSIONS_DATA_URI)) { const installedExtensions = await this.extensionManagementService.getInstalled(); - const ignoredExtensions = this.extensionSyncManagementService.getIgnoredExtensions(installedExtensions); + const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions); const localExtensions = this.getLocalExtensions(installedExtensions).filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier))); return this.format(localExtensions); } @@ -363,7 +372,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse // Builtin Extension Sync: Enablement & State if (installedExtension && installedExtension.isBuiltin) { if (e.state && installedExtension.manifest.version === e.version) { - this.updateExtensionState(e.state, e.identifier.id, installedExtension.manifest.version); + this.updateExtensionState(e.state, installedExtension.manifest.publisher, installedExtension.manifest.name, installedExtension.manifest.version); } if (e.disabled) { this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...`, e.identifier.id); @@ -382,14 +391,16 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse const extension = await this.extensionGalleryService.getCompatibleExtension(e.identifier); /* Update extension state only if - * extension is installed and version is same as synced version or - * extension is not installed and installable + * extension is installed and version is same as synced version or + * extension is not installed and installable */ if (e.state && (installedExtension ? installedExtension.manifest.version === e.version /* Installed and has same version */ : !!extension /* Installable */) ) { - this.updateExtensionState(e.state, e.identifier.id, installedExtension?.manifest.version); + const publisher = installedExtension ? installedExtension.manifest.publisher : extension!.publisher; + const name = installedExtension ? installedExtension.manifest.name : extension!.name; + this.updateExtensionState(e.state, publisher, name, installedExtension?.manifest.version); } if (extension) { @@ -436,15 +447,15 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse return newSkippedExtensions; } - private updateExtensionState(state: IStringDictionary, id: string, version?: string): void { - const extensionState = JSON.parse(this.storageService.get(id, StorageScope.GLOBAL) || '{}'); - const keys = version ? this.extensionsStorageSyncService.getKeysForSync({ id, version }) : undefined; + private updateExtensionState(state: IStringDictionary, publisher: string, name: string, version: string | undefined): void { + const extensionState = getExtensionStorageState(publisher, name, this.storageService); + const keys = version ? this.extensionsStorageSyncService.getKeysForSync({ id: getGalleryExtensionId(publisher, name), version }) : undefined; if (keys) { keys.forEach(key => extensionState[key] = state[key]); } else { forEach(state, ({ key, value }) => extensionState[key] = value); } - this.storageService.store(id, JSON.stringify(extensionState), StorageScope.GLOBAL, StorageTarget.MACHINE); + storeExtensionStorageState(publisher, name, extensionState, this.storageService); } private parseExtensions(syncData: ISyncData): ISyncExtension[] { @@ -465,8 +476,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse try { const keys = this.extensionsStorageSyncService.getKeysForSync({ id: identifier.id, version: manifest.version }); if (keys) { - const extensionStorageValue = this.storageService.get(identifier.id, StorageScope.GLOBAL) || '{}'; - const extensionStorageState = JSON.parse(extensionStorageValue); + const extensionStorageState = getExtensionStorageState(manifest.publisher, manifest.name, this.storageService); syncExntesion.state = Object.keys(extensionStorageState).reduce((state: IStringDictionary, key) => { if (keys.includes(key)) { state[key] = extensionStorageState[key]; @@ -490,6 +500,7 @@ export class ExtensionsInitializer extends AbstractInitializer { @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, @IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService, @IStorageService private readonly storageService: IStorageService, + @IIgnoredExtensionsManagementService private readonly ignoredExtensionsManagementService: IIgnoredExtensionsManagementService, @IFileService fileService: IFileService, @IEnvironmentService environmentService: IEnvironmentService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @@ -511,12 +522,18 @@ export class ExtensionsInitializer extends AbstractInitializer { const newlyEnabledExtensions: ILocalExtension[] = []; const installedExtensions = await this.extensionManagementService.getInstalled(); const newExtensionsToSync = new Map(); - const installedExtensionsToSync: ISyncExtension[] = []; + const installedExtensionsToSync: { syncExtension: ISyncExtension, installedExtension: ILocalExtension }[] = []; const toInstall: { names: string[], uuids: string[] } = { names: [], uuids: [] }; const toDisable: IExtensionIdentifier[] = []; for (const extension of remoteExtensions) { - if (installedExtensions.some(i => areSameExtensions(i.identifier, extension.identifier))) { - installedExtensionsToSync.push(extension); + if (this.ignoredExtensionsManagementService.hasToNeverSyncExtension(extension.identifier.id)) { + // Skip extension ignored to sync + continue; + } + + const installedExtension = installedExtensions.find(i => areSameExtensions(i.identifier, extension.identifier)); + if (installedExtension) { + installedExtensionsToSync.push({ syncExtension: extension, installedExtension }); if (extension.disabled) { toDisable.push(extension.identifier); } @@ -536,11 +553,11 @@ export class ExtensionsInitializer extends AbstractInitializer { } // 1. Initialise already installed extensions state - for (const extensionToSync of installedExtensionsToSync) { - if (extensionToSync.state) { - const extensionState = JSON.parse(this.storageService.get(extensionToSync.identifier.id, StorageScope.GLOBAL) || '{}'); - forEach(extensionToSync.state, ({ key, value }) => extensionState[key] = value); - this.storageService.store(extensionToSync.identifier.id, JSON.stringify(extensionState), StorageScope.GLOBAL, StorageTarget.MACHINE); + for (const { syncExtension, installedExtension } of installedExtensionsToSync) { + if (syncExtension.state) { + const extensionState = getExtensionStorageState(installedExtension.manifest.publisher, installedExtension.manifest.name, this.storageService); + forEach(syncExtension.state, ({ key, value }) => extensionState[key] = value); + storeExtensionStorageState(installedExtension.manifest.publisher, installedExtension.manifest.name, extensionState, this.storageService); } } @@ -560,7 +577,7 @@ export class ExtensionsInitializer extends AbstractInitializer { try { const extensionToSync = newExtensionsToSync.get(galleryExtension.identifier.id.toLowerCase())!; if (extensionToSync.state) { - this.storageService.store(extensionToSync.identifier.id, JSON.stringify(extensionToSync.state), StorageScope.GLOBAL, StorageTarget.MACHINE); + storeExtensionStorageState(galleryExtension.publisher, galleryExtension.name, extensionToSync.state, this.storageService); } this.logService.trace(`Installing extension...`, galleryExtension.identifier.id); const local = await this.extensionManagementService.installFromGallery(galleryExtension, { isMachineScoped: false } /* pass options to prevent install and sync dialog in web */); diff --git a/src/vs/platform/webview/common/resourceLoader.ts b/src/vs/platform/webview/common/resourceLoader.ts index ac2931d3fe80..46f0217fa20f 100644 --- a/src/vs/platform/webview/common/resourceLoader.ts +++ b/src/vs/platform/webview/common/resourceLoader.ts @@ -25,7 +25,8 @@ export namespace WebviewResourceResponse { constructor( public readonly stream: VSBufferReadableStream, - public readonly mimeType: string + public readonly etag: string | undefined, + public readonly mimeType: string, ) { } } @@ -36,7 +37,7 @@ export namespace WebviewResourceResponse { } interface FileReader { - readFileStream(resource: URI): Promise; + readFileStream(resource: URI): Promise<{ stream: VSBufferReadableStream, etag?: string }>; } export async function loadLocalResource( @@ -73,7 +74,7 @@ export async function loadLocalResource( logService.debug(`loadLocalResource - Loaded over http(s). requestUri=${requestUri}, response=${response.res.statusCode}`); if (response.res.statusCode === 200) { - return new WebviewResourceResponse.StreamSuccess(response.stream, mime); + return new WebviewResourceResponse.StreamSuccess(response.stream, undefined, mime); } return WebviewResourceResponse.Failed; } @@ -82,7 +83,7 @@ export async function loadLocalResource( const contents = await fileReader.readFileStream(resourceToLoad); logService.debug(`loadLocalResource - Loaded using fileReader. requestUri=${requestUri}`); - return new WebviewResourceResponse.StreamSuccess(contents, mime); + return new WebviewResourceResponse.StreamSuccess(contents.stream, contents.etag, mime); } catch (err) { logService.debug(`loadLocalResource - Error using fileReader. requestUri=${requestUri}`); console.log(err); diff --git a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts index ea3a6dee8a97..a8c2e0fefa39 100644 --- a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts +++ b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts @@ -175,10 +175,14 @@ export class WebviewProtocolProvider extends Disposable { }; } - const fileService = { - readFileStream: async (resource: URI): Promise => { + const fileReader = { + readFileStream: async (resource: URI): Promise<{ stream: VSBufferReadableStream, etag?: string }> => { if (resource.scheme === Schemas.file) { - return (await this.fileService.readFileStream(resource)).value; + const result = (await this.fileService.readFileStream(resource)); + return { + stream: result.value, + etag: result.etag + }; } // Unknown uri scheme. Try delegating the file read back to the renderer @@ -201,7 +205,7 @@ export class WebviewProtocolProvider extends Disposable { throw new FileOperationError('Could not read file', FileOperationResult.FILE_NOT_FOUND); } - return bufferToStream(result); + return { stream: bufferToStream(result), etag: undefined }; } }; @@ -210,15 +214,41 @@ export class WebviewProtocolProvider extends Disposable { roots: metadata.localResourceRoots, remoteConnectionData: metadata.remoteConnectionData, rewriteUri, - }, fileService, this.requestService, this.logService); + }, fileReader, this.requestService, this.logService); if (result.type === WebviewResourceResponse.Type.Success) { + const cacheHeaders: Record = result.etag ? { + 'ETag': result.etag, + 'Cache-Control': 'no-cache' + } : {}; + + const ifNoneMatch = request.headers['If-None-Match']; + if (ifNoneMatch && result.etag === ifNoneMatch) { + /* + * Note that the server generating a 304 response MUST + * generate any of the following header fields that would + * have been sent in a 200 (OK) response to the same request: + * Cache-Control, Content-Location, Date, ETag, Expires, and Vary. + * (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) + */ + return callback({ + statusCode: 304, // not modified + data: undefined, // The request fails if `data` is not set + headers: { + 'Content-Type': result.mimeType, + 'Access-Control-Allow-Origin': '*', + ...cacheHeaders + } + }); + } + return callback({ statusCode: 200, data: this.streamToNodeReadable(result.stream), headers: { 'Content-Type': result.mimeType, 'Access-Control-Allow-Origin': '*', + ...cacheHeaders } }); } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b6e8fb8567f3..2fdb125187fb 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -4697,6 +4697,10 @@ declare module 'vscode' { * This rule will only execute if the text after the cursor matches this regular expression. */ afterText?: RegExp; + /** + * This rule will only execute if the text above the current line matches this regular expression. + */ + previousLineText?: RegExp; /** * The action to execute. */ @@ -5821,6 +5825,11 @@ declare module 'vscode' { setKeysForSync(keys: string[]): void; }; + /** + * A storage utility for secrets. + */ + readonly secrets: SecretStorage; + /** * The uri of the directory containing the extension. */ @@ -5958,6 +5967,48 @@ declare module 'vscode' { update(key: string, value: any): Thenable; } + /** + * The event data that is fired when a secret is added or removed. + */ + export interface SecretStorageChangeEvent { + /** + * The key of the secret that has changed. + */ + readonly key: string; + } + + /** + * Represents a storage utility for secrets, information that is + * sensitive. + */ + export interface SecretStorage { + /** + * Retrieve a secret that was stored with key. Returns undefined if there + * is no password matching that key. + * @param key The key the secret was stored under. + * @returns The stored value or `undefined`. + */ + get(key: string): Thenable; + + /** + * Store a secret under a given key. + * @param key The key to store the secret under. + * @param value The secret. + */ + store(key: string, value: string): Thenable; + + /** + * Remove a secret from storage. + * @param key The key the secret was stored under. + */ + delete(key: string): Thenable; + + /** + * Fires when a secret is stored or deleted. + */ + onDidChange: Event; + } + /** * Represents a color theme kind. */ @@ -12161,7 +12212,7 @@ declare module 'vscode' { /** * Optional reaction handler for creating and deleting reactions on a [comment](#Comment). */ - reactionHandler?: (comment: Comment, reaction: CommentReaction) => Promise; + reactionHandler?: (comment: Comment, reaction: CommentReaction) => Thenable; /** * Dispose this comment controller. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index a075694507a1..228526db133f 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -881,15 +881,6 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/58440 - export interface OnEnterRule { - /** - * This rule will only execute if the text above the this line matches this regular expression. - */ - oneLineAboveText?: RegExp; - } - //#endregion - //#region Tree View: https://github.com/microsoft/vscode/issues/61313 @alexr00 export interface TreeView extends Disposable { reveal(element: T | undefined, options?: { select?: boolean, focus?: boolean, expand?: boolean | number; }): Thenable; @@ -1577,16 +1568,16 @@ declare module 'vscode' { * resolve the raw content for `uri` as the resouce is not necessarily a file on disk. */ // eslint-disable-next-line vscode-dts-provider-naming - openNotebook(uri: Uri, openContext: NotebookDocumentOpenContext): NotebookData | Promise; + openNotebook(uri: Uri, openContext: NotebookDocumentOpenContext): NotebookData | Thenable; // eslint-disable-next-line vscode-dts-provider-naming // eslint-disable-next-line vscode-dts-cancellation - resolveNotebook(document: NotebookDocument, webview: NotebookCommunication): Promise; + resolveNotebook(document: NotebookDocument, webview: NotebookCommunication): Thenable; // eslint-disable-next-line vscode-dts-provider-naming - saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Promise; + saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Thenable; // eslint-disable-next-line vscode-dts-provider-naming - saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Promise; + saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Thenable; // eslint-disable-next-line vscode-dts-provider-naming - backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, cancellation: CancellationToken): Promise; + backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, cancellation: CancellationToken): Thenable; } export interface NotebookKernel { @@ -1685,7 +1676,7 @@ declare module 'vscode' { ): Disposable; export function createNotebookEditorDecorationType(options: NotebookDecorationRenderOptions): NotebookEditorDecorationType; - export function openNotebookDocument(uri: Uri, viewType?: string): Promise; + export function openNotebookDocument(uri: Uri, viewType?: string): Thenable; export const onDidOpenNotebookDocument: Event; export const onDidCloseNotebookDocument: Event; export const onDidSaveNotebookDocument: Event; @@ -1729,7 +1720,7 @@ declare module 'vscode' { export const onDidChangeActiveNotebookEditor: Event; export const onDidChangeNotebookEditorSelection: Event; export const onDidChangeNotebookEditorVisibleRanges: Event; - export function showNotebookDocument(document: NotebookDocument, options?: NotebookDocumentShowOptions): Promise; + export function showNotebookDocument(document: NotebookDocument, options?: NotebookDocumentShowOptions): Thenable; } //#endregion @@ -1940,7 +1931,7 @@ declare module 'vscode' { } export namespace languages { - export function getTokenInformationAtPosition(document: TextDocument, position: Position): Promise; + export function getTokenInformationAtPosition(document: TextDocument, position: Position): Thenable; } //#endregion @@ -2367,13 +2358,6 @@ declare module 'vscode' { location?: Location; } - /** - * Additional metadata about the uri being opened - */ - interface OpenExternalUriContext { - - } - //#endregion //#region Opener service (https://github.com/microsoft/vscode/issues/109277) @@ -2497,54 +2481,38 @@ declare module 'vscode' { export function registerExternalUriOpener(id: string, schemes: readonly string[], opener: ExternalUriOpener, metadata: ExternalUriOpenerMetadata): Disposable; } - //#endregion - - //#region https://github.com/microsoft/vscode/issues/112249 - - /** - * The event data that is fired when a secret is added or removed. - */ - export interface SecretStorageChangeEvent { + interface OpenExternalOptions { /** - * The key of the secret that has changed. + * + * If `true`, then VS Code will check if any contributed openers can handle the + * uri, and fallback to the default opener behavior. + * + * If it is string, then this specifies the id of the `ExternalUriOpener` + * that should be used if it is available. Use `'default'` to force VS Code's + * standard external opener to be used. */ - key: string; + readonly allowContributedOpeners?: boolean | string; } - /** - * Represents a storage utility for secrets, information that is - * sensitive. - */ - export interface SecretStorage { - /** - * Retrieve a secret that was stored with key. Returns undefined if there - * is no password matching that key. - * @param key The key the password was stored under. - * @returns The stored value or `undefined`. - */ - get(key: string): Thenable; - - /** - * Store a secret under a given key. - * @param key The key to store the password under. - * @param value The password. - */ - set(key: string, value: string): Thenable; - - /** - * Remove a secret from storage. - * @param key The key the password was stored under. - */ - delete(key: string): Thenable; - - /** - * Fires when a secret is set or deleted. - */ - onDidChange: Event; + namespace env { + export function openExternal(target: Uri, options?: OpenExternalOptions): Thenable; } - export interface ExtensionContext { - secrets: SecretStorage; + //#endregionn + + //#region https://github.com/Microsoft/vscode/issues/15178 + + // TODO@API must be a class + export interface OpenEditorInfo { + name: string; + resource: Uri; + } + + export namespace window { + export const openEditors: ReadonlyArray; + + // todo@API proper event type + export const onDidChangeOpenEditors: Event; } //#endregion diff --git a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts index 962cf85f2675..2e6aaffa5e46 100644 --- a/src/vs/workbench/api/browser/mainThreadEditorTabs.ts +++ b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts @@ -3,13 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { Verbosity } from 'vs/workbench/common/editor'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; export interface ITabInfo { name: string; @@ -19,34 +18,62 @@ export interface ITabInfo { @extHostNamedCustomer(MainContext.MainThreadEditorTabs) export class MainThreadEditorTabs { - private readonly _registration: IDisposable; + private static _GroupEventFilter = new Set([GroupChangeKind.EDITOR_CLOSE, GroupChangeKind.EDITOR_OPEN]); + + private readonly _dispoables = new DisposableStore(); + private readonly _groups = new Map(); + private readonly _proxy: IExtHostEditorTabsShape; constructor( - _extHostContext: IExtHostContext, + extHostContext: IExtHostContext, @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, ) { - this._registration = CommandsRegistry.registerCommand('_textEditorTabs', () => { - return this._fetchTextEditors(); - }); + + this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs); + + this._editorGroupsService.groups.forEach(this._subscribeToGroup, this); + this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this)); + this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => { + const subscription = this._groups.get(e); + if (subscription) { + subscription.dispose(); + this._groups.delete(e); + this._pushEditorTabs(); + } + })); + this._pushEditorTabs(); } dispose(): void { - this._registration.dispose(); + dispose(this._groups.values()); + this._dispoables.dispose(); } - private _fetchTextEditors(): ITabInfo[] { - const result: ITabInfo[] = []; + private _subscribeToGroup(group: IEditorGroup) { + this._groups.get(group)?.dispose(); + const listener = group.onDidGroupChange(e => { + if (MainThreadEditorTabs._GroupEventFilter.has(e.kind)) { + this._pushEditorTabs(); + } + }); + this._groups.set(group, listener); + } + + private _pushEditorTabs(): void { + const tabs: IEditorTabDto[] = []; for (const group of this._editorGroupsService.groups) { for (const editor of group.editors) { if (editor.isDisposed() || !editor.resource) { continue; } - result.push({ + tabs.push({ + group: group.id, name: editor.getTitle(Verbosity.SHORT) ?? '', resource: editor.resource }); } } - return result; + + this._proxy.$acceptEditorTabs(tabs); } } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index c0f64b5e8d57..391cc7addbf6 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -688,7 +688,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return { beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText), afterText: onEnterRule.afterText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText) : undefined, - oneLineAboveText: onEnterRule.oneLineAboveText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.oneLineAboveText) : undefined, + previousLineText: onEnterRule.previousLineText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.previousLineText) : undefined, action: onEnterRule.action }; } diff --git a/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts index 4e255fc43a2d..95fc3087629f 100644 --- a/src/vs/workbench/api/browser/mainThreadTesting.ts +++ b/src/vs/workbench/api/browser/mainThreadTesting.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { getTestSubscriptionKey, RunTestsRequest, RunTestsResult, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; -import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostTestingResource, ExtHostTestingShape, IExtHostContext, MainContext, MainThreadTestingShape } from '../common/extHost.protocol'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { CancellationToken } from 'vs/base/common/cancellation'; const reviveDiff = (diff: TestsDiff) => { for (const entry of diff) { @@ -41,6 +41,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostTesting); this._register(this.testService.onShouldSubscribe(args => this.proxy.$subscribeToTests(args.resource, args.uri))); this._register(this.testService.onShouldUnsubscribe(args => this.proxy.$unsubscribeFromTests(args.resource, args.uri))); + testService.updateRootProviderCount(1); for (const { resource, uri } of this.testService.subscriptions) { this.proxy.$subscribeToTests(resource, uri); @@ -64,13 +65,6 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh this.testService.unregisterTestController(id); } - /** - * @inheritdoc - */ - $updateDiscoveringCount(resource: ExtHostTestingResource, uriComponents: UriComponents, delta: number): void { - this.testService.updateDiscoveringCount(resource, URI.revive(uriComponents), delta); - } - /** * @inheritdoc */ @@ -103,6 +97,10 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh } public dispose() { - // no-op + this.testService.updateRootProviderCount(-1); + for (const subscription of this.testSubscriptions.values()) { + subscription.dispose(); + } + this.testSubscriptions.clear(); } } diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index 7b230129727e..82425aadb0cb 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -14,6 +14,7 @@ import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorit import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { PORT_AUTO_FORWARD_SETTING } from 'vs/workbench/contrib/remote/browser/tunnelView'; +import { ILogService } from 'vs/platform/log/common/log'; @extHostNamedCustomer(MainContext.MainThreadTunnelService) export class MainThreadTunnelService extends Disposable implements MainThreadTunnelServiceShape { @@ -25,7 +26,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService, @ITunnelService private readonly tunnelService: ITunnelService, @INotificationService private readonly notificationService: INotificationService, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @ILogService private readonly logService: ILogService ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTunnelService); @@ -100,6 +102,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun const forward = this._proxy.$forwardPort(tunnelOptions, tunnelCreationOptions); if (forward) { return forward.then(tunnel => { + this.logService.trace(`MainThreadTunnelService: New tunnel established by tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); if (!tunnel) { return undefined; } @@ -110,6 +113,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined, public: tunnel.public, dispose: async (silent?: boolean) => { + this.logService.trace(`MainThreadTunnelService: Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); return this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port }, silent); } }; diff --git a/src/vs/workbench/api/browser/mainThreadWebviews.ts b/src/vs/workbench/api/browser/mainThreadWebviews.ts index cc5b05c298b2..684096227962 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviews.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviews.ts @@ -78,7 +78,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma private onDidClickLink(handle: extHostProtocol.WebviewHandle, link: string): void { const webview = this.getWebview(handle); if (this.isSupportedLink(webview, URI.parse(link))) { - this._openerService.open(link, { fromUserGesture: true }); + this._openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true }); } } diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index 2a431111e936..7f10aa334c6b 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -52,7 +52,11 @@ export class MainThreadWindow implements MainThreadWindowShape { // called with URI or transformed -> use uri target = uri; } - return this.openerService.open(target, { openExternal: true, allowTunneling: options.allowTunneling }); + return this.openerService.open(target, { + openExternal: true, + allowTunneling: options.allowTunneling, + allowContributedOpeners: options.allowContributedOpeners, + }); } async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index cfcebdf52663..84b95cfc719d 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -3,35 +3,32 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; +import { coalesce } from 'vs/base/common/arrays'; import { forEach } from 'vs/base/common/collections'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as resources from 'vs/base/common/resources'; -import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ViewContainer, IViewsRegistry, ITreeViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IViewDescriptor, ViewContainerLocation, testViewIcon } from 'vs/workbench/common/views'; -import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { coalesce, } from 'vs/base/common/arrays'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files'; -import { VIEWLET_ID as SCM } from 'vs/workbench/contrib/scm/common/scm'; -import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug'; -import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/browser/remoteExplorer'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; -import { ViewletRegistry, Extensions as ViewletExtensions, ShowViewletAction } from 'vs/workbench/browser/viewlet'; -import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { localize } from 'vs/nls'; +import { registerAction2 } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { WebviewViewPane } from 'vs/workbench/contrib/webviewView/browser/webviewViewPane'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { Registry } from 'vs/platform/registry/common/platform'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView'; +import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { Extensions as ViewletExtensions, ShowViewletAction2, ViewletRegistry } from 'vs/workbench/browser/viewlet'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views'; +import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug'; +import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files'; +import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/browser/remoteExplorer'; +import { VIEWLET_ID as SCM } from 'vs/workbench/contrib/scm/common/scm'; +import { WebviewViewPane } from 'vs/workbench/contrib/webviewView/browser/webviewViewPane'; +import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; export interface IUserFriendlyViewsContainerDescriptor { id: string; @@ -255,7 +252,8 @@ const viewsExtensionPoint: IExtensionPoint = ExtensionsR jsonSchema: viewsContribution }); -const TEST_VIEW_CONTAINER_ORDER = 6; +const CUSTOM_VIEWS_START_ORDER = 7; + class ViewsExtensionHandler implements IWorkbenchContribution { private viewContainersRegistry: IViewContainersRegistry; @@ -271,7 +269,6 @@ class ViewsExtensionHandler implements IWorkbenchContribution { } private handleAndRegisterCustomViewContainers() { - this.registerTestViewContainer(); viewsContainersExtensionPoint.setHandler((extensions, { added, removed }) => { if (removed.length) { this.removeCustomViewContainers(removed); @@ -284,7 +281,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { private addCustomViewContainers(extensionPoints: readonly IExtensionPointUser[], existingViewContainers: ViewContainer[]): void { const viewContainersRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); - let activityBarOrder = TEST_VIEW_CONTAINER_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Sidebar).length + 1; + let activityBarOrder = CUSTOM_VIEWS_START_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Sidebar).length; let panelOrder = 5 + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Panel).length + 1; for (let { value, collector, description } of extensionPoints) { forEach(value, entry => { @@ -318,13 +315,6 @@ class ViewsExtensionHandler implements IWorkbenchContribution { } } - private registerTestViewContainer(): void { - const title = localize('test', "Test"); - const icon = testViewIcon; - - this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, undefined, ViewContainerLocation.Sidebar); - } - private isValidViewsContainer(viewsContainersDescriptors: IUserFriendlyViewsContainerDescriptor[], collector: ExtensionMessageCollector): boolean { if (!Array.isArray(viewsContainersDescriptors)) { collector.error(localize('viewcontainer requirearray', "views containers must be an array")); @@ -395,22 +385,15 @@ class ViewsExtensionHandler implements IWorkbenchContribution { }, location); // Register Action to Open Viewlet - class OpenCustomViewletAction extends ShowViewletAction { - constructor( - id: string, label: string, - @IViewletService viewletService: IViewletService, - @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService - ) { - super(id, label, id, viewletService, editorGroupService, layoutService); + registerAction2(class OpenCustomViewletAction extends ShowViewletAction2 { + constructor() { + super({ id, f1: true, title: localize('showViewlet', "Show {0}", title), category: CATEGORIES.View.value }); } - } - const registry = Registry.as(ActionExtensions.WorkbenchActions); - registry.registerWorkbenchAction( - SyncActionDescriptor.create(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)), - `View: Show ${title}`, - CATEGORIES.View.value - ); + + protected viewletId() { + return id; + } + }); } return viewContainer; diff --git a/src/vs/workbench/api/common/exHostSecretState.ts b/src/vs/workbench/api/common/exHostSecretState.ts index 2715b881f753..b06f12450948 100644 --- a/src/vs/workbench/api/common/exHostSecretState.ts +++ b/src/vs/workbench/api/common/exHostSecretState.ts @@ -25,7 +25,7 @@ export class ExtHostSecretState implements ExtHostSecretStateShape { return this._proxy.$getPassword(extensionId, key); } - set(extensionId: string, key: string, value: string): Promise { + store(extensionId: string, key: string, value: string): Promise { return this._proxy.$setPassword(extensionId, key, value); } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 5e90f0ae27ba..5b65bfc9758a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -84,6 +84,7 @@ import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSyste import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting'; import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener'; import { IExtHostSecretState } from 'vs/workbench/api/common/exHostSecretState'; +import { ExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -133,6 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, accessor.get(IExtHostOutputService)); // manually create and register addressable instances + const extHostEditorTabs = rpcProtocol.set(ExtHostContext.ExtHostEditorTabs, new ExtHostEditorTabs()); const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol)); const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService)); @@ -292,8 +294,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I get shell() { return extHostTerminalService.getDefaultShell(false, configProvider); }, - openExternal(uri: URI) { - return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.authority }); + openExternal(uri: URI, options?: { allowContributedOpeners?: boolean | string; }) { + return extHostWindow.openUri(uri, { + allowTunneling: !!initData.remote.authority, + allowContributedOpeners: options?.allowContributedOpeners, + }); }, asExternalUri(uri: URI) { if (uri.scheme === initData.environment.appUriScheme) { @@ -680,6 +685,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return extHostUriOpeners.registerUriOpener(extension.identifier, id, schemes, opener, metadata); }, + get openEditors() { + checkProposedApiEnabled(extension); + return extHostEditorTabs.tabs; + }, + get onDidChangeOpenEditors() { + checkProposedApiEnabled(extension); + return extHostEditorTabs.onDidChangeTabs; + } }; // namespace: workspace diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8cdc92b4a5e5..7bc234158d59 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -335,7 +335,7 @@ export interface IIndentationRuleDto { export interface IOnEnterRuleDto { beforeText: IRegExpDto; afterText?: IRegExpDto; - oneLineAboveText?: IRegExpDto; + previousLineText?: IRegExpDto; action: EnterAction; } export interface ILanguageConfigurationDto { @@ -607,15 +607,29 @@ export interface MainThreadEditorInsetsShape extends IDisposable { $postMessage(handle: number, value: any): Promise; } -export interface MainThreadEditorTabsShape extends IDisposable { - -} - export interface ExtHostEditorInsetsShape { $onDidDispose(handle: number): void; $onDidReceiveMessage(handle: number, message: any): void; } +//#region --- open editors model + +export interface MainThreadEditorTabsShape extends IDisposable { + // manage tabs: move, close, rearrange etc +} + +export interface IEditorTabDto { + group: number; + name: string; + resource: UriComponents +} + +export interface IExtHostEditorTabsShape { + $acceptEditorTabs(tabs: IEditorTabDto[]): void; +} + +//#endregion + export type WebviewHandle = string; export interface WebviewPanelShowOptions { @@ -980,6 +994,7 @@ export interface MainThreadDebugServiceShape extends IDisposable { export interface IOpenUriOptions { readonly allowTunneling?: boolean; + readonly allowContributedOpeners?: boolean | string; } export interface MainThreadWindowShape extends IDisposable { @@ -1838,7 +1853,6 @@ export interface MainThreadTestingShape { $unsubscribeFromDiffs(resource: ExtHostTestingResource, uri: UriComponents): void; $publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void; $runTests(req: RunTestsRequest, token: CancellationToken): Promise; - $updateDiscoveringCount(resource: ExtHostTestingResource, uri: UriComponents, delta: number): void; } // --- proxy identifiers @@ -1927,6 +1941,7 @@ export const ExtHostContext = { ExtHostCustomEditors: createExtId('ExtHostCustomEditors'), ExtHostWebviewViews: createExtId('ExtHostWebviewViews'), ExtHostEditorInsets: createExtId('ExtHostEditorInsets'), + ExtHostEditorTabs: createExtId('ExtHostEditorTabs'), ExtHostProgress: createMainId('ExtHostProgress'), ExtHostComments: createMainId('ExtHostComments'), ExtHostSecretState: createMainId('ExtHostSecretState'), diff --git a/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts new file mode 100644 index 000000000000..2d0f7b4c697f --- /dev/null +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as vscode from 'vscode'; +import { IEditorTabDto, IExtHostEditorTabsShape } from 'vs/workbench/api/common/extHost.protocol'; +import { URI } from 'vs/base/common/uri'; +import { Emitter, Event } from 'vs/base/common/event'; + + +export interface IEditorTab { + name: string; + group: number; + resource: vscode.Uri +} + +export class ExtHostEditorTabs implements IExtHostEditorTabsShape { + + private readonly _onDidChangeTabs = new Emitter(); + readonly onDidChangeTabs: Event = this._onDidChangeTabs.event; + + private _tabs: IEditorTab[] = []; + + get tabs(): readonly IEditorTab[] { + return this._tabs; + } + + $acceptEditorTabs(tabs: IEditorTabDto[]): void { + this._tabs = tabs.map(dto => { + return { + name: dto.name, + group: dto.group, + resource: URI.revive(dto.resource) + }; + }); + this._onDidChangeTabs.fire(); + } +} diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index c09066055e64..34ca106504db 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1921,7 +1921,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF return { beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText), afterText: onEnterRule.afterText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText) : undefined, - oneLineAboveText: onEnterRule.oneLineAboveText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.oneLineAboveText) : undefined, + previousLineText: onEnterRule.previousLineText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.previousLineText) : undefined, action: onEnterRule.action }; } diff --git a/src/vs/workbench/api/common/extHostSecrets.ts b/src/vs/workbench/api/common/extHostSecrets.ts index 837b36f514f5..a593f0ad1f70 100644 --- a/src/vs/workbench/api/common/extHostSecrets.ts +++ b/src/vs/workbench/api/common/extHostSecrets.ts @@ -33,8 +33,8 @@ export class ExtensionSecrets implements vscode.SecretStorage { return this._secretState.get(this._id, key); } - set(key: string, value: string): Promise { - return this._secretState.set(this._id, key, value); + store(key: string, value: string): Promise { + return this._secretState.store(this._id, key, value); } delete(key: string): Promise { diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index 0fd593807bcc..70903d93e39b 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { mapFind } from 'vs/base/common/arrays'; -import { disposableTimeout, RunOnceScheduler } from 'vs/base/common/async'; +import { disposableTimeout } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { once } from 'vs/base/common/functional'; @@ -19,7 +19,7 @@ import { TestItem } from 'vs/workbench/api/common/extHostTypeConverters'; import { Disposable, RequiredTestItem } from 'vs/workbench/api/common/extHostTypes'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { OwnedTestCollection, SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection'; -import { AbstractIncrementalTestCollection, EMPTY_TEST_RESULT, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, RunTestForProviderRequest, RunTestsResult, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { AbstractIncrementalTestCollection, EMPTY_TEST_RESULT, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, RunTestForProviderRequest, RunTestsResult, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import type * as vscode from 'vscode'; const getTestSubscriptionKey = (resource: ExtHostTestingResource, uri: URI) => `${resource}:${uri.toString()}`; @@ -125,19 +125,6 @@ export class ExtHostTesting implements ExtHostTestingShape { return; } - let delta = 0; - const updateCountScheduler = new RunOnceScheduler(() => { - if (delta !== 0) { - this.proxy.$updateDiscoveringCount(resource, uri, delta); - delta = 0; - } - }, 5); - - const updateDelta = (amount: number) => { - delta += amount; - updateCountScheduler.schedule(); - }; - const subscribeFn = (id: string, provider: vscode.TestProvider) => { try { const hierarchy = method!(provider); @@ -145,10 +132,10 @@ export class ExtHostTesting implements ExtHostTestingShape { return; } - updateDelta(1); + collection.pushDiff([TestDiffOpType.DeltaDiscoverComplete, 1]); disposable.add(hierarchy); collection.addRoot(hierarchy.root, id); - Promise.resolve(hierarchy.discoveredInitialTests).then(() => updateDelta(-1)); + Promise.resolve(hierarchy.discoveredInitialTests).then(() => collection.pushDiff([TestDiffOpType.DeltaDiscoverComplete, -1])); hierarchy.onDidChangeTest(e => collection.onItemChange(e, id)); } catch (e) { console.error(e); @@ -161,6 +148,10 @@ export class ExtHostTesting implements ExtHostTestingShape { subscribeFn(id, provider); } + // note: we don't increment the root count initially -- this is done by the + // main thread, incrementing once per extension host. We just push the + // diff to signal that roots have been discovered. + collection.pushDiff([TestDiffOpType.DeltaRootsComplete, -1]); this.testSubscriptions.set(subscriptionKey, { store: disposable, collection, subscribeFn }); } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 378954a685bf..ba868d714fcf 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2315,9 +2315,6 @@ export class FunctionBreakpoint extends Breakpoint { constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string) { super(enabled, condition, hitCondition, logMessage); - if (!functionName) { - throw illegalArgument('functionName'); - } this.functionName = functionName; } } diff --git a/src/vs/workbench/api/node/extHostTunnelService.ts b/src/vs/workbench/api/node/extHostTunnelService.ts index 8075d654f89e..41108eee5d0b 100644 --- a/src/vs/workbench/api/node/extHostTunnelService.ts +++ b/src/vs/workbench/api/node/extHostTunnelService.ts @@ -15,13 +15,13 @@ import * as fs from 'fs'; import * as pfs from 'vs/base/node/pfs'; import { isLinux } from 'vs/base/common/platform'; import { IExtHostTunnelService, TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; -import { asPromise } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; import { TunnelOptions, TunnelCreationOptions } from 'vs/platform/remote/common/tunnel'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { promisify } from 'util'; import { MovingAverage } from 'vs/base/common/numbers'; import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { ILogService } from 'vs/platform/log/common/log'; class ExtensionTunnel implements vscode.Tunnel { private _onDispose: Emitter = new Emitter(); @@ -142,7 +142,8 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, - @IExtHostInitDataService initData: IExtHostInitDataService + @IExtHostInitDataService initData: IExtHostInitDataService, + @ILogService private readonly logService: ILogService ) { super(); this._proxy = extHostRpc.getProxy(MainContext.MainThreadTunnelService); @@ -234,16 +235,19 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise { if (this._forwardPortProvider) { - const providedPort = this._forwardPortProvider(tunnelOptions, tunnelCreationOptions); - if (providedPort !== undefined) { - return asPromise(() => providedPort).then(tunnel => { + try { + const providedPort = this._forwardPortProvider(tunnelOptions, tunnelCreationOptions); + if (providedPort !== undefined) { + const tunnel = await providedPort; if (!this._extensionTunnels.has(tunnelOptions.remoteAddress.host)) { this._extensionTunnels.set(tunnelOptions.remoteAddress.host, new Map()); } const disposeListener = this._register(tunnel.onDidDispose(() => this._proxy.$closeTunnel(tunnel.remoteAddress))); this._extensionTunnels.get(tunnelOptions.remoteAddress.host)!.set(tunnelOptions.remoteAddress.port, { tunnel, disposeListener }); - return Promise.resolve(TunnelDto.fromApiTunnel(tunnel)); - }); + return TunnelDto.fromApiTunnel(tunnel); + } + } catch (e) { + this.logService.trace('$forwardPort: tunnel provider error'); } } return undefined; diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 67798d8844b5..886c2ff68ba7 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -8,7 +8,7 @@ import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IAction, Action, SubmenuAction, Separator, toAction } from 'vs/base/common/actions'; +import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform'; @@ -709,7 +709,14 @@ export class CustomMenubarControl extends MenubarControl { const webNavigationActions: IAction[] = []; const href = this.environmentService.options?.homeIndicator?.href; if (href) { - webNavigationActions.push(toAction({ id: 'goHome', label: nls.localize('goHome', "Go Home"), run: () => window.location.href = href })); + webNavigationActions.push(new Action('goHome', nls.localize('goHome', "Go Home"), undefined, true, + async (event?: MouseEvent) => { + if ((!isMacintosh && event?.ctrlKey) || (isMacintosh && event?.metaKey)) { + window.open(href, '_blank'); + } else { + window.location.href = href; + } + })); } const otherActions = this.getWebNavigationMenuItemActions().map(action => { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 1a0f3feffc2c..79ec52099801 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -9,7 +9,7 @@ import { Action } from 'vs/base/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite'; -import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature0, IInstantiationService, BrandedService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -24,6 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { PaneComposite } from 'vs/workbench/browser/panecomposite'; import { Event } from 'vs/base/common/event'; import { FilterViewPaneContainer } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { Action2 } from 'vs/platform/actions/common/actions'; export abstract class Viewlet extends PaneComposite implements IViewlet { @@ -137,7 +138,7 @@ export class ShowViewletAction extends Action { async run(): Promise { // Pass focus to viewlet if not open or focused - if (this.otherViewletShowing() || !this.sidebarHasFocus()) { + if (otherViewletShowing(this.viewletService, this.viewletId) || !sidebarHasFocus(this.viewletService, this.layoutService)) { await this.viewletService.openViewlet(this.viewletId, true); return; } @@ -145,18 +146,42 @@ export class ShowViewletAction extends Action { // Otherwise pass focus to editor group this.editorGroupService.activeGroup.focus(); } +} - private otherViewletShowing(): boolean { - const activeViewlet = this.viewletService.getActiveViewlet(); +/** + * A reusable action to show a viewlet with a specific id. + */ +export abstract class ShowViewletAction2 extends Action2 { + /** + * Gets the viewlet ID to show. + */ + protected abstract viewletId(): string; - return !activeViewlet || activeViewlet.getId() !== this.viewletId; - } + public async run(accessor: ServicesAccessor): Promise { + const viewletService = accessor.get(IViewletService); + const editorGroupService = accessor.get(IEditorGroupsService); + const layoutService = accessor.get(IWorkbenchLayoutService); - private sidebarHasFocus(): boolean { - const activeViewlet = this.viewletService.getActiveViewlet(); - const activeElement = document.activeElement; - const sidebarPart = this.layoutService.getContainer(Parts.SIDEBAR_PART); + // Pass focus to viewlet if not open or focused + if (otherViewletShowing(viewletService, this.viewletId()) || !sidebarHasFocus(viewletService, layoutService)) { + await viewletService.openViewlet(this.viewletId(), true); + return; + } - return !!(activeViewlet && activeElement && sidebarPart && DOM.isAncestor(activeElement, sidebarPart)); + // Otherwise pass focus to editor group + editorGroupService.activeGroup.focus(); } } + +const otherViewletShowing = (viewletService: IViewletService, viewletId: string): boolean => { + const activeViewlet = viewletService.getActiveViewlet(); + return !activeViewlet || activeViewlet.getId() !== viewletId; +}; + +const sidebarHasFocus = (viewletService: IViewletService, layoutService: IWorkbenchLayoutService): boolean => { + const activeViewlet = viewletService.getActiveViewlet(); + const activeElement = document.activeElement; + const sidebarPart = layoutService.getContainer(Parts.SIDEBAR_PART); + + return !!(activeViewlet && activeElement && sidebarPart && DOM.isAncestor(activeElement, sidebarPart)); +}; diff --git a/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts index 2345ab0030fb..d27f59b3627a 100644 --- a/src/vs/workbench/common/composite.ts +++ b/src/vs/workbench/common/composite.ts @@ -19,7 +19,7 @@ export interface IComposite { readonly onDidBlur: Event; /** - * Returns true if the composite has focus. + * Returns true if the composite has focus. */ hasFocus(): boolean; diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 70f2eb64d044..7bbafb8025e8 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -29,9 +29,6 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { CancellationToken } from 'vs/base/common/cancellation'; -export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test'; -export const testViewIcon = registerIcon('test-view-icon', Codicon.beaker, localize('testViewIcon', 'View icon of the test view.')); - export const defaultViewIcon = registerIcon('default-view-icon', Codicon.window, localize('defaultViewIcon', 'Default view icon.')); export namespace Extensions { diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts index e9dddb2a289c..7d1348b25f86 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts @@ -409,14 +409,14 @@ export class CategoryElementRenderer implements ITreeRenderer this._handleConfigFile(languageIdentifier, configFileLocation)); } @@ -254,18 +268,82 @@ export class LanguageConfigurationFileHandler { return result; } - // private _mapCharacterPairs(pairs: Array): IAutoClosingPairConditional[] { - // return pairs.map(pair => { - // if (Array.isArray(pair)) { - // return { open: pair[0], close: pair[1] }; - // } - // return pair; - // }); - // } + private _extractValidOnEnterRules(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): OnEnterRule[] | null { + const source = configuration.onEnterRules; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules\` to be an array.`); + return null; + } + + let result: OnEnterRule[] | null = null; + for (let i = 0, len = source.length; i < len; i++) { + const onEnterRule = source[i]; + if (!types.isObject(onEnterRule)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules[${i}]\` to be an object.`); + continue; + } + if (!types.isObject(onEnterRule.action)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules[${i}].action\` to be an object.`); + continue; + } + let indentAction: IndentAction; + if (onEnterRule.action.indent === 'none') { + indentAction = IndentAction.None; + } else if (onEnterRule.action.indent === 'indent') { + indentAction = IndentAction.Indent; + } else if (onEnterRule.action.indent === 'indentOutdent') { + indentAction = IndentAction.IndentOutdent; + } else if (onEnterRule.action.indent === 'outdent') { + indentAction = IndentAction.Outdent; + } else { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules[${i}].action.indent\` to be 'none', 'indent', 'indentOutdent' or 'outdent'.`); + continue; + } + const action: EnterAction = { indentAction }; + if (onEnterRule.action.appendText) { + if (typeof onEnterRule.action.appendText === 'string') { + action.appendText = onEnterRule.action.appendText; + } else { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules[${i}].action.appendText\` to be undefined or a string.`); + } + } + if (onEnterRule.action.removeText) { + if (typeof onEnterRule.action.removeText === 'number') { + action.removeText = onEnterRule.action.removeText; + } else { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`onEnterRules[${i}].action.removeText\` to be undefined or a number.`); + } + } + const beforeText = this._parseRegex(languageIdentifier, `onEnterRules[${i}].beforeText`, onEnterRule.beforeText); + if (!beforeText) { + continue; + } + const resultingOnEnterRule: OnEnterRule = { beforeText, action }; + if (onEnterRule.afterText) { + const afterText = this._parseRegex(languageIdentifier, `onEnterRules[${i}].afterText`, onEnterRule.afterText); + if (afterText) { + resultingOnEnterRule.afterText = afterText; + } + } + if (onEnterRule.previousLineText) { + const previousLineText = this._parseRegex(languageIdentifier, `onEnterRules[${i}].previousLineText`, onEnterRule.previousLineText); + if (previousLineText) { + resultingOnEnterRule.previousLineText = previousLineText; + } + } + result = result || []; + result.push(resultingOnEnterRule); + } + + return result; + } private _handleConfig(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): void { - let richEditConfig: LanguageConfiguration = {}; + const richEditConfig: LanguageConfiguration = {}; const comments = this._extractValidCommentRule(languageIdentifier, configuration); if (comments) { @@ -293,25 +371,21 @@ export class LanguageConfigurationFileHandler { } if (configuration.wordPattern) { - try { - let wordPattern = this._parseRegex(configuration.wordPattern); - if (wordPattern) { - richEditConfig.wordPattern = wordPattern; - } - } catch (error) { - // Malformed regexes are ignored + const wordPattern = this._parseRegex(languageIdentifier, `wordPattern`, configuration.wordPattern); + if (wordPattern) { + richEditConfig.wordPattern = wordPattern; } } if (configuration.indentationRules) { - let indentationRules = this._mapIndentationRules(configuration.indentationRules); + const indentationRules = this._mapIndentationRules(languageIdentifier, configuration.indentationRules); if (indentationRules) { richEditConfig.indentationRules = indentationRules; } } if (configuration.folding) { - let markers = configuration.folding.markers; + const markers = configuration.folding.markers; richEditConfig.folding = { offSide: configuration.folding.offSide, @@ -319,44 +393,66 @@ export class LanguageConfigurationFileHandler { }; } + const onEnterRules = this._extractValidOnEnterRules(languageIdentifier, configuration); + if (onEnterRules) { + richEditConfig.onEnterRules = onEnterRules; + } + LanguageConfigurationRegistry.register(languageIdentifier, richEditConfig); } - private _parseRegex(value: string | IRegExp) { + private _parseRegex(languageIdentifier: LanguageIdentifier, confPath: string, value: string | IRegExp) { if (typeof value === 'string') { - return new RegExp(value, ''); - } else if (typeof value === 'object') { - return new RegExp(value.pattern, value.flags); + try { + return new RegExp(value, ''); + } catch (err) { + console.warn(`[${languageIdentifier.language}]: Invalid regular expression in \`${confPath}\`: `, err); + return null; + } } - + if (types.isObject(value)) { + if (typeof value.pattern !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`${confPath}.pattern\` to be a string.`); + return null; + } + if (typeof value.flags !== 'undefined' && typeof value.flags !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`${confPath}.flags\` to be a string.`); + return null; + } + try { + return new RegExp(value.pattern, value.flags); + } catch (err) { + console.warn(`[${languageIdentifier.language}]: Invalid regular expression in \`${confPath}\`: `, err); + return null; + } + } + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`${confPath}\` to be a string or an object.`); return null; } - private _mapIndentationRules(indentationRules: IIndentationRules): IndentationRule | null { - try { - let increaseIndentPattern = this._parseRegex(indentationRules.increaseIndentPattern); - let decreaseIndentPattern = this._parseRegex(indentationRules.decreaseIndentPattern); - - if (increaseIndentPattern && decreaseIndentPattern) { - let result: IndentationRule = { - increaseIndentPattern: increaseIndentPattern, - decreaseIndentPattern: decreaseIndentPattern - }; - - if (indentationRules.indentNextLinePattern) { - result.indentNextLinePattern = this._parseRegex(indentationRules.indentNextLinePattern); - } - if (indentationRules.unIndentedLinePattern) { - result.unIndentedLinePattern = this._parseRegex(indentationRules.unIndentedLinePattern); - } - - return result; - } - } catch (error) { - // Malformed regexes are ignored + private _mapIndentationRules(languageIdentifier: LanguageIdentifier, indentationRules: IIndentationRules): IndentationRule | null { + const increaseIndentPattern = this._parseRegex(languageIdentifier, `indentationRules.increaseIndentPattern`, indentationRules.increaseIndentPattern); + if (!increaseIndentPattern) { + return null; + } + const decreaseIndentPattern = this._parseRegex(languageIdentifier, `indentationRules.decreaseIndentPattern`, indentationRules.decreaseIndentPattern); + if (!decreaseIndentPattern) { + return null; } - return null; + const result: IndentationRule = { + increaseIndentPattern: increaseIndentPattern, + decreaseIndentPattern: decreaseIndentPattern + }; + + if (indentationRules.indentNextLinePattern) { + result.indentNextLinePattern = this._parseRegex(languageIdentifier, `indentationRules.indentNextLinePattern`, indentationRules.indentNextLinePattern); + } + if (indentationRules.unIndentedLinePattern) { + result.unIndentedLinePattern = this._parseRegex(languageIdentifier, `indentationRules.unIndentedLinePattern`, indentationRules.unIndentedLinePattern); + } + + return result; } } @@ -601,6 +697,100 @@ const schema: IJSONSchema = { } } } + }, + onEnterRules: { + type: 'array', + items: { + type: 'object', + description: nls.localize('schema.onEnterRules', 'The language\'s rules to be evaluated when pressing Enter.'), + required: ['beforeText', 'action'], + properties: { + beforeText: { + type: ['string', 'object'], + description: nls.localize('schema.onEnterRules.beforeText', 'This rule will only execute if the text before the cursor matches this regular expression.'), + properties: { + pattern: { + type: 'string', + description: nls.localize('schema.onEnterRules.beforeText.pattern', 'The RegExp pattern for beforeText.'), + default: '', + }, + flags: { + type: 'string', + description: nls.localize('schema.onEnterRules.beforeText.flags', 'The RegExp flags for beforeText.'), + default: '', + pattern: '^([gimuy]+)$', + patternErrorMessage: nls.localize('schema.onEnterRules.beforeText.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.') + } + } + }, + afterText: { + type: ['string', 'object'], + description: nls.localize('schema.onEnterRules.afterText', 'This rule will only execute if the text after the cursor matches this regular expression.'), + properties: { + pattern: { + type: 'string', + description: nls.localize('schema.onEnterRules.afterText.pattern', 'The RegExp pattern for afterText.'), + default: '', + }, + flags: { + type: 'string', + description: nls.localize('schema.onEnterRules.afterText.flags', 'The RegExp flags for afterText.'), + default: '', + pattern: '^([gimuy]+)$', + patternErrorMessage: nls.localize('schema.onEnterRules.afterText.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.') + } + } + }, + previousLineText: { + type: ['string', 'object'], + description: nls.localize('schema.onEnterRules.previousLineText', 'This rule will only execute if the text above the line matches this regular expression.'), + properties: { + pattern: { + type: 'string', + description: nls.localize('schema.onEnterRules.previousLineText.pattern', 'The RegExp pattern for previousLineText.'), + default: '', + }, + flags: { + type: 'string', + description: nls.localize('schema.onEnterRules.previousLineText.flags', 'The RegExp flags for previousLineText.'), + default: '', + pattern: '^([gimuy]+)$', + patternErrorMessage: nls.localize('schema.onEnterRules.previousLineText.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.') + } + } + }, + action: { + type: ['string', 'object'], + description: nls.localize('schema.onEnterRules.action', 'The action to execute.'), + required: ['indent'], + default: { 'indent': 'indent' }, + properties: { + indent: { + type: 'string', + description: nls.localize('schema.onEnterRules.action.indent', "Describe what to do with the indentation"), + default: 'indent', + enum: ['none', 'indent', 'indentOutdent', 'outdent'], + markdownEnumDescriptions: [ + nls.localize('schema.onEnterRules.action.indent.none', "Insert new line and copy the previous line's indentation."), + nls.localize('schema.onEnterRules.action.indent.indent', "Insert new line and indent once (relative to the previous line's indentation)."), + nls.localize('schema.onEnterRules.action.indent.indentOutdent', "Insert two new lines:\n - the first one indented which will hold the cursor\n - the second one at the same indentation level"), + nls.localize('schema.onEnterRules.action.indent.outdent', "Insert new line and outdent once (relative to the previous line's indentation).") + ] + }, + appendText: { + type: 'string', + description: nls.localize('schema.onEnterRules.action.appendText', 'Describes text to be appended after the new line and after the indentation.'), + default: '', + }, + removeText: { + type: 'number', + description: nls.localize('schema.onEnterRules.action.removeText', 'Describes the number of characters to remove from the new line\'s indentation.'), + default: 0, + } + } + } + } + } } } diff --git a/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts b/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts index 2b6f530c48b2..3c920d1366f8 100644 --- a/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts +++ b/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts @@ -115,7 +115,8 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider { const pick = await provider.pick(); if (pick) { - await configManager.selectConfiguration(pick.launch, pick.config.name, pick.config, { type: pick.config.type }); + // Use the type of the provider, not of the config since config sometimes have subtypes (for example "node-terminal") + await configManager.selectConfiguration(pick.launch, pick.config.name, pick.config, { type: provider.type }); this.debugService.startDebugging(pick.launch, pick.config); } } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 8b630a9249e8..233fcee0fd81 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -478,7 +478,7 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { || !this.extension.local || this.extension.state !== ExtensionState.Installed || this.extension.type !== ExtensionType.User - || this.extension.enablementState === EnablementState.DisabledByEnvironemt + || this.extension.enablementState === EnablementState.DisabledByEnvironment ) { return false; } diff --git a/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts b/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts index 473b4f7aedc4..fae7cc0faec5 100644 --- a/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts +++ b/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts @@ -67,7 +67,7 @@ export class ExternalUriOpenerService extends Disposable implements IExternalUri return { dispose: remove }; } - async openExternal(href: string, ctx: { sourceUri: URI }, token: CancellationToken): Promise { + async openExternal(href: string, ctx: { sourceUri: URI, preferredOpenerId?: string }, token: CancellationToken): Promise { const targetUri = typeof href === 'string' ? URI.parse(href) : href; @@ -77,11 +77,24 @@ export class ExternalUriOpenerService extends Disposable implements IExternalUri return false; } - // First check to see if we have a configured opener + // First see if we have a preferredOpener + if (ctx.preferredOpenerId) { + if (ctx.preferredOpenerId === defaultExternalUriOpenerId) { + return false; + } + + const preferredOpener = allOpeners.get(ctx.preferredOpenerId); + if (preferredOpener) { + // Skip the `canOpen` check here since the opener was specifically requested. + return preferredOpener.openExternalUri(targetUri, ctx, token); + } + } + + // Check to see if we have a configured opener const configuredOpener = this.getConfiguredOpenerForUri(allOpeners, targetUri); if (configuredOpener) { // Skip the `canOpen` check here since the opener was specifically requested. - return configuredOpener === 'default' ? false : configuredOpener.openExternalUri(targetUri, ctx, token); + return configuredOpener === defaultExternalUriOpenerId ? false : configuredOpener.openExternalUri(targetUri, ctx, token); } // Then check to see if there is a valid opener diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 60fd454b0866..3f2855d2f181 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -232,7 +232,8 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri this._register(this.editorService.overrideOpenEditor({ getEditorOverrides: (resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined) => { - const currentEditorForResource = group && this.editorService.findEditors(resource, group); + const currentEditorsForResource = group && this.editorService.findEditors(resource, group); + const currentEditorForResource = currentEditorsForResource && currentEditorsForResource.length ? currentEditorsForResource[0] : undefined; const associatedEditors = distinct([ ...this.getUserAssociatedNotebookEditors(resource), @@ -336,7 +337,24 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri } if (originalInput instanceof NotebookEditorInput) { - return undefined; + if (originalInput.viewType === id) { + return undefined; + } else { + return { + override: (async () => { + const notebookInput = NotebookEditorInput.create(this.instantiationService, originalInput.resource, originalInput.getName(), id); + await group.replaceEditors([{ + editor: originalInput, + replacement: notebookInput + }]); + if (group.activeEditorPane?.input === notebookInput) { + return group.activeEditorPane; + } else { + return undefined; + } + })() + }; + } } if (originalInput instanceof NotebookDiffEditorInput) { 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 bb7cbb456f38..ce56dffa3934 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -427,7 +427,7 @@ var requirejs = (function() { if (matchesScheme(link, Schemas.http) || matchesScheme(link, Schemas.https) || matchesScheme(link, Schemas.mailto) || matchesScheme(link, Schemas.command)) { - this.openerService.open(link, { fromUserGesture: true }); + this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true }); } })); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index cbd9e56698c4..4ecb45f196b8 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -253,7 +253,6 @@ export class OutlinePane extends ViewPane { // update: refresh tree this._domNode.classList.remove('message'); tree.updateChildren(); - tree.expandAll(); } }; updateTree(); diff --git a/src/vs/workbench/contrib/remote/common/tunnelFactory.ts b/src/vs/workbench/contrib/remote/common/tunnelFactory.ts index 20ee629634f0..36524ca4b7c8 100644 --- a/src/vs/workbench/contrib/remote/common/tunnelFactory.ts +++ b/src/vs/workbench/contrib/remote/common/tunnelFactory.ts @@ -3,44 +3,59 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITunnelService, TunnelOptions, RemoteTunnel, TunnelCreationOptions } from 'vs/platform/remote/common/tunnel'; +import { ITunnelService, TunnelOptions, RemoteTunnel, TunnelCreationOptions, ITunnel } from 'vs/platform/remote/common/tunnel'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { ILogService } from 'vs/platform/log/common/log'; export class TunnelFactoryContribution extends Disposable implements IWorkbenchContribution { constructor( @ITunnelService tunnelService: ITunnelService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IOpenerService openerService: IOpenerService, - @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, + @ILogService logService: ILogService ) { super(); const tunnelFactory = environmentService.options?.tunnelProvider?.tunnelFactory; if (tunnelFactory) { this._register(tunnelService.setTunnelProvider({ - forwardPort: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise | undefined => { - const tunnelPromise = tunnelFactory(tunnelOptions, tunnelCreationOptions); - if (!tunnelPromise) { - return undefined; + forwardPort: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise | undefined => { + let tunnelPromise: Promise | undefined; + try { + tunnelPromise = tunnelFactory(tunnelOptions, tunnelCreationOptions); + } catch (e) { + logService.trace('tunnelFactory: tunnel provider error'); } - return new Promise(resolve => { - tunnelPromise.then(async (tunnel) => { - const localAddress = tunnel.localAddress.startsWith('http') ? tunnel.localAddress : `http://${tunnel.localAddress}`; - const remoteTunnel: RemoteTunnel = { - tunnelRemotePort: tunnel.remoteAddress.port, - tunnelRemoteHost: tunnel.remoteAddress.host, - // The tunnel factory may give us an inaccessible local address. - // To make sure this doesn't happen, resolve the uri immediately. - localAddress: (await openerService.resolveExternalUri(URI.parse(localAddress))).resolved.toString(), - public: !!tunnel.public, - dispose: async () => { await tunnel.dispose; } - }; - resolve(remoteTunnel); - }); + + return new Promise(async (resolve) => { + if (!tunnelPromise) { + resolve(undefined); + return; + } + let tunnel: ITunnel; + try { + tunnel = await tunnelPromise; + } catch (e) { + logService.trace('tunnelFactory: tunnel provider promise error'); + resolve(undefined); + return; + } + const localAddress = tunnel.localAddress.startsWith('http') ? tunnel.localAddress : `http://${tunnel.localAddress}`; + const remoteTunnel: RemoteTunnel = { + tunnelRemotePort: tunnel.remoteAddress.port, + tunnelRemoteHost: tunnel.remoteAddress.host, + // The tunnel factory may give us an inaccessible local address. + // To make sure this doesn't happen, resolve the uri immediately. + localAddress: (await openerService.resolveExternalUri(URI.parse(localAddress))).resolved.toString(), + public: !!tunnel.public, + dispose: async () => { await tunnel.dispose(); } + }; + resolve(remoteTunnel); }); } }, environmentService.options?.tunnelProvider?.features ?? { elevation: false, public: false })); diff --git a/src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts b/src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts index e55526fa2303..3c7d555dada3 100644 --- a/src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts +++ b/src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts @@ -239,7 +239,7 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 6a4381cb7046..bec90fc81c9b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -997,6 +997,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { case 'pwsh.exe': return WindowsShellType.PowerShell; case 'bash.exe': + case 'git-cmd.exe': return WindowsShellType.GitBash; case 'wsl.exe': case 'ubuntu.exe': diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts index 38abc19ad740..106e3315f763 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts @@ -15,7 +15,7 @@ import { HierarchicalElement, HierarchicalFolder } from 'vs/workbench/contrib/te import { locationsEqual, TestLocationStore } from 'vs/workbench/contrib/testing/browser/explorerProjections/locationStore'; import { NodeChangeList, NodeRenderDirective, NodeRenderFn, peersHaveChildren } from 'vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper'; import { InternalTestItem, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; /** * Projection that lists tests in their traditional tree view. @@ -46,7 +46,7 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes this._register(listener.onFolderChange(this.applyFolderChange, this)); for (const [folder, collection] of listener.workspaceFolderCollections) { - const queue = [collection.rootNodes]; + const queue = [collection.rootIds]; while (queue.length) { for (const id of queue.pop()!) { const node = collection.getNodeById(id)!; diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts index 60cba9a76a9f..b263ca46c160 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts @@ -10,7 +10,7 @@ import { HierarchicalByLocationProjection as HierarchicalByLocationProjection } import { HierarchicalElement, HierarchicalFolder } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalNodes'; import { NodeRenderDirective } from 'vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper'; import { InternalTestItem } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; /** * Type of test element in the list. diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts index cbb7eeb351e8..b60493f3b28f 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts @@ -95,7 +95,7 @@ export class NodeChangeList pruneNodesNotInTree(this.changedParents, tree); pruneNodesNotInTree(this.updatedNodes, tree); - const diffDeep = this.isFirstApply ? Infinity : 0; + const diffDepth = this.isFirstApply ? Infinity : 0; this.isFirstApply = false; for (let parent of this.changedParents) { @@ -107,7 +107,7 @@ export class NodeChangeList tree.setChildren( parent, this.renderNodeList(renderNode, parent === null ? roots() : parent.children), - { diffIdentityProvider: testIdentityProvider, diffDeep }, + { diffIdentityProvider: testIdentityProvider, diffDepth }, ); } } diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByLocation.ts index 8f2a5f74e2d0..b56bdad656a4 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByLocation.ts @@ -17,8 +17,8 @@ import { locationsEqual, TestLocationStore } from 'vs/workbench/contrib/testing/ import { isRunningState, NodeChangeList, NodeRenderDirective, NodeRenderFn, peersHaveChildren } from 'vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper'; import { StateElement } from 'vs/workbench/contrib/testing/browser/explorerProjections/stateNodes'; import { statesInOrder } from 'vs/workbench/contrib/testing/browser/testExplorerTree'; -import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; interface IStatusTestItem extends IncrementalTestCollectionItem { treeElements: Map; @@ -109,14 +109,7 @@ export class StateByLocationProjection extends AbstractIncrementalTestCollection const firstDiff: TestsDiff = []; for (const [, collection] of listener.workspaceFolderCollections) { - const queue = [collection.rootNodes]; - while (queue.length) { - for (const id of queue.pop()!) { - const node = collection.getNodeById(id)!; - firstDiff.push([TestDiffOpType.Add, node]); - queue.push(node.children); - } - } + firstDiff.push(...collection.getReviverDiff()); } this.apply(firstDiff); diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByName.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByName.ts index 26e5d99e005c..cd08be93fab1 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByName.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/stateByName.ts @@ -17,8 +17,8 @@ import { ListElementType } from 'vs/workbench/contrib/testing/browser/explorerPr import { locationsEqual, TestLocationStore } from 'vs/workbench/contrib/testing/browser/explorerProjections/locationStore'; import { isRunningState, NodeChangeList, NodeRenderFn } from 'vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper'; import { StateElement } from 'vs/workbench/contrib/testing/browser/explorerProjections/stateNodes'; -import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; class ListTestStateElement implements ITestTreeElement { public computedState = this.test.item.state.runState; @@ -108,14 +108,7 @@ export class StateByNameProjection extends AbstractIncrementalTestCollection(); +const category = localize('testing.category', 'Test'); - public onDidChangeVisibility = this.visChangeEmitter.event; - public isVisible = true; - - protected _setVisible(isVisible: boolean) { - if (isVisible !== this.isVisible) { - this.isVisible = isVisible; - this.visChangeEmitter.fire(isVisible); - } - } +const enum ActionOrder { + Run = 10, + Debug, + Refresh, + Collapse, } -export const filterVisibleActions = (actions: ReadonlyArray) => - actions.filter(a => !(a instanceof FilterableAction) || a.isVisible); - export class DebugAction extends Action { constructor( private readonly tests: Iterable, @@ -44,7 +41,7 @@ export class DebugAction extends Action { @ITestService private readonly testService: ITestService ) { super( - 'action.run', + 'testing.run', localize('debug test', 'Debug Test'), 'test-action ' + ThemeIcon.asClassName(icons.testingDebugIcon), /* enabled= */ !isRunning @@ -69,7 +66,7 @@ export class RunAction extends Action { @ITestService private readonly testService: ITestService ) { super( - 'action.run', + 'testing.run', localize('run test', 'Run Test'), 'test-action ' + ThemeIcon.asClassName(icons.testingRunIcon), /* enabled= */ !isRunning, @@ -88,21 +85,14 @@ export class RunAction extends Action { } abstract class RunOrDebugAction extends ViewAction { - constructor(id: string, title: string, icon: ThemeIcon) { + constructor(id: string, title: string, icon: ThemeIcon, private readonly debug: boolean) { super({ id, title, icon, viewId: Testing.ExplorerViewId, - menu: { - id: MenuId.ViewTitle, - order: 10, - group: 'navigation', - when: ContextKeyAndExpr.create([ - ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId), - ContextKeyEqualsExpr.create(TestingContextKeys.isRunning.serialize(), false), - ]) - } + f1: true, + category, }); } @@ -110,15 +100,15 @@ abstract class RunOrDebugAction extends ViewAction { * @override */ public runInView(accessor: ServicesAccessor, view: TestingExplorerView): Promise { - const tests = this.getActionableTests(accessor.get(ITestingCollectionService), view.viewModel); + const tests = this.getActionableTests(accessor.get(IWorkspaceTestCollectionService), view.viewModel); if (!tests.length) { return Promise.resolve(EMPTY_TEST_RESULT); } - return accessor.get(ITestService).runTests({ tests, debug: this.debug() }); + return accessor.get(ITestService).runTests({ tests, debug: this.debug }); } - private getActionableTests(testCollection: ITestingCollectionService, viewModel: TestingExplorerViewModel) { + private getActionableTests(testCollection: IWorkspaceTestCollectionService, viewModel: TestingExplorerViewModel) { const selected = viewModel.getSelectedTests(); const tests: TestIdWithProvider[] = []; if (!selected.length) { @@ -140,7 +130,6 @@ abstract class RunOrDebugAction extends ViewAction { return tests; } - protected abstract debug(): boolean; protected abstract filter(item: InternalTestItem): boolean; } @@ -148,19 +137,13 @@ export class RunSelectedAction extends RunOrDebugAction { constructor( ) { super( - 'action.runSelected', + 'testing.runSelected', localize('runSelectedTests', 'Run Selected Tests'), icons.testingRunIcon, + false, ); } - /** - * @override - */ - public debug() { - return false; - } - /** * @override */ @@ -172,19 +155,13 @@ export class RunSelectedAction extends RunOrDebugAction { export class DebugSelectedAction extends RunOrDebugAction { constructor() { super( - 'action.debugSelected', + 'testing.debugSelected', localize('debugSelectedTests', 'Debug Selected Tests'), icons.testingDebugIcon, + true, ); } - /** - * @override - */ - public debug() { - return true; - } - /** * @override */ @@ -193,6 +170,81 @@ export class DebugSelectedAction extends RunOrDebugAction { } } +abstract class RunOrDebugAllAllAction extends Action2 { + constructor(id: string, title: string, icon: ThemeIcon, private readonly debug: boolean, private noTestsFoundError: string) { + super({ + id, + title, + icon, + f1: true, + category, + menu: { + id: MenuId.ViewTitle, + order: debug ? ActionOrder.Debug : ActionOrder.Run, + group: 'navigation', + when: ContextKeyAndExpr.create([ + ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId), + ContextKeyEqualsExpr.create(TestingContextKeys.isRunning.serialize(), false), + ]) + } + }); + } + + public async run(accessor: ServicesAccessor) { + const testService = accessor.get(ITestService); + const workspace = accessor.get(IWorkspaceContextService); + const notifications = accessor.get(INotificationService); + + const tests: TestIdWithProvider[] = []; + await Promise.all(workspace.getWorkspace().folders.map(async (folder) => { + const handle = testService.subscribeToDiffs(ExtHostTestingResource.Workspace, folder.uri); + try { + await waitForAllRoots(handle.collection); + + for (const root of handle.collection.rootIds) { + const node = handle.collection.getNodeById(root); + if (node && (this.debug ? node.item.debuggable : node.item.runnable)) { + tests.push({ testId: node.id, providerId: node.providerId }); + } + } + } finally { + handle.dispose(); + } + })); + + if (tests.length === 0) { + notifications.info(this.noTestsFoundError); + return; + } + + await testService.runTests({ tests, debug: this.debug }); + } +} + +export class RunAllAction extends RunOrDebugAllAllAction { + constructor() { + super( + 'testing.runAll', + localize('runAllTests', 'Run All Tests'), + icons.testingDebugIcon, + false, + localize('noTestProvider', 'No tests found in this workspace. You may need to install a test provider extension'), + ); + } +} + +export class DebugAllAction extends RunOrDebugAllAllAction { + constructor() { + super( + 'testing.debugAll', + localize('debugAllTests', 'Debug All Tests'), + icons.testingDebugIcon, + true, + localize('noDebugTestProvider', 'No debuggable tests found in this workspace. You may need to install a test provider extension'), + ); + } +} + export class CancelTestRunAction extends Action2 { constructor() { super({ @@ -201,7 +253,7 @@ export class CancelTestRunAction extends Action2 { icon: icons.testingCancelIcon, menu: { id: MenuId.ViewTitle, - order: 10, + order: ActionOrder.Run, group: 'navigation', when: ContextKeyAndExpr.create([ ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId), @@ -323,14 +375,43 @@ export class TestingGroupByStatusAction extends ViewAction } } +export class CollapseAllAction extends ViewAction { + constructor() { + super({ + id: 'testing.collapseAll', + viewId: Testing.ExplorerViewId, + title: localize('testing.collapseAll', "Collapse All Tests"), + f1: false, + icon: Codicon.collapseAll, + menu: { + id: MenuId.ViewTitle, + order: ActionOrder.Collapse, + group: 'navigation', + when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) + } + }); + } + + /** + * @override + */ + public runInView(_accessor: ServicesAccessor, view: TestingExplorerView) { + view.viewModel.collapseAll(); + } +} + export class RefreshTestsAction extends Action2 { constructor() { super({ id: 'testing.refreshTests', title: localize('testing.refresh', "Refresh Tests"), + category, + f1: true, + icon: Codicon.refresh, menu: { id: MenuId.ViewTitle, - order: 0, + order: ActionOrder.Refresh, + group: 'navigation', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } }); @@ -343,3 +424,19 @@ export class RefreshTestsAction extends Action2 { accessor.get(ITestService).resubscribeToAllTests(); } } + +export class ShowTestView extends ShowViewletAction2 { + constructor() { + super({ + // matches old test action for back-compat + id: 'workbench.view.extension.test', + title: localize('showTestViewley', "Show Test"), + category: CATEGORIES.View.value, + f1: true, + }); + } + + protected viewletId() { + return Testing.ViewletId; + } +} diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index ad79e2a599ff..52aaeebc760d 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -25,7 +25,7 @@ import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browse import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; -import { ITestingCollectionService, TestingCollectionService } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { IWorkspaceTestCollectionService, WorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; @@ -35,15 +35,15 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import * as Action from './testExplorerActions'; registerSingleton(ITestService, TestService); -registerSingleton(ITestingCollectionService, TestingCollectionService); +registerSingleton(IWorkspaceTestCollectionService, WorkspaceTestCollectionService); const viewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ id: Testing.ViewletId, - name: localize('testing', "Testing"), + name: localize('test', "Test"), ctorDescriptor: new SyncDescriptor(TestingViewPaneContainer), icon: testingViewIcon, alwaysUseContainerInfo: true, - order: 5, + order: 6, hideIfEmpty: true, }, ViewContainerLocation.Sidebar); @@ -87,6 +87,10 @@ registerAction2(Action.DebugSelectedAction); registerAction2(Action.TestingGroupByLocationAction); registerAction2(Action.TestingGroupByStatusAction); registerAction2(Action.RefreshTestsAction); +registerAction2(Action.ShowTestView); +registerAction2(Action.CollapseAllAction); +registerAction2(Action.RunAllAction); +registerAction2(Action.DebugAllAction); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index e5927f74b1c4..dc0f2989071b 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -34,7 +34,6 @@ import { IProgressService } from 'vs/platform/progress/common/progress'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { ExtHostTestingResource } from 'vs/workbench/api/common/extHost.protocol'; import { TestRunState } from 'vs/workbench/api/common/extHostTypes'; import { IResourceLabel, IResourceLabelOptions, IResourceLabelProps, ResourceLabels } from 'vs/workbench/browser/labels'; import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; @@ -52,7 +51,7 @@ import { cmpPriority, isFailedState } from 'vs/workbench/contrib/testing/browser import { TestingExplorerFilter, TestingFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter'; import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { TestExplorerViewGrouping, TestExplorerViewMode } from 'vs/workbench/contrib/testing/common/constants'; -import { ITestingCollectionService, TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { IWorkspaceTestCollectionService, TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -68,7 +67,7 @@ export class TestingExplorerView extends ViewPane { constructor( options: IViewletViewOptions, - @ITestingCollectionService private readonly testCollection: ITestingCollectionService, + @IWorkspaceTestCollectionService private readonly testCollection: IWorkspaceTestCollectionService, @ITestService private readonly testService: ITestService, @IProgressService private readonly progress: IProgressService, @IContextMenuService contextMenuService: IContextMenuService, @@ -106,13 +105,6 @@ export class TestingExplorerView extends ViewPane { this.viewModel = this.instantiationService.createInstance(TestingExplorerViewModel, listContainer, this.onDidChangeBodyVisibility, this.currentSubscription, this.filterState); this._register(this.viewModel); - this.updateProgressIndicator(); - this._register(this.testService.onBusyStateChange(t => { - if (t.resource === ExtHostTestingResource.Workspace && t.busy !== (!!this.finishDiscovery)) { - this.updateProgressIndicator(); - } - })); - this.getProgressIndicator().show(true); this._register(this.onDidChangeBodyVisibility(visible => { @@ -135,8 +127,7 @@ export class TestingExplorerView extends ViewPane { this.filter.saveState(); } - private updateProgressIndicator() { - const busy = Iterable.some(this.testService.busyTestLocations, s => s.resource === ExtHostTestingResource.Workspace); + private updateProgressIndicator(busy: number) { if (!busy && this.finishDiscovery) { this.finishDiscovery(); this.finishDiscovery = undefined; @@ -156,7 +147,9 @@ export class TestingExplorerView extends ViewPane { } private createSubscription() { - return this.testCollection.subscribeToWorkspaceTests(); + const handle = this.testCollection.subscribeToWorkspaceTests(); + handle.subscription.onBusyProvidersChange(() => this.updateProgressIndicator(handle.subscription.busyProviders)); + return handle; } } @@ -309,6 +302,13 @@ export class TestingExplorerViewModel extends Disposable { this.tree.setSelection([item]); } + /** + * Collapse all items in the tree. + */ + public async collapseAll() { + this.tree.collapseAll(); + } + /** * Opens an editor for the item. If there is a failure associated with the * test item, it will be shown. diff --git a/src/vs/workbench/contrib/testing/common/constants.ts b/src/vs/workbench/contrib/testing/common/constants.ts index 1d896c6b3de7..e1317f872495 100644 --- a/src/vs/workbench/contrib/testing/common/constants.ts +++ b/src/vs/workbench/contrib/testing/common/constants.ts @@ -7,7 +7,8 @@ import { localize } from 'vs/nls'; import { TestRunState } from 'vs/workbench/api/common/extHostTypes'; export const enum Testing { - ViewletId = 'workbench.view.testing', + // marked as "extension" so that any existing test extensions are assigned to it. + ViewletId = 'workbench.view.extension.test', ExplorerViewId = 'workbench.view.testing', OutputPeekContributionId = 'editor.contrib.testingOutputPeek', } diff --git a/src/vs/workbench/contrib/testing/common/ownedTestCollection.ts b/src/vs/workbench/contrib/testing/common/ownedTestCollection.ts index 5d98a05714e9..0e34dff791e7 100644 --- a/src/vs/workbench/contrib/testing/common/ownedTestCollection.ts +++ b/src/vs/workbench/contrib/testing/common/ownedTestCollection.ts @@ -9,7 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { generateUuid } from 'vs/base/common/uuid'; import { TestItem } from 'vs/workbench/api/common/extHostTypeConverters'; import { RequiredTestItem, TestItem as ApiTestItem } from 'vs/workbench/api/common/extHostTypes'; -import { InternalTestItem, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { InternalTestItem, TestDiffOpType, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testCollection'; /** * @private @@ -103,6 +103,14 @@ export class SingleUseTestCollection implements IDisposable { return diff; } + /** + * Pushes a new diff entry onto the collected diff list. + */ + public pushDiff(diff: TestsDiffOp) { + this.diff.push(diff); + this.debounceSendDiff.schedule(); + } + public dispose() { for (const item of this.testItemToInternal.values()) { this.testIdToInternal.delete(item.id); diff --git a/src/vs/workbench/contrib/testing/common/testCollection.ts b/src/vs/workbench/contrib/testing/common/testCollection.ts index 87b0b8ffac20..cee17ec76680 100644 --- a/src/vs/workbench/contrib/testing/common/testCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testCollection.ts @@ -82,15 +82,23 @@ export interface InternalTestItem { } export const enum TestDiffOpType { + /** Adds a new test (with children) */ Add, + /** Shallow-updates an existing test */ Update, + /** Removes a test (and all its children) */ Remove, + /** Changes the number of providers running initial test discovery. */ + DeltaDiscoverComplete, + /** Changes the number of providers who are yet to publish their collection roots. */ + DeltaRootsComplete, } export type TestsDiffOp = | [op: TestDiffOpType.Add, item: InternalTestItem] | [op: TestDiffOpType.Update, item: InternalTestItem] - | [op: TestDiffOpType.Remove, itemId: string]; + | [op: TestDiffOpType.Remove, itemId: string] + | [op: TestDiffOpType.DeltaDiscoverComplete | TestDiffOpType.DeltaRootsComplete, amount: number]; /** * Utility function to get a unique string for a subscription to a resource, @@ -213,13 +221,38 @@ export abstract class AbstractIncrementalTestCollection('testService'); @@ -20,6 +20,54 @@ export interface MainTestController { export type TestDiffListener = (diff: TestsDiff) => void; +export interface IMainThreadTestCollection extends AbstractIncrementalTestCollection { + onPendingRootProvidersChange: Event; + onBusyProvidersChange: Event; + + /** + * Number of test root sources who are yet to report. + */ + pendingRootProviders: number; + + /** + * Number of providers working to discover tests. + */ + busyProviders: number; + + /** + * Root node IDs. + */ + rootIds: ReadonlySet; + + /** + * Gets a node in the collection by ID. + */ + getNodeById(id: string): IncrementalTestCollectionItem | undefined; + + /** + * Gets a diff that adds all items currently in the tree to a new collection, + * allowing it to fully hydrate. + */ + getReviverDiff(): TestsDiff; +} + +export const waitForAllRoots = (collection: IMainThreadTestCollection, timeout = 3000) => { + if (collection.pendingRootProviders === 0) { + return Promise.resolve(); + } + + let listener: IDisposable; + return new Promise(resolve => { + listener = collection.onPendingRootProvidersChange(count => { + if (count === 0) { + resolve(); + } + }); + + setTimeout(resolve, timeout); + }).finally(() => listener.dispose()); +}; + export interface ITestService { readonly _serviceBrand: undefined; readonly onShouldSubscribe: Event<{ resource: ExtHostTestingResource, uri: URI; }>; @@ -32,27 +80,23 @@ export interface ITestService { readonly onTestRunStarted: Event; readonly onTestRunCompleted: Event<{ req: RunTestsRequest, result: RunTestsResult; }>; - /** - * List of resources where tests are actively being discovered. - */ - readonly busyTestLocations: Iterable<{ resource: ExtHostTestingResource, uri: URI; }>; - - /** - * Fires when the busy state of a resource changes. - */ - readonly onBusyStateChange: Event<{ resource: ExtHostTestingResource, uri: URI, busy: boolean; }>; - registerTestController(id: string, controller: MainTestController): void; unregisterTestController(id: string): void; runTests(req: RunTestsRequest, token?: CancellationToken): Promise; cancelTestRun(req: RunTestsRequest): void; publishDiff(resource: ExtHostTestingResource, uri: URI, diff: TestsDiff): void; - subscribeToDiffs(resource: ExtHostTestingResource, uri: URI, acceptDiff: TestDiffListener): IDisposable; + subscribeToDiffs(resource: ExtHostTestingResource, uri: URI, acceptDiff?: TestDiffListener): { + collection: IMainThreadTestCollection; + dispose(): void; + }; /** - * Updates the number of test providers still discovering tests for the given resource. + * Updates the number of sources who provide test roots when subscription + * is requested. This is equal to the number of extension hosts, and used + * with `TestDiffOpType.DeltaRootsComplete` to signal when all roots + * are available. */ - updateDiscoveringCount(resource: ExtHostTestingResource, uri: URI, delta: number): void; + updateRootProviderCount(delta: number): void; /** * Looks up a test, by a request to extension hosts. diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 3f664481dff9..11a620c3eeb9 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { groupBy } from 'vs/base/common/arrays'; +import { disposableTimeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; -import { Iterable } from 'vs/base/common/iterator'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { isDefined } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; @@ -16,18 +16,21 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { ExtHostTestingResource } from 'vs/workbench/api/common/extHost.protocol'; import { AbstractIncrementalTestCollection, collectTestResults, EMPTY_TEST_RESULT, getTestSubscriptionKey, IncrementalTestCollectionItem, InternalTestItem, RunTestsRequest, RunTestsResult, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; -import { ITestService, MainTestController, TestDiffListener } from 'vs/workbench/contrib/testing/common/testService'; +import { IMainThreadTestCollection, ITestService, MainTestController, TestDiffListener } from 'vs/workbench/contrib/testing/common/testService'; type TestLocationIdent = { resource: ExtHostTestingResource, uri: URI }; +const workspaceUnsubscribeDelay = 30_000; +const documentUnsubscribeDelay = 5_000; + export class TestService extends Disposable implements ITestService { declare readonly _serviceBrand: undefined; private testControllers = new Map(); private readonly testSubscriptions = new Map; + disposeTimeout?: IDisposable, listeners: number; }>(); @@ -40,6 +43,7 @@ export class TestService extends Disposable implements ITestService { private readonly runStartedEmitter = new Emitter(); private readonly runCompletedEmitter = new Emitter<{ req: RunTestsRequest, result: RunTestsResult }>(); private readonly runningTests = new Map(); + private rootProviderCount = 0; public readonly onTestRunStarted = this.runStartedEmitter.event; public readonly onTestRunCompleted = this.runCompletedEmitter.event; @@ -101,15 +105,22 @@ export class TestService extends Disposable implements ITestService { /** * @inheritdoc */ - public get busyTestLocations() { - return Iterable.map(Iterable.filter(this.testSubscriptions.values(), s => s.stillDiscovering > 0), s => s.ident); + public async lookupTest(test: TestIdWithProvider) { + for (const { collection } of this.testSubscriptions.values()) { + const node = collection.getNodeById(test.testId); + if (node) { + return node; + } + } + + return this.testControllers.get(test.providerId)?.lookupTest(test); } /** * @inheritdoc */ - public async lookupTest(test: TestIdWithProvider) { - return this.testControllers.get(test.providerId)?.lookupTest(test); + public updateRootProviderCount(delta: number) { + this.rootProviderCount += delta; } @@ -145,24 +156,6 @@ export class TestService extends Disposable implements ITestService { return result; } - /** - * @inheritdoc - */ - public updateDiscoveringCount(resource: ExtHostTestingResource, uri: URI, delta: number) { - const subscriptionKey = getTestSubscriptionKey(resource, uri); - const subscription = this.testSubscriptions.get(subscriptionKey); - if (!subscription) { - return; - } - - const wasBusy = !!subscription.stillDiscovering; - subscription.stillDiscovering += delta; - const isBusy = !!subscription.stillDiscovering; - if (wasBusy !== isBusy) { - this.busyStateChangeEmitter.fire({ resource, uri, busy: isBusy }); - } - } - /** * @inheritdoc */ @@ -178,37 +171,49 @@ export class TestService extends Disposable implements ITestService { /** * @inheritdoc */ - public subscribeToDiffs(resource: ExtHostTestingResource, uri: URI, acceptDiff: TestDiffListener) { + public subscribeToDiffs(resource: ExtHostTestingResource, uri: URI, acceptDiff?: TestDiffListener) { const subscriptionKey = getTestSubscriptionKey(resource, uri); let subscription = this.testSubscriptions.get(subscriptionKey); if (!subscription) { subscription = { ident: { resource, uri }, - collection: new MainThreadTestCollection(), + collection: new MainThreadTestCollection(this.rootProviderCount), listeners: 0, onDiff: new Emitter(), - stillDiscovering: 0, }; this.subscribeEmitter.fire({ resource, uri }); this.testSubscriptions.set(subscriptionKey, subscription); + } else if (subscription.disposeTimeout) { + subscription.disposeTimeout.dispose(); + subscription.disposeTimeout = undefined; } subscription.listeners++; - const revive = subscription.collection.getReviverDiff(); - if (revive.length) { - acceptDiff(revive); + if (acceptDiff) { + acceptDiff(subscription.collection.getReviverDiff()); } - const listener = subscription.onDiff.event(acceptDiff); - return toDisposable(() => { - listener.dispose(); + const listener = acceptDiff && subscription.onDiff.event(acceptDiff); + return { + collection: subscription.collection, + dispose: () => { + listener?.dispose(); - if (!--subscription!.listeners) { - this.unsubscribeEmitter.fire({ resource, uri }); - this.testSubscriptions.delete(subscriptionKey); + if (--subscription!.listeners > 0) { + return; + } + + + subscription!.disposeTimeout = disposableTimeout( + () => { + this.unsubscribeEmitter.fire({ resource, uri }); + this.testSubscriptions.delete(subscriptionKey); + }, + resource === ExtHostTestingResource.TextDocument ? documentUnsubscribeDelay : workspaceUnsubscribeDelay, + ); } - }); + }; } /** @@ -218,6 +223,7 @@ export class TestService extends Disposable implements ITestService { const sub = this.testSubscriptions.get(getTestSubscriptionKey(resource, URI.revive(uri))); if (sub) { sub.collection.apply(diff); + // console.log('accept', sub.collection, diff); sub.onDiff.fire(diff); } } @@ -241,13 +247,55 @@ export class TestService extends Disposable implements ITestService { } } -class MainThreadTestCollection extends AbstractIncrementalTestCollection { +class MainThreadTestCollection extends AbstractIncrementalTestCollection implements IMainThreadTestCollection { + private pendingRootChangeEmitter = new Emitter(); + private busyProvidersChangeEmitter = new Emitter(); + private _busyProviders = 0; + /** - * Gets a diff that adds all items currently in the tree to a new collection, - * allowing it to fully hydrate. + * @inheritdoc + */ + public get pendingRootProviders() { + return this._pendingRootProviders; + } + + /** + * @inheritdoc + */ + public get busyProviders() { + return this._busyProviders; + } + + /** + * @inheritdoc + */ + public get rootIds() { + return this.roots; + } + + public readonly onPendingRootProvidersChange = this.pendingRootChangeEmitter.event; + public readonly onBusyProvidersChange = this.busyProvidersChangeEmitter.event; + + constructor(private _pendingRootProviders: number) { + super(); + } + + /** + * @inheritdoc + */ + public getNodeById(id: string) { + return this.items.get(id); + } + + /** + * @inheritdoc */ public getReviverDiff() { - const ops: TestsDiff = []; + const ops: TestsDiff = [ + [TestDiffOpType.DeltaDiscoverComplete, this._busyProviders], + [TestDiffOpType.DeltaRootsComplete, this._pendingRootProviders], + ]; + const queue = [this.roots]; while (queue.length) { for (const child of queue.pop()!) { @@ -276,6 +324,25 @@ class MainThreadTestCollection extends AbstractIncrementalTestCollection; + getChildren(): Iterable; } export interface ITestSubscriptionItem extends IncrementalTestCollectionItem { @@ -28,10 +27,6 @@ export class TestSubscriptionListener extends Disposable { public readonly onDiff = this.onDiffEmitter.event; public readonly onFolderChange = this.onFolderChangeEmitter.event; - public get testCount() { - return this.subscription.testCount; - } - public get workspaceFolders() { return this.subscription.workspaceFolders; } @@ -57,21 +52,9 @@ export class TestSubscriptionListener extends Disposable { /** * Maintains an observable set of tests in the core. */ -export interface ITestingCollectionService { +export interface IWorkspaceTestCollectionService { readonly _serviceBrand: undefined; - /** - * Gets the current tests. Will only be non-zero if there's at least one - * active subscriber/ - */ - readonly count: number; - - /** - * Gets a test by ID if it exists in the collection. This is *not* guarenteed - * and will only include workspace tests. - */ - getTestById(id: string): ITestSubscriptionItem | undefined; - /** * Gets all workspace folders we're listening to. */ @@ -83,9 +66,9 @@ export interface ITestingCollectionService { subscribeToWorkspaceTests(): TestSubscriptionListener; } -export const ITestingCollectionService = createDecorator('ITestingViewService'); +export const IWorkspaceTestCollectionService = createDecorator('ITestingViewService'); -export class TestingCollectionService implements ITestingCollectionService { +export class WorkspaceTestCollectionService implements IWorkspaceTestCollectionService { declare _serviceBrand: undefined; private subscription?: TestSubscription; @@ -96,32 +79,6 @@ export class TestingCollectionService implements ITestingCollectionService { constructor(@IInstantiationService protected instantiationService: IInstantiationService) { } - /** - * @inheritdoc - */ - public get count() { - return this.subscription?.testCount || 0; - } - - /** - * @inheritdoc - */ - public getTestById(id: string) { - const collections = this.subscription?.workspaceFolderCollections; - if (!collections) { - return undefined; - } - - for (const [, collection] of collections) { - const test = collection.getNodeById(id); - if (test) { - return test; - } - } - - return undefined; - } - /** * @inheritdoc */ @@ -137,33 +94,47 @@ export class TestingCollectionService implements ITestingCollectionService { this.subscription.removeListener(listener); if (this.subscription.listenerCount === 0) { - this.debounceDispose(); + this.subscription.dispose(); + this.subscription = undefined; } }); this.subscription.addListener(listener); return listener; } - - @debounce(10_0000) - private debounceDispose() { - if (this.subscription && this.subscription.listenerCount === 0) { - this.subscription.dispose(); - this.subscription = undefined; - } - } } class TestSubscription extends Disposable { private listeners = new Set(); + private pendingRootChangeEmitter = new Emitter(); + private busyProvidersChangeEmitter = new Emitter(); private readonly collectionsForWorkspaces = new Map(); - public testCount = 0; + public readonly onPendingRootProvidersChange = this.pendingRootChangeEmitter.event; + public readonly onBusyProvidersChange = this.busyProvidersChangeEmitter.event; + + public get busyProviders() { + let total = 0; + for (const { collection } of this.collectionsForWorkspaces.values()) { + total += collection.busyProviders; + } + + return total; + } + + public get pendingRootProviders() { + let total = 0; + for (const { collection } of this.collectionsForWorkspaces.values()) { + total += collection.pendingRootProviders; + } + + return total; + } public get listenerCount() { return this.listeners.size; @@ -224,8 +195,8 @@ class TestSubscription extends Disposable { const folderNode: ITestSubscriptionFolder = { folder, getChildren: function* () { - for (const rootId of collection.rootNodes) { - const node = collection.getNodeById(rootId); + for (const rootId of listener.collection.rootIds) { + const node = listener.collection.getNodeById(rootId); if (node) { yield node; } @@ -233,50 +204,28 @@ class TestSubscription extends Disposable { }, }; - const collection = new TestCollection(folderNode, { - add: () => { - this.testCount++; - }, - remove: () => { - this.testCount--; - }, - update: () => undefined, - complete: () => undefined, - }); - const listener = this.testService.subscribeToDiffs( ExtHostTestingResource.Workspace, folder.uri, diff => { - collection.apply(diff); for (const listener of this.listeners) { listener.publishDiff(folder, diff); } }, ); - this.collectionsForWorkspaces.set(folder.uri.toString(), { listener, collection, folder: folderNode }); - } -} - -class TestCollection extends AbstractIncrementalTestCollection { - constructor(private readonly workspace: ITestSubscriptionFolder, private readonly collector: IncrementalChangeCollector) { - super(); - } - - public get rootNodes() { - return this.roots; - } - - public getNodeById(id: string) { - return this.items.get(id); - } - - protected createChangeCollector() { - return this.collector; - } - - protected createItem(internal: InternalTestItem): ITestSubscriptionItem { - return { ...internal, root: this.workspace, children: new Set() }; + const disposable = new DisposableStore(); + disposable.add(listener); + disposable.add(listener.collection.onBusyProvidersChange( + () => this.pendingRootChangeEmitter.fire(this.pendingRootProviders))); + disposable.add(listener.collection.onBusyProvidersChange( + () => this.busyProvidersChangeEmitter.fire(this.busyProviders))); + + + this.collectionsForWorkspaces.set(folder.uri.toString(), { + listener: disposable, + collection: listener.collection, + folder: folderNode, + }); } } diff --git a/src/vs/workbench/contrib/testing/test/browser/testObjectTree.ts b/src/vs/workbench/contrib/testing/test/browser/testObjectTree.ts index c6a420683542..a7c1201b3a25 100644 --- a/src/vs/workbench/contrib/testing/test/browser/testObjectTree.ts +++ b/src/vs/workbench/contrib/testing/test/browser/testObjectTree.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { IWorkspaceFolder, IWorkspaceFolderData, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ITestTreeElement, ITestTreeProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections'; import { TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/testingCollectionService'; +import { TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; import { TestOwnedTestCollection, TestSingleUseCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection'; type SerializedTree = { e: string; children?: SerializedTree[] }; diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index f37d8e2160b7..ef9980b7559d 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -372,6 +372,16 @@ MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { order: 2 }); +MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { + group: '4_themes', + command: { + id: SelectProductIconThemeAction.ID, + title: localize({ key: 'miSelectProductIconTheme', comment: ['&& denotes a mnemonic'] }, "&&Product Icon Theme") + }, + order: 3 +}); + + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '4_themes', command: { @@ -389,3 +399,12 @@ MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { }, order: 2 }); + +MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '4_themes', + command: { + id: SelectProductIconThemeAction.ID, + title: localize('themes.selectProductIconTheme.label', "Product Icon Theme") + }, + order: 3 +}); diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 2407b261f8c8..b2f093ee1954 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -319,7 +319,8 @@ */ function isCopyPasteOrCut(e) { const hasMeta = e.ctrlKey || e.metaKey; - return hasMeta && ['c', 'v', 'x'].includes(e.key.toLowerCase()); + const shiftInsert = e.shiftKey && e.key.toLowerCase() === 'insert'; + return (hasMeta && ['c', 'v', 'x'].includes(e.key.toLowerCase())) || shiftInsert; } /** diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index c922702eaf41..4403a2ac4b43 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -202,7 +202,7 @@ export class IFrameWebview extends BaseWebview implements Web remoteConnectionData, rewriteUri, }, { - readFileStream: (resource) => this.fileService.readFileStream(resource).then(x => x.value), + readFileStream: (resource) => this.fileService.readFileStream(resource).then(x => ({ stream: x.value, etag: x.etag })), }, this.requestService, this.logService); if (result.type === WebviewResourceResponse.Type.Success) { diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts b/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts index 62e5d11d3306..99820e69b3ed 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts @@ -111,7 +111,7 @@ export class WebviewResourceRequestManager extends Disposable { roots: this._localResourceRoots, remoteConnectionData: remoteConnectionData, }, { - readFileStream: (resource) => fileService.readFileStream(resource).then(x => x.value), + readFileStream: (resource) => fileService.readFileStream(resource).then(x => ({ stream: x.value, etag: x.etag })), }, requestService, this._logService); this._logService.debug(`WebviewResourceRequestManager(${this.id}): finished resource load. uri: ${uri}, type=${response.type}`); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts index 0ef2f941f51d..a7628dd2cace 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { GettingStartedInputFactory, GettingStartedPage, GettingStartedInput } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted'; +import { GettingStartedInputFactory, GettingStartedInput, getGettingStartedInput } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; @@ -13,6 +13,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; import product from 'vs/platform/product/common/product'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export * as icons from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons'; @@ -34,7 +35,7 @@ registerAction2(class extends Action2 { } public run(accessor: ServicesAccessor) { - return accessor.get(IInstantiationService).createInstance(GettingStartedPage, {}).openEditor(); + accessor.get(IEditorService).openEditor(accessor.get(IInstantiationService).invokeFunction(getGettingStartedInput, {}), {}); } }); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css index c3bb1a2e122e..74045c54e267 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css @@ -62,7 +62,7 @@ border-radius: 4px; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.categories #getting-started-categories-container { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.categories .getting-started-categories-container { display: flex; flex-wrap: wrap; justify-content: center; @@ -70,7 +70,7 @@ margin: 32px auto; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.categories #getting-started-categories-scrolling-container { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.categories .getting-started-categories-scrolling-container { overflow: scroll; height: 100%; } @@ -111,11 +111,11 @@ min-height: auto; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-columns .gap { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-columns .gap { flex: 150px 1 1000 } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-media { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-media { min-height: 300px; } @@ -124,7 +124,7 @@ font-size: 22pt; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-columns { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-columns { display: flex; justify-content: flex-start; padding: 20px 20px 0; @@ -145,7 +145,7 @@ opacity: 0.8; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-columns #getting-started-detail-left > div { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-columns .getting-started-detail-left > div { width: 100%; } @@ -190,7 +190,7 @@ margin-bottom: 0; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-left { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-left { min-width: 330px; width: 40%; max-width: 400px; @@ -202,17 +202,17 @@ height: 100%; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-container { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-container { height: 100%; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #gettingStartedDetailsContent { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .gettingStartedDetailsContent { height: 100%; display: flex; flex-direction: column; } -.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail #getting-started-detail-right { +.monaco-workbench .part.editor > .content .walkThroughContent .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-right { display: flex; align-items: flex-start; justify-content: center; diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index 5976e1252513..c9b673530419 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -6,13 +6,11 @@ import 'vs/css!./gettingStarted'; import 'vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started'; import { localize } from 'vs/nls'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WalkThroughInput } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { IEditorInputFactory } from 'vs/workbench/common/editor'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { assertIsDefined } from 'vs/base/common/types'; import { $, addDisposableListener } from 'vs/base/browser/dom'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -26,6 +24,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { gettingStartedCheckedCodicon, gettingStartedUncheckedCodicon } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; export const gettingStartedInputTypeId = 'workbench.editors.gettingStartedInput'; const telemetryFrom = 'gettingStartedPage'; @@ -37,11 +37,39 @@ export class GettingStartedInput extends WalkThroughInput { selectedTask: string | undefined; } +export function getGettingStartedInput(accessor: ServicesAccessor, options: { selectedCategory?: string, selectedTask?: string }) { + const resource = FileAccess.asBrowserUri('./vs_code_editor_getting_started.md', require) + .with({ + scheme: Schemas.walkThrough, + query: JSON.stringify({ moduleId: 'vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started' }) + }); + + const instantiationService = accessor.get(IInstantiationService); + + const pages: GettingStartedPage[] = []; + + const editorInput = instantiationService.createInstance(GettingStartedInput, { + typeId: gettingStartedInputTypeId, + name: localize('editorGettingStarted.title', "Getting Started"), + resource, + telemetryFrom, + onReady: (container: HTMLElement, disposableStore: DisposableStore) => { + const page = instantiationService.createInstance(GettingStartedPage, options, editorInput); + page.onReady(container); + pages.push(page); + disposableStore.add(page); + }, + layout: () => pages.forEach(page => page.layout()), + }); + + return editorInput; +} + export class GettingStartedPage extends Disposable { readonly editorInput: GettingStartedInput; private inProgressScroll = Promise.resolve(); - private dispatchListeners = new DisposableStore(); + private dispatchListeners: DisposableStore = new DisposableStore(); private gettingStartedCategories: IGettingStartedCategoryWithProgress[]; private currentCategory: IGettingStartedCategoryWithProgress | undefined; @@ -52,31 +80,17 @@ export class GettingStartedPage extends Disposable { constructor( initialState: { selectedCategory?: string, selectedTask?: string }, - @IEditorService private readonly editorService: IEditorService, + editorInput: GettingStartedInput, @ICommandService private readonly commandService: ICommandService, @IProductService private readonly productService: IProductService, @IKeybindingService private readonly keybindingService: IKeybindingService, @IGettingStartedService private readonly gettingStartedService: IGettingStartedService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IOpenerService private readonly openerService: IOpenerService, ) { super(); - const resource = FileAccess.asBrowserUri('./vs_code_editor_getting_started.md', require) - .with({ - scheme: Schemas.walkThrough, - query: JSON.stringify({ moduleId: 'vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started' }) - }); - - - this.editorInput = this.instantiationService.createInstance(GettingStartedInput, { - typeId: gettingStartedInputTypeId, - name: localize('editorGettingStarted.title', "Getting Started"), - resource, - telemetryFrom, - onReady: (container: HTMLElement) => this.onReady(container), - layout: () => this.layout(), - }); + this.editorInput = editorInput; this.editorInput.selectedCategory = initialState.selectedCategory; this.editorInput.selectedTask = initialState.selectedTask; @@ -95,24 +109,22 @@ export class GettingStartedPage extends Disposable { } ourTask.done = task.done; if (category.id === this.currentCategory?.id) { - const badgeelement = assertIsDefined(document.getElementById('done-task-' + task.id)); - if (task.done) { - badgeelement.classList.remove(...ThemeIcon.asClassNameArray(gettingStartedUncheckedCodicon)); - badgeelement.classList.add('complete', ...ThemeIcon.asClassNameArray(gettingStartedCheckedCodicon)); - } - else { - badgeelement.classList.add(...ThemeIcon.asClassNameArray(gettingStartedUncheckedCodicon)); - badgeelement.classList.remove('complete', ...ThemeIcon.asClassNameArray(gettingStartedCheckedCodicon)); - } + const badgeelements = assertIsDefined(document.querySelectorAll(`[data-done-task-id="${task.id}"]`)); + badgeelements.forEach(badgeelement => { + if (task.done) { + badgeelement.classList.remove(...ThemeIcon.asClassNameArray(gettingStartedUncheckedCodicon)); + badgeelement.classList.add('complete', ...ThemeIcon.asClassNameArray(gettingStartedCheckedCodicon)); + } + else { + badgeelement.classList.add(...ThemeIcon.asClassNameArray(gettingStartedUncheckedCodicon)); + badgeelement.classList.remove('complete', ...ThemeIcon.asClassNameArray(gettingStartedCheckedCodicon)); + } + }); } this.updateCategoryProgress(); })); } - public openEditor(options: IEditorOptions = { pinned: true }) { - return this.editorService.openEditor(this.editorInput, options); - } - private registerDispatchListeners(container: HTMLElement) { this.dispatchListeners.clear(); @@ -151,7 +163,7 @@ export class GettingStartedPage extends Disposable { break; } case 'selectTask': { - this.selectTask(argument); + this.selectTask(container, argument); e.stopPropagation(); break; } @@ -160,8 +172,14 @@ export class GettingStartedPage extends Disposable { throw Error('cannot run task action for category of non items type' + this.currentCategory?.id); } const taskToRun = assertIsDefined(this.currentCategory?.content.items.find(task => task.id === argument)); - const commandToRun = assertIsDefined(taskToRun.button?.command); - this.commandService.executeCommand(commandToRun); + if (taskToRun.button.command) { + this.commandService.executeCommand(taskToRun.button.command); + } else if (taskToRun.button.link) { + this.openerService.open(taskToRun.button.link); + this.gettingStartedService.progressByEvent('linkOpened:' + taskToRun.button.link); + } else { + throw Error('Task ' + JSON.stringify(taskToRun) + ' does not have an associated action'); + } break; } default: { @@ -174,10 +192,10 @@ export class GettingStartedPage extends Disposable { }); } - private selectTask(id: string | undefined) { - const mediaElement = assertIsDefined(document.getElementById('getting-started-media')); + private selectTask(container: HTMLElement, id: string | undefined) { + const mediaElement = assertIsDefined(container.querySelector('.getting-started-media')); if (id) { - const taskElement = assertIsDefined(document.getElementById('getting-started-task-' + id)); + const taskElement = assertIsDefined(container.querySelector(`[data-task-id="${id}"]`)); if (!this.currentCategory || this.currentCategory.content.type !== 'items') { throw Error('cannot expand task for category of non items type' + this.currentCategory?.id); } @@ -196,7 +214,7 @@ export class GettingStartedPage extends Disposable { this.detailImageScrollbar?.scanDomNode(); } - private onReady(container: HTMLElement) { + onReady(container: HTMLElement) { const categoryElements = this.gettingStartedCategories.map( category => { const categoryDescriptionElement = @@ -218,21 +236,21 @@ export class GettingStartedPage extends Disposable { $(ThemeIcon.asCSSSelector(category.icon), {}), categoryDescriptionElement); }); - const categoriesSlide = assertIsDefined(document.getElementById('gettingStartedSlideCategory')); - const tasksSlide = assertIsDefined(document.getElementById('gettingStartedSlideDetails')); + const categoriesSlide = assertIsDefined(container.querySelector('.gettingStartedSlideCategory')); + const tasksSlide = assertIsDefined(container.querySelector('.gettingStartedSlideDetails')); - const tasksContent = assertIsDefined(document.getElementById('gettingStartedDetailsContent') as HTMLElement); + const tasksContent = assertIsDefined(container.querySelector('.gettingStartedDetailsContent') as HTMLElement); tasksContent.remove(); if (this.detailImageScrollbar) { this.detailImageScrollbar.dispose(); } this.detailImageScrollbar = this._register(new DomScrollableElement(tasksContent, { className: 'full-height-scrollable' })); tasksSlide.appendChild(this.detailImageScrollbar.getDomNode()); this.detailImageScrollbar.scanDomNode(); - const rightColumn = assertIsDefined(container.querySelector('#getting-started-detail-right')); - rightColumn.appendChild($('img#getting-started-media')); + const rightColumn = assertIsDefined(container.querySelector('.getting-started-detail-right')); + rightColumn.appendChild($('img.getting-started-media')); - const categoryScrollContainer = $('#getting-started-categories-scrolling-container'); - const categoriesContainer = $('#getting-started-categories-container'); + const categoryScrollContainer = $('.getting-started-categories-scrolling-container'); + const categoriesContainer = $('.getting-started-categories-container'); categoryElements.forEach(element => { categoriesContainer.appendChild(element); }); @@ -248,7 +266,7 @@ export class GettingStartedPage extends Disposable { this.updateCategoryProgress(); - assertIsDefined(document.getElementById('product-name')).textContent = this.productService.nameLong; + assertIsDefined(container.querySelector('.product-name')).textContent = this.productService.nameLong; this.registerDispatchListeners(container); @@ -265,7 +283,7 @@ export class GettingStartedPage extends Disposable { setTimeout(() => assertIsDefined(container.querySelector('.gettingStartedContainer')).classList.add('animationReady'), 0); } - private layout() { + layout() { this.categoriesScrollbar?.scanDomNode(); this.detailsScrollbar?.scanDomNode(); this.detailImageScrollbar?.scanDomNode(); @@ -295,7 +313,7 @@ export class GettingStartedPage extends Disposable { private async scrollToCategory(container: HTMLElement, categoryID: string) { this.inProgressScroll = this.inProgressScroll.then(async () => { - this.clearDetialView(); + this.clearDetialView(container); this.editorInput.selectedCategory = categoryID; this.currentCategory = this.gettingStartedCategories.find(category => category.id === categoryID); const slides = [...container.querySelectorAll('.gettingStartedSlide').values()]; @@ -313,8 +331,8 @@ export class GettingStartedPage extends Disposable { if (!category) { throw Error('could not find category with ID ' + categoryID); } if (category.content.type !== 'items') { throw Error('category with ID ' + categoryID + ' is not of items type'); } - const leftColumn = assertIsDefined(document.getElementById('getting-started-detail-left')); - const detailTitle = assertIsDefined(document.getElementById('getting-started-detail-title')); + const leftColumn = assertIsDefined(container.querySelector('.getting-started-detail-left')); + const detailTitle = assertIsDefined(container.querySelector('.getting-started-detail-title')); detailTitle.appendChild( $('.getting-started-category', {}, @@ -325,8 +343,8 @@ export class GettingStartedPage extends Disposable { const categoryElements = category.content.items.map( (task, i, arr) => $('button.getting-started-task', - { 'x-dispatch': 'selectTask:' + task.id, id: 'getting-started-task-' + task.id }, - $('.codicon' + (task.done ? '.complete.codicon-pass-filled' : '.codicon-circle-large-outline'), { id: 'done-task-' + task.id }), + { 'x-dispatch': 'selectTask:' + task.id, 'data-task-id': task.id }, + $('.codicon' + (task.done ? '.complete.codicon-pass-filled' : '.codicon-circle-large-outline'), { 'data-done-task-id': task.id }), $('.task-description-container', {}, $('h3.task-title', {}, task.title), $('.task-description.description', {}, task.description), @@ -334,7 +352,7 @@ export class GettingStartedPage extends Disposable { ...( task.button ? [$('button.emphasis.getting-started-task-action', { 'x-dispatch': 'runTaskAction:' + task.id }, - task.button.title + this.getKeybindingLabel(task.button.command) + task.button.title + (task.button.command ? this.getKeybindingLabel(task.button.command) : '') )] : []), ...( @@ -346,22 +364,23 @@ export class GettingStartedPage extends Disposable { )) ))); - const detailContainer = $('#getting-started-detail-container'); + const detailContainer = $('.getting-started-detail-container'); if (this.detailsScrollbar) { this.detailsScrollbar.getDomNode().remove(); this.detailsScrollbar.dispose(); } this.detailsScrollbar = this._register(new DomScrollableElement(detailContainer, { className: 'full-height-scrollable' })); categoryElements.forEach(element => detailContainer.appendChild(element)); leftColumn.appendChild(this.detailsScrollbar.getDomNode()); const toExpand = category.content.items.find(item => !item.done) ?? category.content.items[0]; - this.selectTask(selectedItem ?? toExpand.id); + this.selectTask(container, selectedItem ?? toExpand.id); this.detailsScrollbar.scanDomNode(); this.registerDispatchListeners(container); } - private clearDetialView() { - const detailContainer = (document.getElementById('getting-started-detail-container')); + private clearDetialView(container: HTMLElement) { + console.log(container); + const detailContainer = (container.querySelector('.getting-started-detail-container')); detailContainer?.remove(); - const detailTitle = assertIsDefined(document.getElementById('getting-started-detail-title')); + const detailTitle = assertIsDefined(container.querySelector('.getting-started-detail-title')); while (detailTitle.firstChild) { detailTitle.removeChild(detailTitle.firstChild); } } @@ -376,7 +395,7 @@ export class GettingStartedPage extends Disposable { this.currentCategory = undefined; this.editorInput.selectedCategory = undefined; this.editorInput.selectedTask = undefined; - this.selectTask(undefined); + this.selectTask(container, undefined); const slides = [...container.querySelectorAll('.gettingStartedSlide').values()]; const currentSlide = slides.findIndex(element => !element.classList.contains('prev') && !element.classList.contains('next')); @@ -400,9 +419,9 @@ export class GettingStartedInputFactory implements IEditorInputFactory { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): GettingStartedInput { try { const { selectedCategory, selectedTask } = JSON.parse(serializedEditorInput); - return instantiationService.createInstance(GettingStartedPage, { selectedCategory, selectedTask }).editorInput; + return instantiationService.invokeFunction(getGettingStartedInput, { selectedCategory, selectedTask }); } catch { } - return instantiationService.createInstance(GettingStartedPage, {}).editorInput; + return instantiationService.invokeFunction(getGettingStartedInput, {}); } } diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started.ts index 1c2733696e3c..9c09f066d840 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/vs_code_editor_getting_started.ts @@ -9,23 +9,23 @@ import { localize } from 'vs/nls'; export default () => `
-
+
-

${escape(localize('gettingStarted.vscode', "Visual Studio Code"))}

+

${escape(localize('gettingStarted.vscode', "Visual Studio Code"))}

${escape(localize({ key: 'gettingStarted.editingRedefined', comment: ['Shown as subtitle on the Welcome page.'] }, "Code editing. Redefined"))}

-
+
Back -
+
-
+
-
-
+
+
-
+
diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 28f84015a660..766cd1af6ad5 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -46,7 +46,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { gettingStartedInputTypeId, GettingStartedPage } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted'; +import { getGettingStartedInput, gettingStartedInputTypeId } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted'; import { welcomeButtonBackground, welcomeButtonHoverBackground, welcomePageBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors'; const configurationKey = 'workbench.startupEditor'; @@ -105,10 +105,6 @@ export class WelcomePageContribution implements IWorkbenchContribution { }); } else { const startupEditorTypeID = startupEditorSetting === 'gettingStarted' ? gettingStartedInputTypeId : welcomeInputTypeId; - const launchEditor = startupEditorSetting === 'gettingStarted' - ? instantiationService.createInstance(GettingStartedPage, {}) - : instantiationService.createInstance(WelcomePage); - let options: IEditorOptions; let editor = editorService.activeEditor; if (editor) { @@ -120,7 +116,13 @@ export class WelcomePageContribution implements IWorkbenchContribution { } else { options = { pinned: false }; } - return launchEditor.openEditor(options); + + if (startupEditorTypeID === gettingStartedInputTypeId) { + editorService.openEditor(instantiationService.invokeFunction(getGettingStartedInput, {}), options); + } else { + const launchEditor = instantiationService.createInstance(WelcomePage); + return launchEditor.openEditor(options); + } } } return undefined; diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts index 288b01233e54..09d5c3df1187 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts @@ -5,7 +5,7 @@ import { EditorInput, EditorModel, ITextEditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { IReference } from 'vs/base/common/lifecycle'; +import { DisposableStore, IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import * as marked from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; @@ -42,7 +42,7 @@ export interface WalkThroughInputOptions { readonly description?: string; readonly resource: URI; readonly telemetryFrom: string; - readonly onReady?: (container: HTMLElement) => void; + readonly onReady?: (container: HTMLElement, contentDisposables: DisposableStore) => void; readonly layout?: (dimension: Dimension) => void; } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index a3474fb4fe61..ee07278a42b2 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -271,7 +271,9 @@ export class WalkThroughPart extends EditorPane { this.saveTextEditorViewState(this.input); } - this.contentDisposables = dispose(this.contentDisposables); + const store = new DisposableStore(); + this.contentDisposables.push(store); + this.content.innerText = ''; return super.setInput(input, options, context, token) @@ -294,7 +296,7 @@ export class WalkThroughPart extends EditorPane { this.decorateContent(); this.contentDisposables.push(this.keybindingService.onDidUpdateKeybindings(() => this.decorateContent())); if (input.onReady) { - input.onReady(this.content.firstElementChild as HTMLElement); + input.onReady(this.content.firstElementChild as HTMLElement, store); } this.scrollbar.scanDomNode(); this.loadTextEditorViewState(input); @@ -404,7 +406,7 @@ export class WalkThroughPart extends EditorPane { } })); if (input.onReady) { - input.onReady(innerContent); + input.onReady(innerContent, store); } this.scrollbar.scanDomNode(); this.loadTextEditorViewState(input); @@ -500,6 +502,7 @@ export class WalkThroughPart extends EditorPane { if (this.input instanceof WalkThroughInput) { this.saveTextEditorViewState(this.input); } + this.contentDisposables = dispose(this.contentDisposables); super.clearInput(); } diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 94d47c9cdec6..42e950be7a96 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -79,10 +79,10 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench getEnablementState(extension: IExtension): EnablementState { if (this.extensionBisectService.isDisabledByBisect(extension)) { - return EnablementState.DisabledByEnvironemt; + return EnablementState.DisabledByEnvironment; } if (this._isDisabledInEnv(extension)) { - return EnablementState.DisabledByEnvironemt; + return EnablementState.DisabledByEnvironment; } if (this._isDisabledByExtensionKind(extension)) { return EnablementState.DisabledByExtensionKind; @@ -97,7 +97,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench return false; } const enablementState = this.getEnablementState(extension); - if (enablementState === EnablementState.DisabledByEnvironemt || enablementState === EnablementState.DisabledByExtensionKind) { + if (enablementState === EnablementState.DisabledByEnvironment || enablementState === EnablementState.DisabledByExtensionKind) { return false; } return true; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index 380898ba50d3..31b04b854801 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -34,7 +34,7 @@ export interface IWorkbenchExtensioManagementService extends IExtensionManagemen export const enum EnablementState { DisabledByExtensionKind, - DisabledByEnvironemt, + DisabledByEnvironment, DisabledGlobally, DisabledWorkspace, EnabledGlobally, diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index 7259d0698d3e..24826debc551 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -458,7 +458,7 @@ suite('ExtensionEnablementService Test', () => { instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, getInstalled: () => Promise.resolve([extension, aLocalExtension('pub.b')]) } as IExtensionManagementService); testObject = new TestExtensionEnablementService(instantiationService); assert.ok(!testObject.isEnabled(extension)); - assert.deepEqual(testObject.getEnablementState(extension), EnablementState.DisabledByEnvironemt); + assert.deepEqual(testObject.getEnablementState(extension), EnablementState.DisabledByEnvironment); }); test('test local workspace extension is disabled by kind', async () => { diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 40e8dbe6fc93..c19a1f5ba58e 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -12,7 +12,7 @@ import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; -import { getGalleryExtensionId, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionId, groupByExtension, ExtensionIdentifierWithVersion, getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isValidExtensionVersion } from 'vs/platform/extensions/common/extensionValidator'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; @@ -335,7 +335,7 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { } // id := `publisher.name` - extensionDescription.id = `${extensionDescription.publisher}.${extensionDescription.name}`; + extensionDescription.id = getExtensionId(extensionDescription.publisher, extensionDescription.name); extensionDescription.identifier = new ExtensionIdentifier(extensionDescription.id); extensionDescription.extensionLocation = URI.file(this._absoluteFolderPath); diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts index d70a5af93072..0b60fc817ad1 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts @@ -18,7 +18,9 @@ type GettingStartedItem = { id: string title: string, description: string, - button: { title: string, command: string }, + button: + | { title: string, command?: never, link: string } + | { title: string, command: string, link?: never }, doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never, } when?: string, media: { type: 'image', path: string, altText: string }, @@ -225,6 +227,17 @@ export const content: GettingStartedContent = [ }, doneOn: { commandExecuted: 'workbench.action.openSettings' }, media: { type: 'image', altText: 'VS Code Settings', path: 'settings.jpg' }, + }, + { + id: 'video', + title: localize('gettingStarted.video.title', "Open A Link"), + description: localize('gettingStarted.video.description', "Open a link."), + button: { + title: localize('gettingStarted.video.button', "Open"), + link: 'https://aka.ms/unknown' + }, + doneOn: { eventFired: 'linkOpened:https://aka.ms/unknown' }, + media: { type: 'image', altText: 'VS Code Settings', path: 'settings.jpg' }, } ] } diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts index 5020ef5b02ce..0bb3220d7f7d 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts @@ -24,7 +24,9 @@ export interface IGettingStartedTask { category: GettingStartedCategory | string, when: ContextKeyExpression, order: number, - button: { title: string, command: string }, + button: + | { title: string, command?: never, link: string } + | { title: string, command: string, link?: never }, doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never, } media: { type: 'image', path: URI, altText: string }, } diff --git a/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts b/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts index cdc53cda42d7..afe18caf17f5 100644 --- a/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts +++ b/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts @@ -21,6 +21,7 @@ class TestViewlet implements IViewlet { readonly onDidBlur = Event.None; readonly onDidFocus = Event.None; + hasFocus() { return false; } getId(): string { return this.id; } getTitle(): string { return this.id; } getActions(): IAction[] { return []; } diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 08fd92251575..65f25cd64758 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -131,7 +131,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.fileIconThemeSequencer = new Sequencer(); this.productIconThemeWatcher = new ThemeFileWatcher(fileService, environmentService, this.reloadCurrentProductIconTheme.bind(this)); - this.productIconThemeRegistry = new ThemeRegistry(productIconThemesExtPoint, ProductIconThemeData.fromExtensionTheme, true, ProductIconThemeData.defaultTheme, true); + this.productIconThemeRegistry = new ThemeRegistry(productIconThemesExtPoint, ProductIconThemeData.fromExtensionTheme, true, ProductIconThemeData.defaultTheme); this.onProductIconThemeChange = new Emitter(); this.currentProductIconTheme = ProductIconThemeData.createUnloadedTheme(''); this.productIconThemeSequencer = new Sequencer(); diff --git a/src/vs/workbench/services/themes/common/themeExtensionPoints.ts b/src/vs/workbench/services/themes/common/themeExtensionPoints.ts index 86a6a82f320d..ec402a27ceee 100644 --- a/src/vs/workbench/services/themes/common/themeExtensionPoints.ts +++ b/src/vs/workbench/services/themes/common/themeExtensionPoints.ts @@ -10,7 +10,6 @@ import * as resources from 'vs/base/common/resources'; import { ExtensionMessageCollector, IExtensionPoint, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; @@ -127,8 +126,7 @@ export class ThemeRegistry { private readonly themesExtPoint: IExtensionPoint, private create: (theme: IThemeExtensionPoint, themeLocation: URI, extensionData: ExtensionData) => T, private idRequired = false, - private builtInTheme: T | undefined = undefined, - private isProposedApi = false + private builtInTheme: T | undefined = undefined ) { this.extensionThemes = []; this.initialize(); @@ -144,9 +142,6 @@ export class ThemeRegistry { } this.extensionThemes.length = 0; for (let ext of extensions) { - if (this.isProposedApi) { - checkProposedApiEnabled(ext.description); - } let extensionData: ExtensionData = { extensionId: ext.description.identifier.value, extensionPublisher: ext.description.publisher, diff --git a/src/vs/workbench/services/userData/browser/userDataInit.ts b/src/vs/workbench/services/userData/browser/userDataInit.ts index 4673d41229fc..d4624409ffd0 100644 --- a/src/vs/workbench/services/userData/browser/userDataInit.ts +++ b/src/vs/workbench/services/userData/browser/userDataInit.ts @@ -29,6 +29,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IExtensionService, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { mark } from 'vs/base/common/performance'; +import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions'; export const IUserDataInitializationService = createDecorator('IUserDataInitializationService'); export interface IUserDataInitializationService { @@ -191,11 +192,12 @@ class WorkbenchExtensionsInitializer extends ExtensionsInitializer { @IExtensionGalleryService galleryService: IExtensionGalleryService, @IGlobalExtensionEnablementService extensionEnablementService: IGlobalExtensionEnablementService, @IStorageService storageService: IStorageService, + @IIgnoredExtensionsManagementService ignoredExtensionsManagementService: IIgnoredExtensionsManagementService, @IFileService fileService: IFileService, @IEnvironmentService environmentService: IEnvironmentService, @IUserDataSyncLogService logService: IUserDataSyncLogService, ) { - super(extensionManagementService, galleryService, extensionEnablementService, storageService, fileService, environmentService, logService); + super(extensionManagementService, galleryService, extensionEnablementService, storageService, ignoredExtensionsManagementService, fileService, environmentService, logService); } protected async initializeRemoteExtensions(remoteExtensions: ISyncExtension[]): Promise { diff --git a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts index 8f39bcebc929..81760cea3bd2 100644 --- a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts @@ -202,10 +202,10 @@ suite('ExtHostLanguageFeatureCommands', function () { for (let info of value) { assert.strictEqual(info instanceof types.SymbolInformation, true); - assert.equal(info.name, 'testing'); - assert.equal(info.kind, types.SymbolKind.Array); + assert.strictEqual(info.name, 'testing'); + assert.strictEqual(info.kind, types.SymbolKind.Array); } - assert.equal(value.length, 3); + assert.strictEqual(value.length, 3); }); }); }); @@ -220,11 +220,11 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); let symbols = await commands.executeCommand('vscode.executeWorkspaceSymbolProvider', ''); - assert.equal(symbols.length, 1); + assert.strictEqual(symbols.length, 1); await rpcProtocol.sync(); symbols = await commands.executeCommand('vscode.executeWorkspaceSymbolProvider', '*'); - assert.equal(symbols.length, 1); + assert.strictEqual(symbols.length, 1); }); // --- formatting @@ -238,7 +238,7 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); let edits = await commands.executeCommand('vscode.executeFormatDocumentProvider', model.uri); - assert.equal(edits.length, 1); + assert.strictEqual(edits.length, 1); }); @@ -257,10 +257,10 @@ suite('ExtHostLanguageFeatureCommands', function () { const edit = await commands.executeCommand('vscode.executeDocumentRenameProvider', model.uri, new types.Position(0, 12), 'newNameOfThis'); assert.ok(edit); - assert.equal(edit.has(model.uri), true); + assert.strictEqual(edit.has(model.uri), true); const textEdits = edit.get(model.uri); - assert.equal(textEdits.length, 1); - assert.equal(textEdits[0].newText, 'newNameOfThis'); + assert.strictEqual(textEdits.length, 1); + assert.strictEqual(textEdits[0].newText, 'newNameOfThis'); }); // --- definition @@ -295,7 +295,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 4); + assert.strictEqual(values.length, 4); for (let v of values) { assert.ok(v.uri instanceof URI); assert.ok(v.range instanceof types.Range); @@ -316,7 +316,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); for (let v of values) { if (isLocation(v)) { assert.ok(v.uri instanceof URI); @@ -353,7 +353,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 4); + assert.strictEqual(values.length, 4); for (let v of values) { assert.ok(v.uri instanceof URI); assert.ok(v.range instanceof types.Range); @@ -374,7 +374,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); for (let v of values) { if (isLocation(v)) { assert.ok(v.uri instanceof URI); @@ -422,7 +422,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 4); + assert.strictEqual(values.length, 4); for (const v of values) { assert.ok(v.uri instanceof URI); assert.ok(v.range instanceof types.Range); @@ -443,7 +443,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeTypeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); for (let v of values) { if (isLocation(v)) { assert.ok(v.uri instanceof URI); @@ -491,7 +491,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 4); + assert.strictEqual(values.length, 4); for (const v of values) { assert.ok(v.uri instanceof URI); assert.ok(v.range instanceof types.Range); @@ -512,7 +512,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand<(vscode.Location | vscode.LocationLink)[]>('vscode.executeImplementationProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); for (let v of values) { if (isLocation(v)) { assert.ok(v.uri instanceof URI); @@ -541,13 +541,13 @@ suite('ExtHostLanguageFeatureCommands', function () { })); return commands.executeCommand('vscode.executeReferenceProvider', model.uri, new types.Position(0, 0)).then(values => { - assert.equal(values.length, 1); + assert.strictEqual(values.length, 1); let [first] = values; - assert.equal(first.uri.toString(), 'some:uri/path'); - assert.equal(first.range.start.line, 0); - assert.equal(first.range.start.character, 1); - assert.equal(first.range.end.line, 0); - assert.equal(first.range.end.character, 5); + assert.strictEqual(first.uri.toString(), 'some:uri/path'); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 1); + assert.strictEqual(first.range.end.line, 0); + assert.strictEqual(first.range.end.character, 5); }); }); @@ -565,12 +565,12 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeDocumentSymbolProvider', model.uri).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); let [first, second] = values; assert.strictEqual(first instanceof types.SymbolInformation, true); assert.strictEqual(second instanceof types.SymbolInformation, true); - assert.equal(first.name, 'testing2'); - assert.equal(second.name, 'testing1'); + assert.strictEqual(first.name, 'testing2'); + assert.strictEqual(second.name, 'testing1'); }); }); }); @@ -593,14 +593,14 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand<(vscode.SymbolInformation & vscode.DocumentSymbol)[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => { - assert.equal(values.length, 2); + assert.strictEqual(values.length, 2); let [first, second] = values; assert.strictEqual(first instanceof types.SymbolInformation, true); assert.strictEqual(first instanceof types.DocumentSymbol, false); assert.strictEqual(second instanceof types.SymbolInformation, true); - assert.equal(first.name, 'DocumentSymbol'); - assert.equal(first.children.length, 1); - assert.equal(second.name, 'SymbolInformation'); + assert.strictEqual(first.name, 'DocumentSymbol'); + assert.strictEqual(first.children.length, 1); + assert.strictEqual(second.name, 'SymbolInformation'); }); }); }); @@ -630,37 +630,37 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.ok(list instanceof types.CompletionList); let values = list.items; assert.ok(Array.isArray(values)); - assert.equal(values.length, 4); + assert.strictEqual(values.length, 4); let [first, second, third, fourth] = values; - assert.equal(first.label, 'item1'); - assert.equal(first.textEdit, undefined);// no text edit, default ranges + assert.strictEqual(first.label, 'item1'); + assert.strictEqual(first.textEdit, undefined);// no text edit, default ranges assert.ok(!types.Range.isRange(first.range)); - assert.equal(second.label, 'item2'); - assert.equal(second.textEdit!.newText, 'foo'); - assert.equal(second.textEdit!.range.start.line, 0); - assert.equal(second.textEdit!.range.start.character, 4); - assert.equal(second.textEdit!.range.end.line, 0); - assert.equal(second.textEdit!.range.end.character, 8); + assert.strictEqual(second.label, 'item2'); + assert.strictEqual(second.textEdit!.newText, 'foo'); + assert.strictEqual(second.textEdit!.range.start.line, 0); + assert.strictEqual(second.textEdit!.range.start.character, 4); + assert.strictEqual(second.textEdit!.range.end.line, 0); + assert.strictEqual(second.textEdit!.range.end.character, 8); - assert.equal(third.label, 'item3'); - assert.equal(third.textEdit!.newText, 'foobar'); - assert.equal(third.textEdit!.range.start.line, 0); - assert.equal(third.textEdit!.range.start.character, 1); - assert.equal(third.textEdit!.range.end.line, 0); - assert.equal(third.textEdit!.range.end.character, 6); + assert.strictEqual(third.label, 'item3'); + assert.strictEqual(third.textEdit!.newText, 'foobar'); + assert.strictEqual(third.textEdit!.range.start.line, 0); + assert.strictEqual(third.textEdit!.range.start.character, 1); + assert.strictEqual(third.textEdit!.range.end.line, 0); + assert.strictEqual(third.textEdit!.range.end.character, 6); - assert.equal(fourth.label, 'item4'); - assert.equal(fourth.textEdit, undefined); + assert.strictEqual(fourth.label, 'item4'); + assert.strictEqual(fourth.textEdit, undefined); const range: any = fourth.range!; assert.ok(types.Range.isRange(range)); - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 1); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 4); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.start.character, 1); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.end.character, 4); assert.ok(fourth.insertText instanceof types.SnippetString); - assert.equal((fourth.insertText).value, 'foo$0bar'); + assert.strictEqual((fourth.insertText).value, 'foo$0bar'); }); }); }); @@ -677,7 +677,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4)).then(list => { assert.ok(list instanceof types.CompletionList); - assert.equal(list.isIncomplete, true); + assert.strictEqual(list.isIncomplete, true); }); }); }); @@ -711,7 +711,7 @@ suite('ExtHostLanguageFeatureCommands', function () { ); assert.ok(list instanceof types.CompletionList); - assert.equal(resolveCount, 2); + assert.strictEqual(resolveCount, 2); }); @@ -738,13 +738,13 @@ suite('ExtHostLanguageFeatureCommands', function () { ); assert.ok(list instanceof types.CompletionList); - assert.equal(list.items.length, 4); + assert.strictEqual(list.items.length, 4); let [a, b, c, d] = list.items; - assert.equal(a.preselect, true); - assert.equal(b.preselect, undefined); - assert.equal(c.preselect, true); - assert.equal(d.preselect, undefined); + assert.strictEqual(a.preselect, true); + assert.strictEqual(b.preselect, undefined); + assert.strictEqual(c.preselect, true); + assert.strictEqual(d.preselect, undefined); }); test('executeCompletionItemProvider doesn\'t capture commitCharacters #58228', async function () { @@ -767,11 +767,11 @@ suite('ExtHostLanguageFeatureCommands', function () { ); assert.ok(list instanceof types.CompletionList); - assert.equal(list.items.length, 2); + assert.strictEqual(list.items.length, 2); let [a, b] = list.items; - assert.deepEqual(a.commitCharacters, ['a', 'b']); - assert.equal(b.commitCharacters, undefined); + assert.deepStrictEqual(a.commitCharacters, ['a', 'b']); + assert.strictEqual(b.commitCharacters, undefined); }); test('vscode.executeCompletionItemProvider returns the wrong CompletionItemKinds in insiders #95715', async function () { @@ -794,11 +794,11 @@ suite('ExtHostLanguageFeatureCommands', function () { ); assert.ok(list instanceof types.CompletionList); - assert.equal(list.items.length, 2); + assert.strictEqual(list.items.length, 2); const [a, b] = list.items; - assert.equal(a.kind, types.CompletionItemKind.Method); - assert.equal(b.kind, types.CompletionItemKind.Property); + assert.strictEqual(a.kind, types.CompletionItemKind.Method); + assert.strictEqual(b.kind, types.CompletionItemKind.Property); }); // --- signatureHelp @@ -841,11 +841,11 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.equal(first.title, 'Title'); - assert.equal(first.command, 'testing'); - assert.deepEqual(first.arguments, [1, 2, true]); + assert.strictEqual(first.title, 'Title'); + assert.strictEqual(first.command, 'testing'); + assert.deepStrictEqual(first.arguments, [1, 2, true]); }); }); }); @@ -867,13 +867,13 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; assert.ok(first.command); - assert.equal(first.command!.command, 'command'); - assert.equal(first.command!.title, 'command_title'); - assert.equal(first.kind!.value, 'foo'); - assert.equal(first.title, 'title'); + assert.strictEqual(first.command!.command, 'command'); + assert.strictEqual(first.command!.title, 'command_title'); + assert.strictEqual(first.kind!.value, 'foo'); + assert.strictEqual(first.title, 'title'); }); }); @@ -898,7 +898,7 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCodeActionProvider', model.uri, selection).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; assert.ok(first.command); assert.ok(first.command!.arguments![1] instanceof types.Selection); @@ -927,9 +927,9 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCodeActionProvider', model.uri, selection).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.isPreferred, true); + assert.strictEqual(first.isPreferred, true); }); }); }); @@ -958,11 +958,11 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); const value = await commands.executeCommand('vscode.executeCodeActionProvider', model.uri, selection, undefined, 1000); - assert.equal(didCallResolve, 1); - assert.equal(value.length, 1); + assert.strictEqual(didCallResolve, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.title, 'title'); // does NOT change + assert.strictEqual(first.title, 'title'); // does NOT change assert.ok(first.edit); // is set }); @@ -984,14 +984,14 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeCodeLensProvider', model.uri).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.command!.title, 'Title'); - assert.equal(first.command!.command, 'cmd'); - assert.equal(first.command!.arguments![0], 1); - assert.equal(first.command!.arguments![1], true); - assert.equal(first.command!.arguments![2], complexArg); + assert.strictEqual(first.command!.title, 'Title'); + assert.strictEqual(first.command!.command, 'cmd'); + assert.strictEqual(first.command!.arguments![0], 1); + assert.strictEqual(first.command!.arguments![1], true); + assert.strictEqual(first.command!.arguments![2], complexArg); }); }); }); @@ -1020,14 +1020,14 @@ suite('ExtHostLanguageFeatureCommands', function () { let value = await commands.executeCommand('vscode.executeCodeLensProvider', model.uri, 2); - assert.equal(value.length, 3); // the resolve argument defines the number of results being returned - assert.equal(resolveCount, 2); + assert.strictEqual(value.length, 3); // the resolve argument defines the number of results being returned + assert.strictEqual(resolveCount, 2); resolveCount = 0; value = await commands.executeCommand('vscode.executeCodeLensProvider', model.uri); - assert.equal(value.length, 4); - assert.equal(resolveCount, 0); + assert.strictEqual(value.length, 4); + assert.strictEqual(resolveCount, 0); }); test('Links, back and forth', function () { @@ -1040,14 +1040,14 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeLinkProvider', model.uri).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.equal(first.target + '', 'foo:bar'); - assert.equal(first.range.start.line, 0); - assert.equal(first.range.start.character, 0); - assert.equal(first.range.end.line, 0); - assert.equal(first.range.end.character, 20); + assert.strictEqual(first.target + '', 'foo:bar'); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 0); + assert.strictEqual(first.range.end.line, 0); + assert.strictEqual(first.range.end.character, 20); }); }); }); @@ -1066,12 +1066,12 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); const links1 = await commands.executeCommand('vscode.executeLinkProvider', model.uri); - assert.equal(links1.length, 1); - assert.equal(links1[0].target, undefined); + assert.strictEqual(links1.length, 1); + assert.strictEqual(links1[0].target, undefined); const links2 = await commands.executeCommand('vscode.executeLinkProvider', model.uri, 1000); - assert.equal(links2.length, 1); - assert.equal(links2[0].target!.toString(), URI.parse('foo:bar').toString()); + assert.strictEqual(links2.length, 1); + assert.strictEqual(links2[0].target!.toString(), URI.parse('foo:bar').toString()); }); @@ -1092,36 +1092,36 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeDocumentColorProvider', model.uri).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.equal(first.color.red, 0.1); - assert.equal(first.color.green, 0.2); - assert.equal(first.color.blue, 0.3); - assert.equal(first.color.alpha, 0.4); - assert.equal(first.range.start.line, 0); - assert.equal(first.range.start.character, 0); - assert.equal(first.range.end.line, 0); - assert.equal(first.range.end.character, 20); + assert.strictEqual(first.color.red, 0.1); + assert.strictEqual(first.color.green, 0.2); + assert.strictEqual(first.color.blue, 0.3); + assert.strictEqual(first.color.alpha, 0.4); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 0); + assert.strictEqual(first.range.end.line, 0); + assert.strictEqual(first.range.end.character, 20); }); }).then(() => { const color = new types.Color(0.5, 0.6, 0.7, 0.8); const range = new types.Range(0, 0, 0, 20); return commands.executeCommand('vscode.executeColorPresentationProvider', color, { uri: model.uri, range }).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.equal(first.label, '#ABC'); - assert.equal(first.textEdit!.newText, '#ABC'); - assert.equal(first.textEdit!.range.start.line, 1); - assert.equal(first.textEdit!.range.start.character, 0); - assert.equal(first.textEdit!.range.end.line, 1); - assert.equal(first.textEdit!.range.end.character, 20); - assert.equal(first.additionalTextEdits!.length, 1); - assert.equal(first.additionalTextEdits![0].range.start.line, 2); - assert.equal(first.additionalTextEdits![0].range.start.character, 20); - assert.equal(first.additionalTextEdits![0].range.end.line, 2); - assert.equal(first.additionalTextEdits![0].range.end.character, 20); + assert.strictEqual(first.label, '#ABC'); + assert.strictEqual(first.textEdit!.newText, '#ABC'); + assert.strictEqual(first.textEdit!.range.start.line, 1); + assert.strictEqual(first.textEdit!.range.start.character, 0); + assert.strictEqual(first.textEdit!.range.end.line, 1); + assert.strictEqual(first.textEdit!.range.end.character, 20); + assert.strictEqual(first.additionalTextEdits!.length, 1); + assert.strictEqual(first.additionalTextEdits![0].range.start.line, 2); + assert.strictEqual(first.additionalTextEdits![0].range.start.character, 20); + assert.strictEqual(first.additionalTextEdits![0].range.end.line, 2); + assert.strictEqual(first.additionalTextEdits![0].range.end.character, 20); }); }); }); @@ -1136,8 +1136,8 @@ suite('ExtHostLanguageFeatureCommands', function () { return rpcProtocol.sync().then(() => { return commands.executeCommand('vscode.executeHoverProvider', model.uri, new types.Position(1, 1)).then(value => { - assert.equal(value.length, 1); - assert.equal(value[0].contents.length, 1); + assert.strictEqual(value.length, 1); + assert.strictEqual(value[0].contents.length, 1); }); }); }); @@ -1237,7 +1237,7 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); let value = await commands.executeCommand('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); assert.ok(value[0].parent); }); @@ -1272,16 +1272,16 @@ suite('ExtHostLanguageFeatureCommands', function () { const root = await commands.executeCommand('vscode.prepareCallHierarchy', model.uri, new types.Position(0, 0)); assert.ok(Array.isArray(root)); - assert.equal(root.length, 1); - assert.equal(root[0].name, 'ROOT'); + assert.strictEqual(root.length, 1); + assert.strictEqual(root[0].name, 'ROOT'); const incoming = await commands.executeCommand('vscode.provideIncomingCalls', root[0]); - assert.equal(incoming.length, 1); - assert.equal(incoming[0].from.name, 'INCOMING'); + assert.strictEqual(incoming.length, 1); + assert.strictEqual(incoming[0].from.name, 'INCOMING'); const outgoing = await commands.executeCommand('vscode.provideOutgoingCalls', root[0]); - assert.equal(outgoing.length, 1); - assert.equal(outgoing[0].to.name, 'OUTGOING'); + assert.strictEqual(outgoing.length, 1); + assert.strictEqual(outgoing[0].to.name, 'OUTGOING'); }); test('selectionRangeProvider on inner array always returns outer array #91852', async function () { @@ -1297,11 +1297,11 @@ suite('ExtHostLanguageFeatureCommands', function () { await rpcProtocol.sync(); let value = await commands.executeCommand('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]); - assert.equal(value.length, 1); - assert.equal(value[0].range.start.line, 0); - assert.equal(value[0].range.start.character, 10); - assert.equal(value[0].range.end.line, 0); - assert.equal(value[0].range.end.character, 10); + assert.strictEqual(value.length, 1); + assert.strictEqual(value[0].range.start.line, 0); + assert.strictEqual(value[0].range.start.character, 10); + assert.strictEqual(value[0].range.end.line, 0); + assert.strictEqual(value[0].range.end.character, 10); }); test('selectionRangeProvider on inner array always returns outer array #91852', async function () { @@ -1322,14 +1322,14 @@ suite('ExtHostLanguageFeatureCommands', function () { model.uri, [new types.Position(0, 0), new types.Position(0, 10)] ); - assert.equal(value.length, 2); - assert.equal(value[0].range.start.line, 0); - assert.equal(value[0].range.start.character, 0); - assert.equal(value[0].range.end.line, 0); - assert.equal(value[0].range.end.character, 0); - assert.equal(value[1].range.start.line, 0); - assert.equal(value[1].range.start.character, 10); - assert.equal(value[1].range.end.line, 0); - assert.equal(value[1].range.end.character, 10); + assert.strictEqual(value.length, 2); + assert.strictEqual(value[0].range.start.line, 0); + assert.strictEqual(value[0].range.start.character, 0); + assert.strictEqual(value[0].range.end.line, 0); + assert.strictEqual(value[0].range.end.character, 0); + assert.strictEqual(value[1].range.start.line, 0); + assert.strictEqual(value[1].range.start.character, 10); + assert.strictEqual(value[1].range.end.line, 0); + assert.strictEqual(value[1].range.end.character, 10); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostBulkEdits.test.ts b/src/vs/workbench/test/browser/api/extHostBulkEdits.test.ts index f6adea9dd437..70bbcc2c26d4 100644 --- a/src/vs/workbench/test/browser/api/extHostBulkEdits.test.ts +++ b/src/vs/workbench/test/browser/api/extHostBulkEdits.test.ts @@ -47,17 +47,17 @@ suite('ExtHostBulkEdits.applyWorkspaceEdit', () => { let edit = new extHostTypes.WorkspaceEdit(); edit.replace(resource, new extHostTypes.Range(0, 0, 0, 0), 'hello'); await bulkEdits.applyWorkspaceEdit(edit); - assert.equal(workspaceResourceEdits.edits.length, 1); + assert.strictEqual(workspaceResourceEdits.edits.length, 1); const [first] = workspaceResourceEdits.edits; assertType(first._type === WorkspaceEditType.Text); - assert.equal(first.modelVersionId, 1337); + assert.strictEqual(first.modelVersionId, 1337); }); test('does not use version id if document is not available', async () => { let edit = new extHostTypes.WorkspaceEdit(); edit.replace(URI.parse('foo:bar2'), new extHostTypes.Range(0, 0, 0, 0), 'hello'); await bulkEdits.applyWorkspaceEdit(edit); - assert.equal(workspaceResourceEdits.edits.length, 1); + assert.strictEqual(workspaceResourceEdits.edits.length, 1); const [first] = workspaceResourceEdits.edits; assertType(first._type === WorkspaceEditType.Text); assert.ok(typeof first.modelVersionId === 'undefined'); diff --git a/src/vs/workbench/test/browser/api/extHostCommands.test.ts b/src/vs/workbench/test/browser/api/extHostCommands.test.ts index 7a60a85fe87d..2ecab2e8d610 100644 --- a/src/vs/workbench/test/browser/api/extHostCommands.test.ts +++ b/src/vs/workbench/test/browser/api/extHostCommands.test.ts @@ -31,8 +31,8 @@ suite('ExtHostCommands', function () { new NullLogService() ); commands.registerCommand(true, 'foo', (): any => { }).dispose(); - assert.equal(lastUnregister!, 'foo'); - assert.equal(CommandsRegistry.getCommand('foo'), undefined); + assert.strictEqual(lastUnregister!, 'foo'); + assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); }); @@ -57,7 +57,7 @@ suite('ExtHostCommands', function () { reg.dispose(); reg.dispose(); reg.dispose(); - assert.equal(unregisterCounter, 1); + assert.strictEqual(unregisterCounter, 1); }); test('execute with retry', async function () { @@ -70,12 +70,12 @@ suite('ExtHostCommands', function () { } async $executeCommand(id: string, args: any[], retry: boolean): Promise { count++; - assert.equal(retry, count === 1); + assert.strictEqual(retry, count === 1); if (count === 1) { - assert.equal(retry, true); + assert.strictEqual(retry, true); throw new Error('$executeCommand:retry'); } else { - assert.equal(retry, false); + assert.strictEqual(retry, false); return 17; } } @@ -87,7 +87,7 @@ suite('ExtHostCommands', function () { ); const result = await commands.executeCommand('fooo', [this, true]); - assert.equal(result, 17); - assert.equal(count, 2); + assert.strictEqual(result, 17); + assert.strictEqual(count, 2); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/browser/api/extHostConfiguration.test.ts index ba291bffd75e..430eaf3e9353 100644 --- a/src/vs/workbench/test/browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/browser/api/extHostConfiguration.test.ts @@ -59,12 +59,12 @@ suite('ExtHostConfiguration', function () { } }); - assert.equal(extHostConfig.getConfiguration('search.exclude')['**/node_modules'], true); - assert.equal(extHostConfig.getConfiguration('search.exclude').get('**/node_modules'), true); - assert.equal(extHostConfig.getConfiguration('search').get('exclude')['**/node_modules'], true); + assert.strictEqual(extHostConfig.getConfiguration('search.exclude')['**/node_modules'], true); + assert.strictEqual(extHostConfig.getConfiguration('search.exclude').get('**/node_modules'), true); + assert.strictEqual(extHostConfig.getConfiguration('search').get('exclude')['**/node_modules'], true); - assert.equal(extHostConfig.getConfiguration('search.exclude').has('**/node_modules'), true); - assert.equal(extHostConfig.getConfiguration('search').has('exclude.**/node_modules'), true); + assert.strictEqual(extHostConfig.getConfiguration('search.exclude').has('**/node_modules'), true); + assert.strictEqual(extHostConfig.getConfiguration('search').has('exclude.**/node_modules'), true); }); test('has/get', () => { @@ -83,18 +83,18 @@ suite('ExtHostConfiguration', function () { const config = all.getConfiguration('farboo'); assert.ok(config.has('config0')); - assert.equal(config.get('config0'), true); - assert.equal(config.get('config4'), ''); - assert.equal(config['config0'], true); - assert.equal(config['config4'], ''); + assert.strictEqual(config.get('config0'), true); + assert.strictEqual(config.get('config4'), ''); + assert.strictEqual(config['config0'], true); + assert.strictEqual(config['config4'], ''); assert.ok(config.has('nested.config1')); - assert.equal(config.get('nested.config1'), 42); + assert.strictEqual(config.get('nested.config1'), 42); assert.ok(config.has('nested.config2')); - assert.equal(config.get('nested.config2'), 'Das Pferd frisst kein Reis.'); + assert.strictEqual(config.get('nested.config2'), 'Das Pferd frisst kein Reis.'); assert.ok(config.has('nested')); - assert.deepEqual(config.get('nested'), { config1: 42, config2: 'Das Pferd frisst kein Reis.' }); + assert.deepStrictEqual(config.get('nested'), { config1: 42, config2: 'Das Pferd frisst kein Reis.' }); }); test('can modify the returned configuration', function () { @@ -118,37 +118,37 @@ suite('ExtHostConfiguration', function () { let testObject = all.getConfiguration(); let actual = testObject.get('farboo')!; actual['nested']['config1'] = 41; - assert.equal(41, actual['nested']['config1']); + assert.strictEqual(41, actual['nested']['config1']); actual['farboo1'] = 'newValue'; - assert.equal('newValue', actual['farboo1']); + assert.strictEqual('newValue', actual['farboo1']); testObject = all.getConfiguration(); actual = testObject.get('farboo')!; - assert.equal(actual['nested']['config1'], 42); - assert.equal(actual['farboo1'], undefined); + assert.strictEqual(actual['nested']['config1'], 42); + assert.strictEqual(actual['farboo1'], undefined); testObject = all.getConfiguration(); actual = testObject.get('farboo')!; - assert.equal(actual['config0'], true); + assert.strictEqual(actual['config0'], true); actual['config0'] = false; - assert.equal(actual['config0'], false); + assert.strictEqual(actual['config0'], false); testObject = all.getConfiguration(); actual = testObject.get('farboo')!; - assert.equal(actual['config0'], true); + assert.strictEqual(actual['config0'], true); testObject = all.getConfiguration(); actual = testObject.inspect('farboo')!; actual['value'] = 'effectiveValue'; - assert.equal('effectiveValue', actual['value']); + assert.strictEqual('effectiveValue', actual['value']); testObject = all.getConfiguration('workbench'); actual = testObject.get('colorCustomizations')!; actual['statusBar.foreground'] = undefined; - assert.equal(actual['statusBar.foreground'], undefined); + assert.strictEqual(actual['statusBar.foreground'], undefined); testObject = all.getConfiguration('workbench'); actual = testObject.get('colorCustomizations')!; - assert.equal(actual['statusBar.foreground'], 'somevalue'); + assert.strictEqual(actual['statusBar.foreground'], 'somevalue'); }); test('Stringify returned configuration', function () { @@ -173,7 +173,7 @@ suite('ExtHostConfiguration', function () { const testObject = all.getConfiguration(); let actual: any = testObject.get('farboo'); - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'config0': true, 'nested': { 'config1': 42, @@ -182,11 +182,11 @@ suite('ExtHostConfiguration', function () { 'config4': '' }), JSON.stringify(actual)); - assert.deepEqual(undefined, JSON.stringify(testObject.get('unknownkey'))); + assert.deepStrictEqual(undefined, JSON.stringify(testObject.get('unknownkey'))); actual = testObject.get('farboo')!; actual['config0'] = false; - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'config0': false, 'nested': { 'config1': 42, @@ -197,14 +197,14 @@ suite('ExtHostConfiguration', function () { actual = testObject.get('workbench')!['colorCustomizations']!; actual['statusBar.background'] = 'anothervalue'; - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'statusBar.foreground': 'somevalue', 'statusBar.background': 'anothervalue' }), JSON.stringify(actual)); actual = testObject.get('workbench'); actual['unknownkey'] = 'somevalue'; - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'colorCustomizations': { 'statusBar.foreground': 'somevalue' }, @@ -218,7 +218,7 @@ suite('ExtHostConfiguration', function () { 'statusBar.background': `#0ff`, 'statusBar.foreground': `#ff0`, }; - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'statusBar.background': `#0ff`, 'statusBar.foreground': `#ff0`, }), JSON.stringify(actual)); @@ -229,7 +229,7 @@ suite('ExtHostConfiguration', function () { 'statusBar.background': `#0ff`, 'statusBar.foreground': `#ff0`, }; - assert.deepEqual(JSON.stringify({ + assert.deepStrictEqual(JSON.stringify({ 'statusBar.background': `#0ff`, 'statusBar.foreground': `#ff0`, }), JSON.stringify(actual)); @@ -292,16 +292,16 @@ suite('ExtHostConfiguration', function () { ); let actual = testObject.getConfiguration().inspect('editor.wordWrap')!; - assert.equal(actual.defaultValue, 'off'); - assert.equal(actual.globalValue, 'on'); - assert.equal(actual.workspaceValue, undefined); - assert.equal(actual.workspaceFolderValue, undefined); + assert.strictEqual(actual.defaultValue, 'off'); + assert.strictEqual(actual.globalValue, 'on'); + assert.strictEqual(actual.workspaceValue, undefined); + assert.strictEqual(actual.workspaceFolderValue, undefined); actual = testObject.getConfiguration('editor').inspect('wordWrap')!; - assert.equal(actual.defaultValue, 'off'); - assert.equal(actual.globalValue, 'on'); - assert.equal(actual.workspaceValue, undefined); - assert.equal(actual.workspaceFolderValue, undefined); + assert.strictEqual(actual.defaultValue, 'off'); + assert.strictEqual(actual.globalValue, 'on'); + assert.strictEqual(actual.workspaceValue, undefined); + assert.strictEqual(actual.workspaceFolderValue, undefined); }); test('inspect in single root context', function () { @@ -341,28 +341,28 @@ suite('ExtHostConfiguration', function () { ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; - assert.equal(actual1.defaultValue, 'off'); - assert.equal(actual1.globalValue, 'on'); - assert.equal(actual1.workspaceValue, 'bounded'); - assert.equal(actual1.workspaceFolderValue, undefined); + assert.strictEqual(actual1.defaultValue, 'off'); + assert.strictEqual(actual1.globalValue, 'on'); + assert.strictEqual(actual1.workspaceValue, 'bounded'); + assert.strictEqual(actual1.workspaceFolderValue, undefined); actual1 = testObject.getConfiguration('editor').inspect('wordWrap')!; - assert.equal(actual1.defaultValue, 'off'); - assert.equal(actual1.globalValue, 'on'); - assert.equal(actual1.workspaceValue, 'bounded'); - assert.equal(actual1.workspaceFolderValue, undefined); + assert.strictEqual(actual1.defaultValue, 'off'); + assert.strictEqual(actual1.globalValue, 'on'); + assert.strictEqual(actual1.workspaceValue, 'bounded'); + assert.strictEqual(actual1.workspaceFolderValue, undefined); let actual2 = testObject.getConfiguration(undefined, workspaceUri).inspect('editor.wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'bounded'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'bounded'); actual2 = testObject.getConfiguration('editor', workspaceUri).inspect('wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'bounded'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'bounded'); }); test('inspect in multi root context', function () { @@ -418,66 +418,66 @@ suite('ExtHostConfiguration', function () { ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; - assert.equal(actual1.defaultValue, 'off'); - assert.equal(actual1.globalValue, 'on'); - assert.equal(actual1.workspaceValue, 'bounded'); - assert.equal(actual1.workspaceFolderValue, undefined); + assert.strictEqual(actual1.defaultValue, 'off'); + assert.strictEqual(actual1.globalValue, 'on'); + assert.strictEqual(actual1.workspaceValue, 'bounded'); + assert.strictEqual(actual1.workspaceFolderValue, undefined); actual1 = testObject.getConfiguration('editor').inspect('wordWrap')!; - assert.equal(actual1.defaultValue, 'off'); - assert.equal(actual1.globalValue, 'on'); - assert.equal(actual1.workspaceValue, 'bounded'); - assert.equal(actual1.workspaceFolderValue, undefined); + assert.strictEqual(actual1.defaultValue, 'off'); + assert.strictEqual(actual1.globalValue, 'on'); + assert.strictEqual(actual1.workspaceValue, 'bounded'); + assert.strictEqual(actual1.workspaceFolderValue, undefined); actual1 = testObject.getConfiguration('editor').inspect('lineNumbers')!; - assert.equal(actual1.defaultValue, 'on'); - assert.equal(actual1.globalValue, undefined); - assert.equal(actual1.workspaceValue, undefined); - assert.equal(actual1.workspaceFolderValue, undefined); + assert.strictEqual(actual1.defaultValue, 'on'); + assert.strictEqual(actual1.globalValue, undefined); + assert.strictEqual(actual1.workspaceValue, undefined); + assert.strictEqual(actual1.workspaceFolderValue, undefined); let actual2 = testObject.getConfiguration(undefined, firstRoot).inspect('editor.wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'off'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'off'); actual2 = testObject.getConfiguration('editor', firstRoot).inspect('wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'off'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'off'); actual2 = testObject.getConfiguration('editor', firstRoot).inspect('lineNumbers')!; - assert.equal(actual2.defaultValue, 'on'); - assert.equal(actual2.globalValue, undefined); - assert.equal(actual2.workspaceValue, undefined); - assert.equal(actual2.workspaceFolderValue, 'relative'); + assert.strictEqual(actual2.defaultValue, 'on'); + assert.strictEqual(actual2.globalValue, undefined); + assert.strictEqual(actual2.workspaceValue, undefined); + assert.strictEqual(actual2.workspaceFolderValue, 'relative'); actual2 = testObject.getConfiguration(undefined, secondRoot).inspect('editor.wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'on'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'on'); actual2 = testObject.getConfiguration('editor', secondRoot).inspect('wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); - assert.equal(actual2.workspaceFolderValue, 'on'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.workspaceFolderValue, 'on'); actual2 = testObject.getConfiguration(undefined, thirdRoot).inspect('editor.wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); assert.ok(Object.keys(actual2).indexOf('workspaceFolderValue') !== -1); - assert.equal(actual2.workspaceFolderValue, undefined); + assert.strictEqual(actual2.workspaceFolderValue, undefined); actual2 = testObject.getConfiguration('editor', thirdRoot).inspect('wordWrap')!; - assert.equal(actual2.defaultValue, 'off'); - assert.equal(actual2.globalValue, 'on'); - assert.equal(actual2.workspaceValue, 'bounded'); + assert.strictEqual(actual2.defaultValue, 'off'); + assert.strictEqual(actual2.globalValue, 'on'); + assert.strictEqual(actual2.workspaceValue, 'bounded'); assert.ok(Object.keys(actual2).indexOf('workspaceFolderValue') !== -1); - assert.equal(actual2.workspaceFolderValue, undefined); + assert.strictEqual(actual2.workspaceFolderValue, undefined); }); test('inspect with language overrides', function () { @@ -527,26 +527,26 @@ suite('ExtHostConfiguration', function () { ); let actual = testObject.getConfiguration(undefined, { uri: firstRoot, languageId: 'typescript' }).inspect('editor.wordWrap')!; - assert.equal(actual.defaultValue, 'off'); - assert.equal(actual.globalValue, 'bounded'); - assert.equal(actual.workspaceValue, undefined); - assert.equal(actual.workspaceFolderValue, 'bounded'); - assert.equal(actual.defaultLanguageValue, undefined); - assert.equal(actual.globalLanguageValue, undefined); - assert.equal(actual.workspaceLanguageValue, 'unbounded'); - assert.equal(actual.workspaceFolderLanguageValue, 'unbounded'); - assert.deepEqual(actual.languageIds, ['markdown', 'typescript']); + assert.strictEqual(actual.defaultValue, 'off'); + assert.strictEqual(actual.globalValue, 'bounded'); + assert.strictEqual(actual.workspaceValue, undefined); + assert.strictEqual(actual.workspaceFolderValue, 'bounded'); + assert.strictEqual(actual.defaultLanguageValue, undefined); + assert.strictEqual(actual.globalLanguageValue, undefined); + assert.strictEqual(actual.workspaceLanguageValue, 'unbounded'); + assert.strictEqual(actual.workspaceFolderLanguageValue, 'unbounded'); + assert.deepStrictEqual(actual.languageIds, ['markdown', 'typescript']); actual = testObject.getConfiguration(undefined, { uri: secondRoot, languageId: 'typescript' }).inspect('editor.wordWrap')!; - assert.equal(actual.defaultValue, 'off'); - assert.equal(actual.globalValue, 'bounded'); - assert.equal(actual.workspaceValue, undefined); - assert.equal(actual.workspaceFolderValue, undefined); - assert.equal(actual.defaultLanguageValue, undefined); - assert.equal(actual.globalLanguageValue, undefined); - assert.equal(actual.workspaceLanguageValue, 'unbounded'); - assert.equal(actual.workspaceFolderLanguageValue, undefined); - assert.deepEqual(actual.languageIds, ['markdown', 'typescript']); + assert.strictEqual(actual.defaultValue, 'off'); + assert.strictEqual(actual.globalValue, 'bounded'); + assert.strictEqual(actual.workspaceValue, undefined); + assert.strictEqual(actual.workspaceFolderValue, undefined); + assert.strictEqual(actual.defaultLanguageValue, undefined); + assert.strictEqual(actual.globalLanguageValue, undefined); + assert.strictEqual(actual.workspaceLanguageValue, 'unbounded'); + assert.strictEqual(actual.workspaceFolderLanguageValue, undefined); + assert.deepStrictEqual(actual.languageIds, ['markdown', 'typescript']); }); @@ -560,12 +560,12 @@ suite('ExtHostConfiguration', function () { }); let config = all.getConfiguration('farboo.config0'); - assert.equal(config.get(''), undefined); - assert.equal(config.has(''), false); + assert.strictEqual(config.get(''), undefined); + assert.strictEqual(config.has(''), false); config = all.getConfiguration('farboo'); - assert.equal(config.get('config0'), true); - assert.equal(config.has('config0'), true); + assert.strictEqual(config.get('config0'), true); + assert.strictEqual(config.has('config0'), true); }); test('getConfiguration vs get', function () { @@ -578,12 +578,12 @@ suite('ExtHostConfiguration', function () { }); let config = all.getConfiguration('farboo.config0'); - assert.equal(config.get(''), undefined); - assert.equal(config.has(''), false); + assert.strictEqual(config.get(''), undefined); + assert.strictEqual(config.has(''), false); config = all.getConfiguration('farboo'); - assert.equal(config.get('config0'), true); - assert.equal(config.has('config0'), true); + assert.strictEqual(config.get('config0'), true); + assert.strictEqual(config.has('config0'), true); }); test('name vs property', function () { @@ -595,8 +595,8 @@ suite('ExtHostConfiguration', function () { const config = all.getConfiguration('farboo'); assert.ok(config.has('get')); - assert.equal(config.get('get'), 'get-prop'); - assert.deepEqual(config['get'], config.get); + assert.strictEqual(config.get('get'), 'get-prop'); + assert.deepStrictEqual(config['get'], config.get); assert.throws(() => config['get'] = 'get-prop'); }); @@ -612,7 +612,7 @@ suite('ExtHostConfiguration', function () { let config = allConfig.getConfiguration('foo'); config.update('bar', 42); - assert.equal(shape.lastArgs[0], null); + assert.strictEqual(shape.lastArgs[0], null); }); test('update/section to key', function () { @@ -628,16 +628,16 @@ suite('ExtHostConfiguration', function () { let config = allConfig.getConfiguration('foo'); config.update('bar', 42, true); - assert.equal(shape.lastArgs[0], ConfigurationTarget.USER); - assert.equal(shape.lastArgs[1], 'foo.bar'); - assert.equal(shape.lastArgs[2], 42); + assert.strictEqual(shape.lastArgs[0], ConfigurationTarget.USER); + assert.strictEqual(shape.lastArgs[1], 'foo.bar'); + assert.strictEqual(shape.lastArgs[2], 42); config = allConfig.getConfiguration(''); config.update('bar', 42, true); - assert.equal(shape.lastArgs[1], 'bar'); + assert.strictEqual(shape.lastArgs[1], 'bar'); config.update('foo.bar', 42, true); - assert.equal(shape.lastArgs[1], 'foo.bar'); + assert.strictEqual(shape.lastArgs[1], 'foo.bar'); }); test('update, what is #15834', function () { @@ -649,8 +649,8 @@ suite('ExtHostConfiguration', function () { }, shape); allConfig.getConfiguration('editor').update('formatOnSave', { extensions: ['ts'] }); - assert.equal(shape.lastArgs[1], 'editor.formatOnSave'); - assert.deepEqual(shape.lastArgs[2], { extensions: ['ts'] }); + assert.strictEqual(shape.lastArgs[1], 'editor.formatOnSave'); + assert.deepStrictEqual(shape.lastArgs[2], { extensions: ['ts'] }); }); test('update/error-state not OK', function () { @@ -698,7 +698,7 @@ suite('ExtHostConfiguration', function () { const configEventData: IConfigurationChange = { keys: ['farboo.updatedConfig', 'farboo.newConfig'], overrides: [] }; testObject.onDidChangeConfiguration(e => { - assert.deepEqual(testObject.getConfiguration().get('farboo'), { + assert.deepStrictEqual(testObject.getConfiguration().get('farboo'), { 'config': false, 'updatedConfig': true, 'newConfig': true, diff --git a/src/vs/workbench/test/browser/api/extHostDecorations.test.ts b/src/vs/workbench/test/browser/api/extHostDecorations.test.ts index 4e78842c7662..0c926b504105 100644 --- a/src/vs/workbench/test/browser/api/extHostDecorations.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDecorations.test.ts @@ -68,17 +68,17 @@ suite('ExtHostDecorations', function () { return extHostDecorations.$provideDecorations(handle, [{ id: idx, uri: URI.parse('test:///file') }], CancellationToken.None); }); - assert.equal(calledA, true); - assert.equal(calledB, true); + assert.strictEqual(calledA, true); + assert.strictEqual(calledB, true); - assert.equal(requests.length, 2); + assert.strictEqual(requests.length, 2); const [first, second] = requests; const firstResult = await Promise.race([first, timeout(30).then(() => false)]); - assert.equal(typeof firstResult, 'boolean'); // never finishes... + assert.strictEqual(typeof firstResult, 'boolean'); // never finishes... const secondResult = await Promise.race([second, timeout(30).then(() => false)]); - assert.equal(typeof secondResult, 'object'); + assert.strictEqual(typeof secondResult, 'object'); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostDiagnostics.test.ts b/src/vs/workbench/test/browser/api/extHostDiagnostics.test.ts index db7351cfcb71..68fd8bca049c 100644 --- a/src/vs/workbench/test/browser/api/extHostDiagnostics.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDiagnostics.test.ts @@ -45,26 +45,26 @@ suite('ExtHostDiagnostics', () => { test('diagnostic collection, forEach, clear, has', function () { let collection = new DiagnosticCollection('test', 'test', 100, new DiagnosticsShape(), new Emitter()); - assert.equal(collection.name, 'test'); + assert.strictEqual(collection.name, 'test'); collection.dispose(); assert.throws(() => collection.name); let c = 0; collection = new DiagnosticCollection('test', 'test', 100, new DiagnosticsShape(), new Emitter()); collection.forEach(() => c++); - assert.equal(c, 0); + assert.strictEqual(c, 0); collection.set(URI.parse('foo:bar'), [ new Diagnostic(new Range(0, 0, 1, 1), 'message-1'), new Diagnostic(new Range(0, 0, 1, 1), 'message-2') ]); collection.forEach(() => c++); - assert.equal(c, 1); + assert.strictEqual(c, 1); c = 0; collection.clear(); collection.forEach(() => c++); - assert.equal(c, 0); + assert.strictEqual(c, 0); collection.set(URI.parse('foo:bar1'), [ new Diagnostic(new Range(0, 0, 1, 1), 'message-1'), @@ -75,7 +75,7 @@ suite('ExtHostDiagnostics', () => { new Diagnostic(new Range(0, 0, 1, 1), 'message-2') ]); collection.forEach(() => c++); - assert.equal(c, 2); + assert.strictEqual(c, 2); assert.ok(collection.has(URI.parse('foo:bar1'))); assert.ok(collection.has(URI.parse('foo:bar2'))); @@ -105,7 +105,7 @@ suite('ExtHostDiagnostics', () => { }); array = collection.get(URI.parse('foo:bar')) as Diagnostic[]; - assert.equal(array.length, 2); + assert.strictEqual(array.length, 2); collection.dispose(); }); @@ -121,10 +121,10 @@ suite('ExtHostDiagnostics', () => { ]); let array = collection.get(uri); - assert.equal(array.length, 2); + assert.strictEqual(array.length, 2); let [first, second] = array; - assert.equal(first.message, 'message-1'); - assert.equal(second.message, 'message-2'); + assert.strictEqual(first.message, 'message-1'); + assert.strictEqual(second.message, 'message-2'); // clear collection.delete(uri); @@ -152,10 +152,10 @@ suite('ExtHostDiagnostics', () => { ]); array = collection.get(uri); - assert.equal(array.length, 2); + assert.strictEqual(array.length, 2); [first, second] = array; - assert.equal(first.message, 'message-2'); - assert.equal(second.message, 'message-3'); + assert.strictEqual(first.message, 'message-2'); + assert.strictEqual(second.message, 'message-3'); collection.dispose(); }); @@ -172,21 +172,21 @@ suite('ExtHostDiagnostics', () => { let uri = URI.parse('sc:hightower'); collection.set([[uri, [new Diagnostic(new Range(0, 0, 1, 1), 'error')]]]); - assert.equal(collection.get(uri).length, 1); - assert.equal(collection.get(uri)[0].message, 'error'); - assert.equal(lastEntries.length, 1); + assert.strictEqual(collection.get(uri).length, 1); + assert.strictEqual(collection.get(uri)[0].message, 'error'); + assert.strictEqual(lastEntries.length, 1); let [[, data1]] = lastEntries; - assert.equal(data1.length, 1); - assert.equal(data1[0].message, 'error'); + assert.strictEqual(data1.length, 1); + assert.strictEqual(data1[0].message, 'error'); lastEntries = undefined!; collection.set([[uri, [new Diagnostic(new Range(0, 0, 1, 1), 'warning')]]]); - assert.equal(collection.get(uri).length, 1); - assert.equal(collection.get(uri)[0].message, 'warning'); - assert.equal(lastEntries.length, 1); + assert.strictEqual(collection.get(uri).length, 1); + assert.strictEqual(collection.get(uri)[0].message, 'warning'); + assert.strictEqual(lastEntries.length, 1); let [[, data2]] = lastEntries; - assert.equal(data2.length, 1); - assert.equal(data2[0].message, 'warning'); + assert.strictEqual(data2.length, 1); + assert.strictEqual(data2[0].message, 'warning'); lastEntries = undefined!; }); @@ -207,12 +207,12 @@ suite('ExtHostDiagnostics', () => { let diag = new Diagnostic(new Range(0, 0, 0, 1), 'ffff'); collection.set(uri, [diag]); - assert.equal(changeCount, 1); - assert.equal(eventCount, 1); + assert.strictEqual(changeCount, 1); + assert.strictEqual(eventCount, 1); collection.set(uri, [diag]); - assert.equal(changeCount, 2); - assert.equal(eventCount, 2); + assert.strictEqual(changeCount, 2); + assert.strictEqual(eventCount, 2); }); test('diagnostics collection, tuples and undefined (small array), #15585', function () { @@ -232,8 +232,8 @@ suite('ExtHostDiagnostics', () => { [uri2, [diag]], ]); - assert.equal(collection.get(uri).length, 1); - assert.equal(collection.get(uri2).length, 1); + assert.strictEqual(collection.get(uri).length, 1); + assert.strictEqual(collection.get(uri2).length, 1); }); test('diagnostics collection, tuples and undefined (large array), #15585', function () { @@ -254,8 +254,8 @@ suite('ExtHostDiagnostics', () => { for (let i = 0; i < 500; i++) { let uri = URI.parse('sc:hightower#' + i); - assert.equal(collection.has(uri), true); - assert.equal(collection.get(uri).length, 1); + assert.strictEqual(collection.has(uri), true); + assert.strictEqual(collection.get(uri).length, 1); } }); @@ -278,12 +278,12 @@ suite('ExtHostDiagnostics', () => { } collection.set(uri, diagnostics); - assert.equal(collection.get(uri).length, 500); - assert.equal(lastEntries.length, 1); - assert.equal(lastEntries[0][1].length, 251); - assert.equal(lastEntries[0][1][0].severity, MarkerSeverity.Error); - assert.equal(lastEntries[0][1][200].severity, MarkerSeverity.Warning); - assert.equal(lastEntries[0][1][250].severity, MarkerSeverity.Info); + assert.strictEqual(collection.get(uri).length, 500); + assert.strictEqual(lastEntries.length, 1); + assert.strictEqual(lastEntries[0][1].length, 251); + assert.strictEqual(lastEntries[0][1][0].severity, MarkerSeverity.Error); + assert.strictEqual(lastEntries[0][1][200].severity, MarkerSeverity.Warning); + assert.strictEqual(lastEntries[0][1][250].severity, MarkerSeverity.Info); }); test('diagnostic eventing', async function () { @@ -295,19 +295,19 @@ suite('ExtHostDiagnostics', () => { let diag3 = new Diagnostic(new Range(1, 1, 2, 3), 'diag3'); let p = Event.toPromise(emitter.event).then(a => { - assert.equal(a.length, 1); - assert.equal(a[0].toString(), 'aa:bb'); + assert.strictEqual(a.length, 1); + assert.strictEqual(a[0].toString(), 'aa:bb'); assert.ok(URI.isUri(a[0])); }); collection.set(URI.parse('aa:bb'), []); await p; p = Event.toPromise(emitter.event).then(e => { - assert.equal(e.length, 2); + assert.strictEqual(e.length, 2); assert.ok(URI.isUri(e[0])); assert.ok(URI.isUri(e[1])); - assert.equal(e[0].toString(), 'aa:bb'); - assert.equal(e[1].toString(), 'aa:cc'); + assert.strictEqual(e[0].toString(), 'aa:bb'); + assert.strictEqual(e[1].toString(), 'aa:cc'); }); collection.set([ [URI.parse('aa:bb'), [diag1]], @@ -316,7 +316,7 @@ suite('ExtHostDiagnostics', () => { await p; p = Event.toPromise(emitter.event).then(e => { - assert.equal(e.length, 2); + assert.strictEqual(e.length, 2); assert.ok(URI.isUri(e[0])); assert.ok(URI.isUri(e[1])); }); @@ -333,7 +333,7 @@ suite('ExtHostDiagnostics', () => { // delete collection.set(URI.parse('aa:bb'), [diag1]); let p = Event.toPromise(emitter.event).then(e => { - assert.equal(e[0].toString(), 'aa:bb'); + assert.strictEqual(e[0].toString(), 'aa:bb'); }); collection.delete(URI.parse('aa:bb')); await p; @@ -341,7 +341,7 @@ suite('ExtHostDiagnostics', () => { // set->undefined (as delete) collection.set(URI.parse('aa:bb'), [diag1]); p = Event.toPromise(emitter.event).then(e => { - assert.equal(e[0].toString(), 'aa:bb'); + assert.strictEqual(e[0].toString(), 'aa:bb'); }); collection.set(URI.parse('aa:bb'), undefined!); await p; @@ -353,13 +353,13 @@ suite('ExtHostDiagnostics', () => { $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]) { let [[, data]] = entries; - assert.equal(entries.length, 1); - assert.equal(data.length, 1); + assert.strictEqual(entries.length, 1); + assert.strictEqual(data.length, 1); let [diag] = data; - assert.equal(diag.relatedInformation!.length, 2); - assert.equal(diag.relatedInformation![0].message, 'more1'); - assert.equal(diag.relatedInformation![1].message, 'more2'); + assert.strictEqual(diag.relatedInformation!.length, 2); + assert.strictEqual(diag.relatedInformation![0].message, 'more1'); + assert.strictEqual(diag.relatedInformation![1].message, 'more2'); done(); } }, new Emitter()); @@ -400,9 +400,9 @@ suite('ExtHostDiagnostics', () => { collection1.clear(); collection2.clear(); - assert.equal(ownerHistory.length, 2); - assert.equal(ownerHistory[0], 'foo'); - assert.equal(ownerHistory[1], 'foo0'); + assert.strictEqual(ownerHistory.length, 2); + assert.strictEqual(ownerHistory[0], 'foo'); + assert.strictEqual(ownerHistory[1], 'foo0'); }); test('Error updating diagnostics from extension #60394', function () { @@ -420,14 +420,14 @@ suite('ExtHostDiagnostics', () => { array.push(diag1, diag2); collection.set(URI.parse('test:me'), array); - assert.equal(callCount, 1); + assert.strictEqual(callCount, 1); collection.set(URI.parse('test:me'), array); - assert.equal(callCount, 2); // equal array + assert.strictEqual(callCount, 2); // equal array array.push(diag2); collection.set(URI.parse('test:me'), array); - assert.equal(callCount, 3); // same but un-equal array + assert.strictEqual(callCount, 3); // same but un-equal array }); test('Diagnostics created by tasks aren\'t accessible to extensions #47292', async function () { @@ -461,11 +461,11 @@ suite('ExtHostDiagnostics', () => { const p1 = Event.toPromise(diags.onDidChangeDiagnostics); diags.$acceptMarkersChange([[uri, data]]); await p1; - assert.equal(diags.getDiagnostics(uri).length, 1); + assert.strictEqual(diags.getDiagnostics(uri).length, 1); const p2 = Event.toPromise(diags.onDidChangeDiagnostics); diags.$acceptMarkersChange([[uri, []]]); await p2; - assert.equal(diags.getDiagnostics(uri).length, 0); + assert.strictEqual(diags.getDiagnostics(uri).length, 0); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostDocumentData.test.ts b/src/vs/workbench/test/browser/api/extHostDocumentData.test.ts index 4519c6154fc7..9de6d4235f3b 100644 --- a/src/vs/workbench/test/browser/api/extHostDocumentData.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDocumentData.test.ts @@ -19,14 +19,14 @@ suite('ExtHostDocumentData', () => { function assertPositionAt(offset: number, line: number, character: number) { let position = data.document.positionAt(offset); - assert.equal(position.line, line); - assert.equal(position.character, character); + assert.strictEqual(position.line, line); + assert.strictEqual(position.character, character); } function assertOffsetAt(line: number, character: number, offset: number) { let pos = new Position(line, character); let actual = data.document.offsetAt(pos); - assert.equal(actual, offset); + assert.strictEqual(actual, offset); } setup(function () { @@ -58,7 +58,7 @@ suite('ExtHostDocumentData', () => { }, URI.parse('foo:bar'), [], '\n', 1, 'text', true); return data.document.save().then(() => { - assert.equal(saved.toString(), 'foo:bar'); + assert.strictEqual(saved.toString(), 'foo:bar'); data.dispose(); @@ -74,13 +74,13 @@ suite('ExtHostDocumentData', () => { data.dispose(); const { document } = data; - assert.equal(document.lineCount, 4); - assert.equal(document.lineAt(0).text, 'This is line one'); + assert.strictEqual(document.lineCount, 4); + assert.strictEqual(document.lineAt(0).text, 'This is line one'); }); test('lines', () => { - assert.equal(data.document.lineCount, 4); + assert.strictEqual(data.document.lineCount, 4); assert.throws(() => data.document.lineAt(-1)); assert.throws(() => data.document.lineAt(data.document.lineCount)); @@ -89,11 +89,11 @@ suite('ExtHostDocumentData', () => { assert.throws(() => data.document.lineAt(0.8)); let line = data.document.lineAt(0); - assert.equal(line.lineNumber, 0); - assert.equal(line.text.length, 16); - assert.equal(line.text, 'This is line one'); - assert.equal(line.isEmptyOrWhitespace, false); - assert.equal(line.firstNonWhitespaceCharacterIndex, 0); + assert.strictEqual(line.lineNumber, 0); + assert.strictEqual(line.text.length, 16); + assert.strictEqual(line.text, 'This is line one'); + assert.strictEqual(line.isEmptyOrWhitespace, false); + assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 0); data.onEvents({ changes: [{ @@ -107,31 +107,31 @@ suite('ExtHostDocumentData', () => { }); // line didn't change - assert.equal(line.text, 'This is line one'); - assert.equal(line.firstNonWhitespaceCharacterIndex, 0); + assert.strictEqual(line.text, 'This is line one'); + assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 0); // fetch line again line = data.document.lineAt(0); - assert.equal(line.text, '\t This is line one'); - assert.equal(line.firstNonWhitespaceCharacterIndex, 2); + assert.strictEqual(line.text, '\t This is line one'); + assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 2); }); test('line, issue #5704', function () { let line = data.document.lineAt(0); let { range, rangeIncludingLineBreak } = line; - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 16); - assert.equal(rangeIncludingLineBreak.end.line, 1); - assert.equal(rangeIncludingLineBreak.end.character, 0); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.end.character, 16); + assert.strictEqual(rangeIncludingLineBreak.end.line, 1); + assert.strictEqual(rangeIncludingLineBreak.end.character, 0); line = data.document.lineAt(data.document.lineCount - 1); range = line.range; rangeIncludingLineBreak = line.rangeIncludingLineBreak; - assert.equal(range.end.line, 3); - assert.equal(range.end.character, 29); - assert.equal(rangeIncludingLineBreak.end.line, 3); - assert.equal(rangeIncludingLineBreak.end.character, 29); + assert.strictEqual(range.end.line, 3); + assert.strictEqual(range.end.character, 29); + assert.strictEqual(rangeIncludingLineBreak.end.line, 3); + assert.strictEqual(rangeIncludingLineBreak.end.character, 29); }); @@ -245,28 +245,28 @@ suite('ExtHostDocumentData', () => { ], '\n', 1, 'text', false); let range = data.document.getWordRangeAtPosition(new Position(0, 2))!; - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 0); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 4); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.start.character, 0); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.end.character, 4); // ignore bad regular expresson /.*/ assert.throws(() => data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!); range = data.document.getWordRangeAtPosition(new Position(0, 5), /[a-z+]+/)!; - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 5); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 14); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.start.character, 5); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.end.character, 14); range = data.document.getWordRangeAtPosition(new Position(0, 17), /[a-z+]+/)!; - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 15); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 18); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.start.character, 15); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.end.character, 18); range = data.document.getWordRangeAtPosition(new Position(0, 11), /yy/)!; - assert.equal(range, undefined); + assert.strictEqual(range, undefined); }); test('getWordRangeAtPosition doesn\'t quite use the regex as expected, #29102', function () { @@ -279,22 +279,22 @@ suite('ExtHostDocumentData', () => { ], '\n', 1, 'text', false); let range = data.document.getWordRangeAtPosition(new Position(0, 0), /\/\*.+\*\//); - assert.equal(range, undefined); + assert.strictEqual(range, undefined); range = data.document.getWordRangeAtPosition(new Position(1, 0), /\/\*.+\*\//)!; - assert.equal(range.start.line, 1); - assert.equal(range.start.character, 0); - assert.equal(range.end.line, 1); - assert.equal(range.end.character, 14); + assert.strictEqual(range.start.line, 1); + assert.strictEqual(range.start.character, 0); + assert.strictEqual(range.end.line, 1); + assert.strictEqual(range.end.character, 14); range = data.document.getWordRangeAtPosition(new Position(3, 0), /("|').*\1/); - assert.equal(range, undefined); + assert.strictEqual(range, undefined); range = data.document.getWordRangeAtPosition(new Position(3, 1), /("|').*\1/)!; - assert.equal(range.start.line, 3); - assert.equal(range.start.character, 1); - assert.equal(range.end.line, 3); - assert.equal(range.end.character, 10); + assert.strictEqual(range.start.line, 3); + assert.strictEqual(range.start.character, 1); + assert.strictEqual(range.end.line, 3); + assert.strictEqual(range.end.character, 10); }); @@ -307,13 +307,13 @@ suite('ExtHostDocumentData', () => { ], '\n', 1, 'text', false); let range = data.document.getWordRangeAtPosition(new Position(0, 1_177_170), regex)!; - assert.equal(range, undefined); + assert.strictEqual(range, undefined); const pos = new Position(0, 1177170); range = data.document.getWordRangeAtPosition(pos)!; assert.ok(range); assert.ok(range.contains(pos)); - assert.equal(data.document.getText(range), 'TaskDefinition'); + assert.strictEqual(data.document.getText(range), 'TaskDefinition'); }); test('Rename popup sometimes populates with text on the left side omitted #96013', function () { @@ -326,10 +326,10 @@ suite('ExtHostDocumentData', () => { ], '\n', 1, 'text', false); let range = data.document.getWordRangeAtPosition(new Position(0, 27), regex)!; - assert.equal(range.start.line, 0); - assert.equal(range.end.line, 0); - assert.equal(range.start.character, 4); - assert.equal(range.end.character, 28); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.start.character, 4); + assert.strictEqual(range.end.character, 28); }); test('Custom snippet $TM_SELECTED_TEXT not show suggestion #108892', function () { @@ -340,11 +340,11 @@ suite('ExtHostDocumentData', () => { const pos = new Position(0, 55); const range = data.document.getWordRangeAtPosition(pos)!; - assert.equal(range.start.line, 0); - assert.equal(range.end.line, 0); - assert.equal(range.start.character, 47); - assert.equal(range.end.character, 61); - assert.equal(data.document.getText(range), 'soprannominato'); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.end.line, 0); + assert.strictEqual(range.start.character, 47); + assert.strictEqual(range.end.character, 61); + assert.strictEqual(data.document.getText(range), 'soprannominato'); }); }); @@ -365,7 +365,7 @@ suite('ExtHostDocumentData updates line mapping', () => { let line = 0, character = 0, previousIsCarriageReturn = false; for (let offset = 0; offset <= allText.length; offset++) { // The position coordinate system cannot express the position between \r and \n - let position = new Position(line, character + (previousIsCarriageReturn ? -1 : 0)); + const position = new Position(line, character + (previousIsCarriageReturn ? -1 : 0)); if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) { let actualPosition = doc.document.positionAt(offset); diff --git a/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts index 8220fcf97aa9..a89f12a7a19c 100644 --- a/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts @@ -68,8 +68,8 @@ suite('ExtHostDocumentSaveParticipant', () => { sub.dispose(); assert.ok(event); - assert.equal(event.reason, TextDocumentSaveReason.Manual); - assert.equal(typeof event.waitUntil, 'function'); + assert.strictEqual(event.reason, TextDocumentSaveReason.Manual); + assert.strictEqual(typeof event.waitUntil, 'function'); }); }); @@ -100,7 +100,7 @@ suite('ExtHostDocumentSaveParticipant', () => { sub.dispose(); const [first] = values; - assert.equal(first, false); + assert.strictEqual(first, false); }); }); @@ -128,11 +128,11 @@ suite('ExtHostDocumentSaveParticipant', () => { let counter = 0; let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) { - assert.equal(counter++, 0); + assert.strictEqual(counter++, 0); }); let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) { - assert.equal(counter++, 1); + assert.strictEqual(counter++, 1); }); return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => { @@ -156,7 +156,7 @@ suite('ExtHostDocumentSaveParticipant', () => { await participant.$participateInSave(resource, SaveReason.EXPLICIT); sub.dispose(); - assert.equal(callCount, 2); + assert.strictEqual(callCount, 2); }); test('event delivery, overall timeout', () => { @@ -182,8 +182,8 @@ suite('ExtHostDocumentSaveParticipant', () => { sub2.dispose(); sub3.dispose(); - assert.equal(callCount, 2); - assert.equal(values.length, 2); + assert.strictEqual(callCount, 2); + assert.strictEqual(values.length, 2); }); }); @@ -238,7 +238,7 @@ suite('ExtHostDocumentSaveParticipant', () => { sub.dispose(); const [first] = values; - assert.equal(first, false); + assert.strictEqual(first, false); }); }); @@ -279,7 +279,7 @@ suite('ExtHostDocumentSaveParticipant', () => { return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => { sub.dispose(); - assert.equal(dto.edits.length, 2); + assert.strictEqual(dto.edits.length, 2); assert.ok((dto.edits[0]).edit); assert.ok((dto.edits[1]).edit); }); @@ -315,8 +315,8 @@ suite('ExtHostDocumentSaveParticipant', () => { return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => { sub.dispose(); - assert.equal(edits, undefined); - assert.equal(values[0], false); + assert.strictEqual(edits, undefined); + assert.strictEqual(values[0], false); }); }); @@ -351,16 +351,16 @@ suite('ExtHostDocumentSaveParticipant', () => { let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) { // the document state we started with - assert.equal(document.version, 1); - assert.equal(document.getText(), 'foo'); + assert.strictEqual(document.version, 1); + assert.strictEqual(document.getText(), 'foo'); e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')])); }); let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) { // the document state AFTER the first listener kicked in - assert.equal(document.version, 2); - assert.equal(document.getText(), 'barfoo'); + assert.strictEqual(document.version, 2); + assert.strictEqual(document.getText(), 'barfoo'); e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')])); }); @@ -370,8 +370,8 @@ suite('ExtHostDocumentSaveParticipant', () => { sub2.dispose(); // the document state AFTER eventing is done - assert.equal(document.version, 3); - assert.equal(document.getText(), 'barbarfoo'); + assert.strictEqual(document.version, 3); + assert.strictEqual(document.getText(), 'barbarfoo'); }); }); @@ -391,7 +391,7 @@ suite('ExtHostDocumentSaveParticipant', () => { return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => { sub.dispose(); - assert.equal(didLogSomething, true); + assert.strictEqual(didLogSomething, true); }); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostDocumentsAndEditors.test.ts b/src/vs/workbench/test/browser/api/extHostDocumentsAndEditors.test.ts index e3f031a03b21..6456bae1d430 100644 --- a/src/vs/workbench/test/browser/api/extHostDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/browser/api/extHostDocumentsAndEditors.test.ts @@ -39,7 +39,7 @@ suite('ExtHostDocumentsAndEditors', () => { try { for (const data of e) { - assert.equal(data.document.isClosed, true); + assert.strictEqual(data.document.isClosed, true); } resolve(undefined); } catch (e) { diff --git a/src/vs/workbench/test/browser/api/extHostFileSystemEventService.test.ts b/src/vs/workbench/test/browser/api/extHostFileSystemEventService.test.ts index 0d26033abf7f..805e8f4e19a3 100644 --- a/src/vs/workbench/test/browser/api/extHostFileSystemEventService.test.ts +++ b/src/vs/workbench/test/browser/api/extHostFileSystemEventService.test.ts @@ -20,14 +20,14 @@ suite('ExtHostFileSystemEventService', () => { }; const watcher1 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher('**/somethingInteresting', false, false, false); - assert.equal(watcher1.ignoreChangeEvents, false); - assert.equal(watcher1.ignoreCreateEvents, false); - assert.equal(watcher1.ignoreDeleteEvents, false); + assert.strictEqual(watcher1.ignoreChangeEvents, false); + assert.strictEqual(watcher1.ignoreCreateEvents, false); + assert.strictEqual(watcher1.ignoreDeleteEvents, false); const watcher2 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher('**/somethingBoring', true, true, true); - assert.equal(watcher2.ignoreChangeEvents, true); - assert.equal(watcher2.ignoreCreateEvents, true); - assert.equal(watcher2.ignoreDeleteEvents, true); + assert.strictEqual(watcher2.ignoreChangeEvents, true); + assert.strictEqual(watcher2.ignoreCreateEvents, true); + assert.strictEqual(watcher2.ignoreDeleteEvents, true); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts index 7e96409abc62..44aec4a9030f 100644 --- a/src/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts @@ -127,7 +127,7 @@ suite('ExtHostLanguageFeatures', function () { // --- outline test('DocumentSymbols, register/deregister', async () => { - assert.equal(modes.DocumentSymbolProviderRegistry.all(model).length, 0); + assert.strictEqual(modes.DocumentSymbolProviderRegistry.all(model).length, 0); let d1 = extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentSymbolProvider { provideDocumentSymbols() { return []; @@ -135,7 +135,7 @@ suite('ExtHostLanguageFeatures', function () { }); await rpcProtocol.sync(); - assert.equal(modes.DocumentSymbolProviderRegistry.all(model).length, 1); + assert.strictEqual(modes.DocumentSymbolProviderRegistry.all(model).length, 1); d1.dispose(); return rpcProtocol.sync(); @@ -155,7 +155,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getDocumentSymbols(model, true, CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); }); test('DocumentSymbols, data conversion', async () => { @@ -167,10 +167,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getDocumentSymbols(model, true, CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let entry = value[0]; - assert.equal(entry.name, 'test'); - assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(entry.name, 'test'); + assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); }); // --- code lens @@ -190,7 +190,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensModel(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); + assert.strictEqual(value.lenses.length, 1); }); test('CodeLens, do not resolve a resolved lens', async () => { @@ -208,11 +208,11 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensModel(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); + assert.strictEqual(value.lenses.length, 1); const [data] = value.lenses; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); - assert.equal(symbol!.command!.id, 'id'); - assert.equal(symbol!.command!.title, 'Title'); + assert.strictEqual(symbol!.command!.id, 'id'); + assert.strictEqual(symbol!.command!.title, 'Title'); }); test('CodeLens, missing command', async () => { @@ -225,11 +225,11 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensModel(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); + assert.strictEqual(value.lenses.length, 1); let [data] = value.lenses; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); - assert.equal(symbol!.command!.id, 'missing'); - assert.equal(symbol!.command!.title, '!!MISSING: command!!'); + assert.strictEqual(symbol!.command!.id, 'missing'); + assert.strictEqual(symbol!.command!.title, '!!MISSING: command!!'); }); // --- definition @@ -244,10 +244,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); - assert.equal(entry.uri.toString(), model.uri.toString()); + assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); + assert.strictEqual(entry.uri.toString(), model.uri.toString()); }); test('Definition, one or many', async () => { @@ -265,7 +265,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 2); + assert.strictEqual(value.length, 2); }); test('Definition, registration order', async () => { @@ -284,10 +284,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 2); + assert.strictEqual(value.length, 2); // let [first, second] = value; - assert.equal(value[0].uri.authority, 'second'); - assert.equal(value[1].uri.authority, 'first'); + assert.strictEqual(value[0].uri.authority, 'second'); + assert.strictEqual(value[1].uri.authority, 'first'); }); test('Definition, evil provider', async () => { @@ -305,7 +305,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); }); // -- declaration @@ -320,10 +320,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getDeclarationsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); - assert.equal(entry.uri.toString(), model.uri.toString()); + assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); + assert.strictEqual(entry.uri.toString(), model.uri.toString()); }); // --- implementation @@ -338,10 +338,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getImplementationsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); - assert.equal(entry.uri.toString(), model.uri.toString()); + assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); + assert.strictEqual(entry.uri.toString(), model.uri.toString()); }); // --- type definition @@ -356,10 +356,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getTypeDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); - assert.equal(entry.uri.toString(), model.uri.toString()); + assert.deepStrictEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 }); + assert.strictEqual(entry.uri.toString(), model.uri.toString()); }); // --- extra info @@ -374,9 +374,9 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); + assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); }); }); @@ -391,9 +391,9 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 4, startColumn: 1, endLineNumber: 9, endColumn: 8 }); + assert.deepStrictEqual(entry.range, { startLineNumber: 4, startColumn: 1, endLineNumber: 9, endColumn: 8 }); }); }); @@ -414,10 +414,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getHover(model, new EditorPosition(1, 1), CancellationToken.None); - assert.equal(value.length, 2); + assert.strictEqual(value.length, 2); let [first, second] = (value as modes.Hover[]); - assert.equal(first.contents[0].value, 'registered second'); - assert.equal(second.contents[0].value, 'registered first'); + assert.strictEqual(first.contents[0].value, 'registered second'); + assert.strictEqual(second.contents[0].value, 'registered first'); }); @@ -436,7 +436,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => { - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); }); }); @@ -452,10 +452,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = (await getOccurrencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); - assert.equal(entry.kind, modes.DocumentHighlightKind.Text); + assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); + assert.strictEqual(entry.kind, modes.DocumentHighlightKind.Text); }); test('Occurrences, order 1/2', async () => { @@ -473,10 +473,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = (await getOccurrencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); - assert.equal(entry.kind, modes.DocumentHighlightKind.Text); + assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 }); + assert.strictEqual(entry.kind, modes.DocumentHighlightKind.Text); }); test('Occurrences, order 2/2', async () => { @@ -494,10 +494,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = (await getOccurrencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [entry] = value; - assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 3 }); - assert.equal(entry.kind, modes.DocumentHighlightKind.Text); + assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 3 }); + assert.strictEqual(entry.kind, modes.DocumentHighlightKind.Text); }); test('Occurrences, evil provider', async () => { @@ -516,7 +516,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getOccurrencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None); - assert.equal(value!.length, 1); + assert.strictEqual(value!.length, 1); }); // --- references @@ -537,10 +537,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getReferencesAtPosition(model, new EditorPosition(1, 2), false, CancellationToken.None); - assert.equal(value.length, 2); + assert.strictEqual(value.length, 2); let [first, second] = value; - assert.equal(first.uri.path, '/second'); - assert.equal(second.uri.path, '/first'); + assert.strictEqual(first.uri.path, '/second'); + assert.strictEqual(second.uri.path, '/first'); }); test('References, data conversion', async () => { @@ -553,10 +553,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getReferencesAtPosition(model, new EditorPosition(1, 2), false, CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [item] = value; - assert.deepEqual(item.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); - assert.equal(item.uri.toString(), model.uri.toString()); + assert.deepStrictEqual(item.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(item.uri.toString(), model.uri.toString()); }); test('References, evil provider', async () => { @@ -574,7 +574,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getReferencesAtPosition(model, new EditorPosition(1, 2), false, CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); }); // --- quick fix @@ -592,12 +592,12 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { validActions: actions } = await getCodeActions(model, model.getFullModelRange(), { type: modes.CodeActionTriggerType.Manual }, Progress.None, CancellationToken.None); - assert.equal(actions.length, 2); + assert.strictEqual(actions.length, 2); const [first, second] = actions; - assert.equal(first.action.title, 'Testing1'); - assert.equal(first.action.command!.id, 'test1'); - assert.equal(second.action.title, 'Testing2'); - assert.equal(second.action.command!.id, 'test2'); + assert.strictEqual(first.action.title, 'Testing1'); + assert.strictEqual(first.action.command!.id, 'test1'); + assert.strictEqual(second.action.title, 'Testing2'); + assert.strictEqual(second.action.command!.id, 'test2'); }); test('Quick Fix, code action data conversion', async () => { @@ -616,12 +616,12 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { validActions: actions } = await getCodeActions(model, model.getFullModelRange(), { type: modes.CodeActionTriggerType.Manual }, Progress.None, CancellationToken.None); - assert.equal(actions.length, 1); + assert.strictEqual(actions.length, 1); const [first] = actions; - assert.equal(first.action.title, 'Testing1'); - assert.equal(first.action.command!.title, 'Testing1Command'); - assert.equal(first.action.command!.id, 'test1'); - assert.equal(first.action.kind, 'test.scope'); + assert.strictEqual(first.action.title, 'Testing1'); + assert.strictEqual(first.action.command!.title, 'Testing1Command'); + assert.strictEqual(first.action.command!.id, 'test1'); + assert.strictEqual(first.action.kind, 'test.scope'); }); @@ -639,7 +639,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { validActions: actions } = await getCodeActions(model, model.getFullModelRange(), { type: modes.CodeActionTriggerType.Manual }, Progress.None, CancellationToken.None); - assert.equal(actions.length, 1); + assert.strictEqual(actions.length, 1); }); test('Quick Fix, evil provider', async () => { @@ -657,7 +657,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { validActions: actions } = await getCodeActions(model, model.getFullModelRange(), { type: modes.CodeActionTriggerType.Manual }, Progress.None, CancellationToken.None); - assert.equal(actions.length, 1); + assert.strictEqual(actions.length, 1); }); // --- navigate types @@ -678,11 +678,11 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getWorkspaceSymbols(''); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; const [, symbols] = first; - assert.equal(symbols.length, 1); - assert.equal(symbols[0].name, 'testing'); + assert.strictEqual(symbols.length, 1); + assert.strictEqual(symbols[0].name, 'testing'); }); // --- rename @@ -715,7 +715,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await rename(model, new EditorPosition(1, 1), 'newName'); - assert.equal(value.rejectReason, 'evil'); + assert.strictEqual(value.rejectReason, 'evil'); }); test('Rename, evil provider 2/2', async () => { @@ -736,7 +736,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await rename(model, new EditorPosition(1, 1), 'newName'); - assert.equal(value.edits.length, 1); + assert.strictEqual(value.edits.length, 1); }); test('Rename, ordering', async () => { @@ -759,7 +759,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await rename(model, new EditorPosition(1, 1), 'newName'); // least relevant rename provider - assert.equal(value.edits.length, 2); + assert.strictEqual(value.edits.length, 2); }); test('Multiple RenameProviders don\'t respect all possible PrepareRename handlers, #98352', async function () { @@ -793,7 +793,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); await rename(model, new EditorPosition(1, 1), 'newName'); - assert.deepEqual(called, [true, true, true, false]); + assert.deepStrictEqual(called, [true, true, true, false]); }); test('Multiple RenameProviders don\'t respect all possible PrepareRename handlers, #98352', async function () { @@ -825,7 +825,7 @@ suite('ExtHostLanguageFeatures', function () { await rename(model, new EditorPosition(1, 1), 'newName'); // first provider has NO prepare which means it is taken by default - assert.deepEqual(called, [false, false, true]); + assert.deepStrictEqual(called, [false, false, true]); }); // --- parameter hints @@ -863,7 +863,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await provideSignatureHelp(model, new EditorPosition(1, 1), { triggerKind: modes.SignatureHelpTriggerKind.Invoke, isRetrigger: false }, CancellationToken.None); - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); // --- suggestions @@ -884,8 +884,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { items } = await provideSuggestionItems(model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set().add(modes.CompletionItemKind.Snippet))); - assert.equal(items.length, 1); - assert.equal(items[0].completion.insertText, 'testing2'); + assert.strictEqual(items.length, 1); + assert.strictEqual(items[0].completion.insertText, 'testing2'); }); test('Suggest, order 2/3', async () => { @@ -904,8 +904,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { items } = await provideSuggestionItems(model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set().add(modes.CompletionItemKind.Snippet))); - assert.equal(items.length, 1); - assert.equal(items[0].completion.insertText, 'weak-selector'); + assert.strictEqual(items.length, 1); + assert.strictEqual(items[0].completion.insertText, 'weak-selector'); }); test('Suggest, order 2/3', async () => { @@ -924,9 +924,9 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { items } = await provideSuggestionItems(model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set().add(modes.CompletionItemKind.Snippet))); - assert.equal(items.length, 2); - assert.equal(items[0].completion.insertText, 'strong-1'); // sort by label - assert.equal(items[1].completion.insertText, 'strong-2'); + assert.strictEqual(items.length, 2); + assert.strictEqual(items[0].completion.insertText, 'strong-1'); // sort by label + assert.strictEqual(items[1].completion.insertText, 'strong-2'); }); test('Suggest, evil provider', async () => { @@ -946,7 +946,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const { items } = await provideSuggestionItems(model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set().add(modes.CompletionItemKind.Snippet))); - assert.equal(items[0].container.incomplete, false); + assert.strictEqual(items[0].container.incomplete, false); }); test('Suggest, CompletionList', async () => { @@ -959,7 +959,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); provideSuggestionItems(model, new EditorPosition(1, 1), new CompletionOptions(undefined, new Set().add(modes.CompletionItemKind.Snippet))).then(model => { - assert.equal(model.items[0].container.incomplete, true); + assert.strictEqual(model.items[0].container.incomplete, true); }); }); @@ -980,13 +980,13 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = (await getDocumentFormattingEditsUntilResult(NullWorkerService, model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!; - assert.equal(value.length, 2); + assert.strictEqual(value.length, 2); let [first, second] = value; - assert.equal(first.text, 'testing'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); - assert.equal(second.eol, EndOfLineSequence.LF); - assert.equal(second.text, ''); - assert.deepEqual(second.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(first.text, 'testing'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(second.eol, EndOfLineSequence.LF); + assert.strictEqual(second.text, ''); + assert.deepStrictEqual(second.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); }); test('Format Doc, evil provider', async () => { @@ -1022,10 +1022,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = (await getDocumentFormattingEditsUntilResult(NullWorkerService, model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.equal(first.text, 'testing'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(first.text, 'testing'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); }); test('Format Range, data conversion', async () => { @@ -1037,10 +1037,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = (await getDocumentRangeFormattingEditsUntilResult(NullWorkerService, model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.text, 'testing'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(first.text, 'testing'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); }); test('Format Range, + format_doc', async () => { @@ -1061,13 +1061,13 @@ suite('ExtHostLanguageFeatures', function () { })); await rpcProtocol.sync(); const value = (await getDocumentRangeFormattingEditsUntilResult(NullWorkerService, model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.text, 'range2'); - assert.equal(first.range.startLineNumber, 3); - assert.equal(first.range.startColumn, 4); - assert.equal(first.range.endLineNumber, 5); - assert.equal(first.range.endColumn, 6); + assert.strictEqual(first.text, 'range2'); + assert.strictEqual(first.range.startLineNumber, 3); + assert.strictEqual(first.range.startColumn, 4); + assert.strictEqual(first.range.endLineNumber, 5); + assert.strictEqual(first.range.endColumn, 6); }); test('Format Range, evil provider', async () => { @@ -1091,10 +1091,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = (await getOnTypeFormattingEdits(NullWorkerService, model, new EditorPosition(1, 1), ';', { insertSpaces: true, tabSize: 2 }))!; - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); const [first] = value; - assert.equal(first.text, ';'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); + assert.strictEqual(first.text, ';'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); }); test('Links, data conversion', async () => { @@ -1109,11 +1109,11 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let { links } = await getLinks(model, CancellationToken.None); - assert.equal(links.length, 1); + assert.strictEqual(links.length, 1); let [first] = links; - assert.equal(first.url, 'foo:bar#3'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); - assert.equal(first.tooltip, 'tooltip'); + assert.strictEqual(first.url?.toString(), 'foo:bar#3'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); + assert.strictEqual(first.tooltip, 'tooltip'); }); test('Links, evil provider', async () => { @@ -1132,10 +1132,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let { links } = await getLinks(model, CancellationToken.None); - assert.equal(links.length, 1); + assert.strictEqual(links.length, 1); let [first] = links; - assert.equal(first.url, 'foo:bar#3'); - assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); + assert.strictEqual(first.url?.toString(), 'foo:bar#3'); + assert.deepStrictEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); }); test('Document colors, data conversion', async () => { @@ -1151,10 +1151,10 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); let value = await getColors(model, CancellationToken.None); - assert.equal(value.length, 1); + assert.strictEqual(value.length, 1); let [first] = value; - assert.deepEqual(first.colorInfo.color, { red: 0.1, green: 0.2, blue: 0.3, alpha: 0.4 }); - assert.deepEqual(first.colorInfo.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 21 }); + assert.deepStrictEqual(first.colorInfo.color, { red: 0.1, green: 0.2, blue: 0.3, alpha: 0.4 }); + assert.deepStrictEqual(first.colorInfo.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 21 }); }); // -- selection ranges @@ -1171,7 +1171,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); provideSelectionRanges(model, [new Position(1, 17)], { selectLeadingAndTrailingWhitespace: true }, CancellationToken.None).then(ranges => { - assert.equal(ranges.length, 1); + assert.strictEqual(ranges.length, 1); assert.ok(ranges[0].length >= 2); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostMessagerService.test.ts b/src/vs/workbench/test/browser/api/extHostMessagerService.test.ts index 50f8ae572ed5..3327a19d989b 100644 --- a/src/vs/workbench/test/browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/browser/api/extHostMessagerService.test.ts @@ -101,28 +101,28 @@ suite('ExtHostMessageService', function () { test('propagte handle on select', async function () { let service = new MainThreadMessageService(null!, new EmptyNotificationService(notification => { - assert.equal(notification.actions!.primary!.length, 1); + assert.strictEqual(notification.actions!.primary!.length, 1); platform.setImmediate(() => notification.actions!.primary![0].run()); }), emptyCommandService, emptyDialogService); const handle = await service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]); - assert.equal(handle, 42); + assert.strictEqual(handle, 42); }); suite('modal', () => { test('calls dialog service', async () => { const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock() { show(severity: Severity, message: string, buttons: string[]) { - assert.equal(severity, 1); - assert.equal(message, 'h'); - assert.equal(buttons.length, 2); - assert.equal(buttons[1], 'Cancel'); + assert.strictEqual(severity, 1); + assert.strictEqual(message, 'h'); + assert.strictEqual(buttons.length, 2); + assert.strictEqual(buttons[1], 'Cancel'); return Promise.resolve({ choice: 0 }); } } as IDialogService); const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]); - assert.equal(handle, 42); + assert.strictEqual(handle, 42); }); test('returns undefined when cancelled', async () => { @@ -133,19 +133,19 @@ suite('ExtHostMessageService', function () { } as IDialogService); const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]); - assert.equal(handle, undefined); + assert.strictEqual(handle, undefined); }); test('hides Cancel button when not needed', async () => { const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock() { show(severity: Severity, message: string, buttons: string[]) { - assert.equal(buttons.length, 1); + assert.strictEqual(buttons.length, 1); return Promise.resolve({ choice: 0 }); } } as IDialogService); const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]); - assert.equal(handle, 42); + assert.strictEqual(handle, 42); }); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts index e2d51f7cceb6..fe0cfc867655 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts @@ -104,14 +104,14 @@ suite('NotebookCell#Document', function () { const d1 = extHostDocuments.getDocument(c1.uri); assert.ok(d1); - assert.equal(d1.languageId, c1.language); - assert.equal(d1.version, 1); + assert.strictEqual(d1.languageId, c1.language); + assert.strictEqual(d1.version, 1); assert.ok(d1.notebook === notebook.notebookDocument); const d2 = extHostDocuments.getDocument(c2.uri); assert.ok(d2); - assert.equal(d2.languageId, c2.language); - assert.equal(d2.version, 1); + assert.strictEqual(d2.languageId, c2.language); + assert.strictEqual(d2.version, 1); assert.ok(d2.notebook === notebook.notebookDocument); }); @@ -197,7 +197,7 @@ suite('NotebookCell#Document', function () { for (let cell of notebook.notebookDocument.cells) { const doc = extHostDocuments.getDocument(cell.uri); assert.ok(doc); - assert.equal(extHostDocuments.getDocument(cell.uri).isClosed, false); + assert.strictEqual(extHostDocuments.getDocument(cell.uri).isClosed, false); docs.push(doc); addData.push({ EOL: '\n', @@ -218,7 +218,7 @@ suite('NotebookCell#Document', function () { // notebook is still open -> cell documents stay open for (let cell of notebook.notebookDocument.cells) { assert.ok(extHostDocuments.getDocument(cell.uri)); - assert.equal(extHostDocuments.getDocument(cell.uri).isClosed, false); + assert.strictEqual(extHostDocuments.getDocument(cell.uri).isClosed, false); } // close notebook -> docs are closed @@ -227,13 +227,13 @@ suite('NotebookCell#Document', function () { assert.throws(() => extHostDocuments.getDocument(cell.uri)); } for (let doc of docs) { - assert.equal(doc.isClosed, true); + assert.strictEqual(doc.isClosed, true); } }); test('cell document goes when cell is removed', async function () { - assert.equal(notebook.notebookDocument.cells.length, 2); + assert.strictEqual(notebook.notebookDocument.cells.length, 2); const [cell1, cell2] = notebook.notebookDocument.cells; extHostNotebooks.$acceptModelChanged(notebook.uri, { @@ -246,25 +246,25 @@ suite('NotebookCell#Document', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1); - assert.equal(cell1.document.isClosed, true); // ref still alive! - assert.equal(cell2.document.isClosed, false); + assert.strictEqual(notebook.notebookDocument.cells.length, 1); + assert.strictEqual(cell1.document.isClosed, true); // ref still alive! + assert.strictEqual(cell2.document.isClosed, false); assert.throws(() => extHostDocuments.getDocument(cell1.uri)); }); test('cell document knows notebook', function () { for (let cells of notebook.notebookDocument.cells) { - assert.equal(cells.document.notebook === notebook.notebookDocument, true); + assert.strictEqual(cells.document.notebook === notebook.notebookDocument, true); } }); test('cell#index', function () { - assert.equal(notebook.notebookDocument.cells.length, 2); + assert.strictEqual(notebook.notebookDocument.cells.length, 2); const [first, second] = notebook.notebookDocument.cells; - assert.equal(first.index, 0); - assert.equal(second.index, 1); + assert.strictEqual(first.index, 0); + assert.strictEqual(second.index, 1); // remove first cell extHostNotebooks.$acceptModelChanged(notebook.uri, { @@ -275,8 +275,8 @@ suite('NotebookCell#Document', function () { }] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1); - assert.equal(second.index, 0); + assert.strictEqual(notebook.notebookDocument.cells.length, 1); + assert.strictEqual(second.index, 0); extHostNotebooks.$acceptModelChanged(notebookUri, { versionId: notebook.notebookDocument.version + 1, @@ -302,7 +302,7 @@ suite('NotebookCell#Document', function () { }] }, false); - assert.equal(notebook.notebookDocument.cells.length, 3); - assert.equal(second.index, 2); + assert.strictEqual(notebook.notebookDocument.cells.length, 3); + assert.strictEqual(second.index, 2); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts index 776543c4fdac..98eb5c211f43 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts @@ -91,27 +91,27 @@ suite('NotebookConcatDocument', function () { test('empty', function () { let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); - assert.equal(doc.getText(), ''); - assert.equal(doc.version, 0); + assert.strictEqual(doc.getText(), ''); + assert.strictEqual(doc.version, 0); - // assert.equal(doc.locationAt(new Position(0, 0)), undefined); - // assert.equal(doc.positionAt(SOME_FAKE_LOCATION?), undefined); + // assert.strictEqual(doc.locationAt(new Position(0, 0)), undefined); + // assert.strictEqual(doc.positionAt(SOME_FAKE_LOCATION?), undefined); }); function assertLocation(doc: vscode.NotebookConcatTextDocument, pos: Position, expected: Location, reverse = true) { const actual = doc.locationAt(pos); - assert.equal(actual.uri.toString(), expected.uri.toString()); - assert.equal(actual.range.isEqual(expected.range), true); + assert.strictEqual(actual.uri.toString(), expected.uri.toString()); + assert.strictEqual(actual.range.isEqual(expected.range), true); if (reverse) { // reverse - offset const offset = doc.offsetAt(pos); - assert.equal(doc.positionAt(offset).isEqual(pos), true); + assert.strictEqual(doc.positionAt(offset).isEqual(pos), true); // reverse - pos const actualPosition = doc.positionAt(actual); - assert.equal(actualPosition.isEqual(pos), true); + assert.strictEqual(actualPosition.isEqual(pos), true); } } @@ -151,13 +151,13 @@ suite('NotebookConcatDocument', function () { }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); - assert.equal(doc.contains(cellUri1), true); - assert.equal(doc.contains(cellUri2), true); - assert.equal(doc.contains(URI.parse('some://miss/path')), false); + assert.strictEqual(doc.contains(cellUri1), true); + assert.strictEqual(doc.contains(cellUri2), true); + assert.strictEqual(doc.contains(URI.parse('some://miss/path')), false); }); test('location, position mapping', function () { @@ -189,7 +189,7 @@ suite('NotebookConcatDocument', function () { }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); @@ -224,8 +224,8 @@ suite('NotebookConcatDocument', function () { } ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 1); - assert.equal(doc.version, 1); + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 1); + assert.strictEqual(doc.version, 1); assertLines(doc, 'Hello', 'World', 'Hello World!'); assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].uri, new Position(0, 0))); @@ -252,8 +252,8 @@ suite('NotebookConcatDocument', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); - assert.equal(doc.version, 2); + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); + assert.strictEqual(doc.version, 2); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].uri, new Position(0, 0))); assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[1].uri, new Position(1, 0))); @@ -271,8 +271,8 @@ suite('NotebookConcatDocument', function () { } ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 1); - assert.equal(doc.version, 3); + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 1); + assert.strictEqual(doc.version, 3); assertLines(doc, 'Hello', 'World', 'Hello World!'); assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].uri, new Position(0, 0))); assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cells[0].uri, new Position(2, 2))); @@ -310,8 +310,8 @@ suite('NotebookConcatDocument', function () { } ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); - assert.equal(doc.version, 1); + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); + assert.strictEqual(doc.version, 1); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].uri, new Position(0, 0))); @@ -322,7 +322,7 @@ suite('NotebookConcatDocument', function () { // offset math let cell1End = doc.offsetAt(new Position(2, 12)); - assert.equal(doc.positionAt(cell1End).isEqual(new Position(2, 12)), true); + assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(2, 12)), true); extHostDocuments.$acceptModelChanged(notebook.notebookDocument.cells[0].uri, { versionId: 0, @@ -337,7 +337,7 @@ suite('NotebookConcatDocument', function () { assertLines(doc, 'Hello', 'World', 'Hi World!', 'Hallo', 'Welt', 'Hallo Welt!'); assertLocation(doc, new Position(2, 12), new Location(notebook.notebookDocument.cells[0].uri, new Position(2, 9)), false); - assert.equal(doc.positionAt(cell1End).isEqual(new Position(3, 2)), true); + assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(3, 2)), true); }); @@ -403,12 +403,12 @@ suite('NotebookConcatDocument', function () { function assertOffsetAtPosition(doc: vscode.NotebookConcatTextDocument, offset: number, expected: { line: number, character: number }, reverse = true) { const actual = doc.positionAt(offset); - assert.equal(actual.line, expected.line); - assert.equal(actual.character, expected.character); + assert.strictEqual(actual.line, expected.line); + assert.strictEqual(actual.character, expected.character); if (reverse) { const actualOffset = doc.offsetAt(actual); - assert.equal(actualOffset, offset); + assert.strictEqual(actualOffset, offset); } } @@ -441,7 +441,7 @@ suite('NotebookConcatDocument', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); @@ -457,16 +457,16 @@ suite('NotebookConcatDocument', function () { function assertLocationAtPosition(doc: vscode.NotebookConcatTextDocument, pos: { line: number, character: number }, expected: { uri: URI, line: number, character: number }, reverse = true) { const actual = doc.locationAt(new Position(pos.line, pos.character)); - assert.equal(actual.uri.toString(), expected.uri.toString()); - assert.equal(actual.range.start.line, expected.line); - assert.equal(actual.range.end.line, expected.line); - assert.equal(actual.range.start.character, expected.character); - assert.equal(actual.range.end.character, expected.character); + assert.strictEqual(actual.uri.toString(), expected.uri.toString()); + assert.strictEqual(actual.range.start.line, expected.line); + assert.strictEqual(actual.range.end.line, expected.line); + assert.strictEqual(actual.range.start.character, expected.character); + assert.strictEqual(actual.range.end.character, expected.character); if (reverse) { const actualPos = doc.positionAt(actual); - assert.equal(actualPos.line, pos.line); - assert.equal(actualPos.character, pos.character); + assert.strictEqual(actualPos.line, pos.line); + assert.strictEqual(actualPos.character, pos.character); } } @@ -498,7 +498,7 @@ suite('NotebookConcatDocument', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); @@ -539,14 +539,14 @@ suite('NotebookConcatDocument', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); - assert.equal(doc.getText(new Range(0, 0, 0, 0)), ''); - assert.equal(doc.getText(new Range(0, 0, 1, 0)), 'Hello\n'); - assert.equal(doc.getText(new Range(2, 0, 4, 0)), 'Hello World!\nHallo\n'); + assert.strictEqual(doc.getText(new Range(0, 0, 0, 0)), ''); + assert.strictEqual(doc.getText(new Range(0, 0, 1, 0)), 'Hello\n'); + assert.strictEqual(doc.getText(new Range(2, 0, 4, 0)), 'Hello World!\nHallo\n'); }); test('validateRange/Position', function () { @@ -577,15 +577,15 @@ suite('NotebookConcatDocument', function () { ] }, false); - assert.equal(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code + assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined); assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'); function assertPosition(actual: vscode.Position, expectedLine: number, expectedCh: number) { - assert.equal(actual.line, expectedLine); - assert.equal(actual.character, expectedCh); + assert.strictEqual(actual.line, expectedLine); + assert.strictEqual(actual.character, expectedCh); } diff --git a/src/vs/workbench/test/browser/api/extHostTextEditor.test.ts b/src/vs/workbench/test/browser/api/extHostTextEditor.test.ts index 931313c55e9f..6e59c522f2ab 100644 --- a/src/vs/workbench/test/browser/api/extHostTextEditor.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTextEditor.test.ts @@ -27,12 +27,12 @@ suite('ExtHostTextEditor', () => { assert.ok(editor.document); editor._acceptViewColumn(3); - assert.equal(3, editor.viewColumn); + assert.strictEqual(3, editor.viewColumn); editor.dispose(); assert.throws(() => editor._acceptViewColumn(2)); - assert.equal(3, editor.viewColumn); + assert.strictEqual(3, editor.viewColumn); assert.ok(editor.document); assert.throws(() => editor._acceptOptions(null!)); @@ -50,13 +50,13 @@ suite('ExtHostTextEditor', () => { }, new NullLogService(), doc, [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4, indentSize: 4 }, [], 1); await editor.edit(edit => { }); - assert.equal(applyCount, 0); + assert.strictEqual(applyCount, 0); await editor.edit(edit => { edit.setEndOfLine(1); }); - assert.equal(applyCount, 1); + assert.strictEqual(applyCount, 1); await editor.edit(edit => { edit.delete(new Range(0, 0, 1, 1)); }); - assert.equal(applyCount, 2); + assert.strictEqual(applyCount, 2); }); }); @@ -70,7 +70,7 @@ suite('ExtHostTextEditorOptions', () => { let mockProxy: MainThreadTextEditorsShape = { dispose: undefined!, $trySetOptions: (id: string, options: ITextEditorConfigurationUpdate) => { - assert.equal(id, '1'); + assert.strictEqual(id, '1'); calls.push(options); return Promise.resolve(undefined); }, @@ -109,7 +109,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: opts.cursorStyle, lineNumbers: opts.lineNumbers }; - assert.deepEqual(actual, expected); + assert.deepStrictEqual(actual, expected); } test('can set tabSize to the same value', () => { @@ -121,7 +121,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can change tabSize to positive integer', () => { @@ -133,7 +133,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 1 }]); + assert.deepStrictEqual(calls, [{ tabSize: 1 }]); }); test('can change tabSize to positive float', () => { @@ -145,7 +145,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 2 }]); + assert.deepStrictEqual(calls, [{ tabSize: 2 }]); }); test('can change tabSize to a string number', () => { @@ -157,7 +157,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 2 }]); + assert.deepStrictEqual(calls, [{ tabSize: 2 }]); }); test('tabSize can request indentation detection', () => { @@ -169,7 +169,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 'auto' }]); + assert.deepStrictEqual(calls, [{ tabSize: 'auto' }]); }); test('ignores invalid tabSize 1', () => { @@ -181,7 +181,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid tabSize 2', () => { @@ -193,7 +193,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid tabSize 3', () => { @@ -205,7 +205,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid tabSize 4', () => { @@ -217,7 +217,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can set indentSize to the same value', () => { @@ -229,7 +229,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can change indentSize to positive integer', () => { @@ -241,7 +241,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ indentSize: 1 }]); + assert.deepStrictEqual(calls, [{ indentSize: 1 }]); }); test('can change indentSize to positive float', () => { @@ -253,7 +253,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ indentSize: 2 }]); + assert.deepStrictEqual(calls, [{ indentSize: 2 }]); }); test('can change indentSize to a string number', () => { @@ -265,7 +265,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ indentSize: 2 }]); + assert.deepStrictEqual(calls, [{ indentSize: 2 }]); }); test('indentSize can request to use tabSize', () => { @@ -277,7 +277,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ indentSize: 'tabSize' }]); + assert.deepStrictEqual(calls, [{ indentSize: 'tabSize' }]); }); test('indentSize cannot request indentation detection', () => { @@ -289,7 +289,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid indentSize 1', () => { @@ -301,7 +301,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid indentSize 2', () => { @@ -313,7 +313,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid indentSize 3', () => { @@ -325,7 +325,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('ignores invalid indentSize 4', () => { @@ -337,7 +337,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can set insertSpaces to the same value', () => { @@ -349,7 +349,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can set insertSpaces to boolean', () => { @@ -361,7 +361,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ insertSpaces: true }]); + assert.deepStrictEqual(calls, [{ insertSpaces: true }]); }); test('can set insertSpaces to false string', () => { @@ -373,7 +373,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can set insertSpaces to truey', () => { @@ -385,7 +385,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ insertSpaces: true }]); + assert.deepStrictEqual(calls, [{ insertSpaces: true }]); }); test('insertSpaces can request indentation detection', () => { @@ -397,7 +397,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ insertSpaces: 'auto' }]); + assert.deepStrictEqual(calls, [{ insertSpaces: 'auto' }]); }); test('can set cursorStyle to same value', () => { @@ -409,7 +409,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can change cursorStyle', () => { @@ -421,7 +421,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block }]); + assert.deepStrictEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block }]); }); test('can set lineNumbers to same value', () => { @@ -433,7 +433,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can change lineNumbers', () => { @@ -445,7 +445,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.Off }); - assert.deepEqual(calls, [{ lineNumbers: RenderLineNumbersType.Off }]); + assert.deepStrictEqual(calls, [{ lineNumbers: RenderLineNumbersType.Off }]); }); test('can do bulk updates 0', () => { @@ -462,7 +462,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, []); + assert.deepStrictEqual(calls, []); }); test('can do bulk updates 1', () => { @@ -477,7 +477,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 'auto', insertSpaces: true }]); + assert.deepStrictEqual(calls, [{ tabSize: 'auto', insertSpaces: true }]); }); test('can do bulk updates 2', () => { @@ -492,7 +492,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On }); - assert.deepEqual(calls, [{ tabSize: 3, insertSpaces: 'auto' }]); + assert.deepStrictEqual(calls, [{ tabSize: 3, insertSpaces: 'auto' }]); }); test('can do bulk updates 3', () => { @@ -507,7 +507,7 @@ suite('ExtHostTextEditorOptions', () => { cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.Relative }); - assert.deepEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.Relative }]); + assert.deepStrictEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.Relative }]); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts index a25792b912d3..8c67b327a9bb 100644 --- a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts @@ -91,24 +91,24 @@ suite('ExtHostTreeView', function () { return testObject.$getChildren('testNodeTreeProvider') .then(elements => { const actuals = elements.map(e => e.handle); - assert.deepEqual(actuals, ['0/0:a', '0/0:b']); + assert.deepStrictEqual(actuals, ['0/0:a', '0/0:b']); return Promise.all([ testObject.$getChildren('testNodeTreeProvider', '0/0:a') .then(children => { const actuals = children.map(e => e.handle); - assert.deepEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']); + assert.deepStrictEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']); return Promise.all([ - testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.equal(children.length, 0)), - testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.equal(children.length, 0)) + testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.strictEqual(children.length, 0)), + testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.strictEqual(children.length, 0)) ]); }), testObject.$getChildren('testNodeTreeProvider', '0/0:b') .then(children => { const actuals = children.map(e => e.handle); - assert.deepEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']); + assert.deepStrictEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']); return Promise.all([ - testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.equal(children.length, 0)), - testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.equal(children.length, 0)) + testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.strictEqual(children.length, 0)), + testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.strictEqual(children.length, 0)) ]); }) ]); @@ -119,24 +119,24 @@ suite('ExtHostTreeView', function () { return testObject.$getChildren('testNodeWithIdTreeProvider') .then(elements => { const actuals = elements.map(e => e.handle); - assert.deepEqual(actuals, ['1/a', '1/b']); + assert.deepStrictEqual(actuals, ['1/a', '1/b']); return Promise.all([ testObject.$getChildren('testNodeWithIdTreeProvider', '1/a') .then(children => { const actuals = children.map(e => e.handle); - assert.deepEqual(actuals, ['1/aa', '1/ab']); + assert.deepStrictEqual(actuals, ['1/aa', '1/ab']); return Promise.all([ - testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.equal(children.length, 0)), - testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.equal(children.length, 0)) + testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.strictEqual(children.length, 0)), + testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.strictEqual(children.length, 0)) ]); }), testObject.$getChildren('testNodeWithIdTreeProvider', '1/b') .then(children => { const actuals = children.map(e => e.handle); - assert.deepEqual(actuals, ['1/ba', '1/bb']); + assert.deepStrictEqual(actuals, ['1/ba', '1/bb']); return Promise.all([ - testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.equal(children.length, 0)), - testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.equal(children.length, 0)) + testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.strictEqual(children.length, 0)), + testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.strictEqual(children.length, 0)) ]); }) ]); @@ -146,7 +146,7 @@ suite('ExtHostTreeView', function () { test('construct highlights tree', () => { return testObject.$getChildren('testNodeWithHighlightsTreeProvider') .then(elements => { - assert.deepEqual(removeUnsetKeys(elements), [{ + assert.deepStrictEqual(removeUnsetKeys(elements), [{ handle: '1/a', label: { label: 'a', highlights: [[0, 2], [3, 5]] }, collapsibleState: TreeItemCollapsibleState.Collapsed @@ -158,7 +158,7 @@ suite('ExtHostTreeView', function () { return Promise.all([ testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/a') .then(children => { - assert.deepEqual(removeUnsetKeys(children), [{ + assert.deepStrictEqual(removeUnsetKeys(children), [{ handle: '1/aa', parentHandle: '1/a', label: { label: 'aa', highlights: [[0, 2], [3, 5]] }, @@ -172,7 +172,7 @@ suite('ExtHostTreeView', function () { }), testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/b') .then(children => { - assert.deepEqual(removeUnsetKeys(children), [{ + assert.deepStrictEqual(removeUnsetKeys(children), [{ handle: '1/ba', parentHandle: '1/b', label: { label: 'ba', highlights: [[0, 2], [3, 5]] }, @@ -200,7 +200,7 @@ suite('ExtHostTreeView', function () { testObject.$getChildren('testNodeWithIdTreeProvider') .then(elements => { const actuals = elements.map(e => e.handle); - assert.deepEqual(actuals, ['1/a', '1/b']); + assert.deepStrictEqual(actuals, ['1/a', '1/b']); return testObject.$getChildren('testNodeWithIdTreeProvider', '1/a') .then(() => testObject.$getChildren('testNodeWithIdTreeProvider', '1/b')) .then(() => assert.fail('Should fail with duplicate id')) @@ -212,7 +212,7 @@ suite('ExtHostTreeView', function () { test('refresh root', function (done) { target.onRefresh.event(actuals => { - assert.equal(undefined, actuals); + assert.strictEqual(undefined, actuals); done(); }); onDidChangeTreeNode.fire(undefined); @@ -221,8 +221,8 @@ suite('ExtHostTreeView', function () { test('refresh a parent node', () => { return new Promise((c, e) => { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:b'], Object.keys(actuals)); - assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { + assert.deepStrictEqual(['0/0:b'], Object.keys(actuals)); + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed @@ -235,8 +235,8 @@ suite('ExtHostTreeView', function () { test('refresh a leaf node', function (done) { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:b/0:bb'], Object.keys(actuals)); - assert.deepEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), { + assert.deepStrictEqual(['0/0:b/0:bb'], Object.keys(actuals)); + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), { handle: '0/0:b/0:bb', parentHandle: '0/0:b', label: { label: 'bb' }, @@ -262,13 +262,13 @@ suite('ExtHostTreeView', function () { test('refresh parent and child node trigger refresh only on parent - scenario 1', async () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals)); - assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { + assert.deepStrictEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals)); + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); - assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { handle: '0/0:a/0:aa', parentHandle: '0/0:a', label: { label: 'aa' }, @@ -285,13 +285,13 @@ suite('ExtHostTreeView', function () { test('refresh parent and child node trigger refresh only on parent - scenario 2', async () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals)); - assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { + assert.deepStrictEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals)); + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); - assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { handle: '0/0:a/0:aa', parentHandle: '0/0:a', label: { label: 'aa' }, @@ -308,8 +308,8 @@ suite('ExtHostTreeView', function () { test('refresh an element for label change', function (done) { labels['a'] = 'aa'; target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:a'], Object.keys(actuals)); - assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), { + assert.deepStrictEqual(['0/0:a'], Object.keys(actuals)); + assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a']), { handle: '0/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.Collapsed @@ -322,7 +322,7 @@ suite('ExtHostTreeView', function () { test('refresh calls are throttled on roots', () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.equal(undefined, actuals); + assert.strictEqual(undefined, actuals); resolve(); }); onDidChangeTreeNode.fire(undefined); @@ -335,7 +335,7 @@ suite('ExtHostTreeView', function () { test('refresh calls are throttled on elements', () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals)); + assert.deepStrictEqual(['0/0:a', '0/0:b'], Object.keys(actuals)); resolve(); }); @@ -349,7 +349,7 @@ suite('ExtHostTreeView', function () { test('refresh calls are throttled on unknown elements', () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals)); + assert.deepStrictEqual(['0/0:a', '0/0:b'], Object.keys(actuals)); resolve(); }); @@ -363,7 +363,7 @@ suite('ExtHostTreeView', function () { test('refresh calls are throttled on unknown elements and root', () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.equal(undefined, actuals); + assert.strictEqual(undefined, actuals); resolve(); }); @@ -377,7 +377,7 @@ suite('ExtHostTreeView', function () { test('refresh calls are throttled on elements and root', () => { return runWithEventMerging((resolve) => { target.onRefresh.event(actuals => { - assert.equal(undefined, actuals); + assert.strictEqual(undefined, actuals); resolve(); }); @@ -396,7 +396,7 @@ suite('ExtHostTreeView', function () { target.onRefresh.event(() => { testObject.$getChildren('testNodeTreeProvider') .then(elements => { - assert.deepEqual(elements.map(e => e.handle), ['0/0:a//0:b']); + assert.deepStrictEqual(elements.map(e => e.handle), ['0/0:a//0:b']); done(); }); }); @@ -439,11 +439,11 @@ suite('ExtHostTreeView', function () { testObject.$getChildren('testNodeTreeProvider') .then(elements => { const actuals = elements.map(e => e.handle); - assert.deepEqual(actuals, ['0/0:a', '0/0:b', '0/1:a', '0/0:d', '0/1:b', '0/0:f', '0/2:a']); + assert.deepStrictEqual(actuals, ['0/0:a', '0/0:b', '0/1:a', '0/0:d', '0/1:b', '0/0:f', '0/2:a']); return testObject.$getChildren('testNodeTreeProvider', '0/1:b') .then(elements => { const actuals = elements.map(e => e.handle); - assert.deepEqual(actuals, ['0/1:b/0:h', '0/1:b/1:h', '0/1:b/0:j', '0/1:b/1:j', '0/1:b/2:h']); + assert.deepStrictEqual(actuals, ['0/1:b/0:h', '0/1:b/1:h', '0/1:b/0:j', '0/1:b/1:j', '0/1:b/2:h']); done(); }); }); @@ -460,7 +460,7 @@ suite('ExtHostTreeView', function () { target.onRefresh.event(() => { testObject.$getChildren('testNodeTreeProvider') .then(elements => { - assert.deepEqual(elements.map(e => e.handle), ['0/0:c']); + assert.deepStrictEqual(elements.map(e => e.handle), ['0/0:c']); done(); }); }); @@ -475,7 +475,7 @@ suite('ExtHostTreeView', function () { return testObject.$getChildren('testNodeTreeProvider') .then(elements => { - assert.deepEqual(elements.map(e => e.handle), ['0/0:a', '0/0:b']); + assert.deepStrictEqual(elements.map(e => e.handle), ['0/0:a', '0/0:b']); }); }); @@ -496,9 +496,9 @@ suite('ExtHostTreeView', function () { return treeView.reveal({ key: 'a' }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual(expected, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual(expected, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); }); }); @@ -512,10 +512,10 @@ suite('ExtHostTreeView', function () { return treeView.reveal({ key: 'aa' }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); - assert.deepEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); - assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); + assert.deepStrictEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); }); }); @@ -531,10 +531,10 @@ suite('ExtHostTreeView', function () { .then(() => treeView.reveal({ key: 'aa' }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); - assert.deepEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); - assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); + assert.deepStrictEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); })); }); @@ -558,10 +558,10 @@ suite('ExtHostTreeView', function () { return treeView.reveal({ key: 'bac' }, { select: false, focus: false, expand: false }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); - assert.deepEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); - assert.deepEqual({ select: false, focus: false, expand: false }, revealTarget.args[0][2]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); + assert.deepStrictEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: false, focus: false, expand: false }, revealTarget.args[0][2]); }); }); @@ -589,10 +589,10 @@ suite('ExtHostTreeView', function () { return treeView.reveal({ key: 'ac' }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); - assert.deepEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); - assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1].item)); + assert.deepStrictEqual(expected.parentChain, (>(revealTarget.args[0][1].parentChain)).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); }); }); }); @@ -630,10 +630,10 @@ suite('ExtHostTreeView', function () { return treeView.reveal({ key: 'bc' }) .then(() => { assert.ok(revealTarget.calledOnce); - assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); - assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]); + assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); + assert.deepStrictEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepStrictEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]); }); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts b/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts index c64d371478d4..0cc72cdd1bc0 100644 --- a/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts @@ -25,45 +25,45 @@ suite('ExtHostTypeConverter', function () { test('MarkdownConvert - uris', function () { let data = MarkdownString.from('Hello'); - assert.equal(isEmptyObject(data.uris), true); - assert.equal(data.value, 'Hello'); + assert.strictEqual(isEmptyObject(data.uris), true); + assert.strictEqual(data.value, 'Hello'); data = MarkdownString.from('Hello [link](foo)'); - assert.equal(data.value, 'Hello [link](foo)'); - assert.equal(isEmptyObject(data.uris), true); // no scheme, no uri + assert.strictEqual(data.value, 'Hello [link](foo)'); + assert.strictEqual(isEmptyObject(data.uris), true); // no scheme, no uri data = MarkdownString.from('Hello [link](www.noscheme.bad)'); - assert.equal(data.value, 'Hello [link](www.noscheme.bad)'); - assert.equal(isEmptyObject(data.uris), true); // no scheme, no uri + assert.strictEqual(data.value, 'Hello [link](www.noscheme.bad)'); + assert.strictEqual(isEmptyObject(data.uris), true); // no scheme, no uri data = MarkdownString.from('Hello [link](foo:path)'); - assert.equal(data.value, 'Hello [link](foo:path)'); - assert.equal(size(data.uris!), 1); + assert.strictEqual(data.value, 'Hello [link](foo:path)'); + assert.strictEqual(size(data.uris!), 1); assert.ok(!!data.uris!['foo:path']); data = MarkdownString.from('hello@foo.bar'); - assert.equal(data.value, 'hello@foo.bar'); - assert.equal(size(data.uris!), 1); + assert.strictEqual(data.value, 'hello@foo.bar'); + assert.strictEqual(size(data.uris!), 1); // assert.ok(!!data.uris!['mailto:hello@foo.bar']); data = MarkdownString.from('*hello* [click](command:me)'); - assert.equal(data.value, '*hello* [click](command:me)'); - assert.equal(size(data.uris!), 1); + assert.strictEqual(data.value, '*hello* [click](command:me)'); + assert.strictEqual(size(data.uris!), 1); assert.ok(!!data.uris!['command:me']); data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); - assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); - assert.equal(size(data.uris!), 1); + assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); + assert.strictEqual(size(data.uris!), 1); assert.ok(!!data.uris!['file:///somepath/here']); data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); - assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); - assert.equal(size(data.uris!), 1); + assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)'); + assert.strictEqual(size(data.uris!), 1); assert.ok(!!data.uris!['file:///somepath/here']); data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here2)'); - assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here2)'); - assert.equal(size(data.uris!), 2); + assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here2)'); + assert.strictEqual(size(data.uris!), 2); assert.ok(!!data.uris!['file:///somepath/here']); assert.ok(!!data.uris!['file:///somepath/here2']); }); @@ -72,12 +72,12 @@ suite('ExtHostTypeConverter', function () { let data = MarkdownString.from('*hello* [click](command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2Ffoo%2Fbaz.ex%22%2C%22path%22%3A%22%2Fc%3A%2Ffoo%2Fbaz.ex%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22dev%22%7D)'); // assert that both uri get extracted but that the latter is only decoded once... - assert.equal(size(data.uris!), 2); + assert.strictEqual(size(data.uris!), 2); forEach(data.uris!, entry => { if (entry.value.scheme === 'file') { assert.ok(URI.revive(entry.value).toString().indexOf('file:///c%3A') === 0); } else { - assert.equal(entry.value.scheme, 'command'); + assert.strictEqual(entry.value.scheme, 'command'); } }); }); diff --git a/src/vs/workbench/test/browser/api/extHostTypes.test.ts b/src/vs/workbench/test/browser/api/extHostTypes.test.ts index 9722d5dac679..34acd549af66 100644 --- a/src/vs/workbench/test/browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTypes.test.ts @@ -12,7 +12,7 @@ import { assertType } from 'vs/base/common/types'; function assertToJSON(a: any, expected: any) { const raw = JSON.stringify(a); const actual = JSON.parse(raw); - assert.deepEqual(actual, expected); + assert.deepStrictEqual(actual, expected); } suite('ExtHostTypes', function () { @@ -20,14 +20,14 @@ suite('ExtHostTypes', function () { test('URI, toJSON', function () { let uri = URI.parse('file:///path/test.file'); - assert.deepEqual(uri.toJSON(), { + assert.deepStrictEqual(uri.toJSON(), { $mid: 1, scheme: 'file', path: '/path/test.file' }); assert.ok(uri.fsPath); - assert.deepEqual(uri.toJSON(), { + assert.deepStrictEqual(uri.toJSON(), { $mid: 1, scheme: 'file', path: '/path/test.file', @@ -36,7 +36,7 @@ suite('ExtHostTypes', function () { }); assert.ok(uri.toString()); - assert.deepEqual(uri.toJSON(), { + assert.deepStrictEqual(uri.toJSON(), { $mid: 1, scheme: 'file', path: '/path/test.file', @@ -54,13 +54,13 @@ suite('ExtHostTypes', function () { return 12; }); d.dispose(); - assert.equal(count, 1); + assert.strictEqual(count, 1); d.dispose(); - assert.equal(count, 1); + assert.strictEqual(count, 1); types.Disposable.from(undefined!, { dispose() { count += 1; } }).dispose(); - assert.equal(count, 2); + assert.strictEqual(count, 2); assert.throws(() => { @@ -83,8 +83,8 @@ suite('ExtHostTypes', function () { assert.throws(() => (pos as any).line = 12); let { line, character } = pos.toJSON(); - assert.equal(line, 0); - assert.equal(character, 0); + assert.strictEqual(line, 0); + assert.strictEqual(character, 0); }); test('Position, toJSON', function () { @@ -120,11 +120,11 @@ suite('ExtHostTypes', function () { let p2 = new types.Position(1, 2); let p3 = new types.Position(0, 4); - assert.equal(p1.compareTo(p1), 0); - assert.equal(p2.compareTo(p1), -1); - assert.equal(p1.compareTo(p2), 1); - assert.equal(p2.compareTo(p3), 1); - assert.equal(p1.compareTo(p3), 1); + assert.strictEqual(p1.compareTo(p1), 0); + assert.strictEqual(p2.compareTo(p1), -1); + assert.strictEqual(p1.compareTo(p2), 1); + assert.strictEqual(p2.compareTo(p3), 1); + assert.strictEqual(p1.compareTo(p3), 1); }); test('Position, translate', function () { @@ -138,24 +138,24 @@ suite('ExtHostTypes', function () { assert.ok(p1.translate(undefined) === p1); let res = p1.translate(-1); - assert.equal(res.line, 0); - assert.equal(res.character, 3); + assert.strictEqual(res.line, 0); + assert.strictEqual(res.character, 3); res = p1.translate({ lineDelta: -1 }); - assert.equal(res.line, 0); - assert.equal(res.character, 3); + assert.strictEqual(res.line, 0); + assert.strictEqual(res.character, 3); res = p1.translate(undefined, -1); - assert.equal(res.line, 1); - assert.equal(res.character, 2); + assert.strictEqual(res.line, 1); + assert.strictEqual(res.character, 2); res = p1.translate({ characterDelta: -1 }); - assert.equal(res.line, 1); - assert.equal(res.character, 2); + assert.strictEqual(res.line, 1); + assert.strictEqual(res.character, 2); res = p1.translate(11); - assert.equal(res.line, 12); - assert.equal(res.character, 3); + assert.strictEqual(res.line, 12); + assert.strictEqual(res.character, 3); assert.throws(() => p1.translate(null!)); assert.throws(() => p1.translate(null!, null!)); @@ -178,8 +178,8 @@ suite('ExtHostTypes', function () { assert.ok(p1.with({ line: 1, character: 3 }) === p1); let p2 = p1.with({ line: 0, character: 11 }); - assert.equal(p2.line, 0); - assert.equal(p2.character, 11); + assert.strictEqual(p2.line, 0); + assert.strictEqual(p2.character, 11); assert.throws(() => p1.with(null!)); assert.throws(() => p1.with(-9)); @@ -210,12 +210,12 @@ suite('ExtHostTypes', function () { test('Range, sorting', function () { // sorts start/end let range = new types.Range(1, 0, 0, 0); - assert.equal(range.start.line, 0); - assert.equal(range.end.line, 1); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.end.line, 1); range = new types.Range(0, 0, 1, 0); - assert.equal(range.start.line, 0); - assert.equal(range.end.line, 1); + assert.strictEqual(range.start.line, 0); + assert.strictEqual(range.end.line, 1); }); test('Range, isEmpty|isSingleLine', function () { @@ -254,26 +254,26 @@ suite('ExtHostTypes', function () { let res: types.Range; res = range.intersection(range)!; - assert.equal(res.start.line, 1); - assert.equal(res.start.character, 1); - assert.equal(res.end.line, 2); - assert.equal(res.end.character, 11); + assert.strictEqual(res.start.line, 1); + assert.strictEqual(res.start.character, 1); + assert.strictEqual(res.end.line, 2); + assert.strictEqual(res.end.character, 11); res = range.intersection(new types.Range(2, 12, 4, 0))!; - assert.equal(res, undefined); + assert.strictEqual(res, undefined); res = range.intersection(new types.Range(0, 0, 1, 0))!; - assert.equal(res, undefined); + assert.strictEqual(res, undefined); res = range.intersection(new types.Range(0, 0, 1, 1))!; assert.ok(res.isEmpty); - assert.equal(res.start.line, 1); - assert.equal(res.start.character, 1); + assert.strictEqual(res.start.line, 1); + assert.strictEqual(res.start.character, 1); res = range.intersection(new types.Range(2, 11, 61, 1))!; assert.ok(res.isEmpty); - assert.equal(res.start.line, 2); - assert.equal(res.start.character, 11); + assert.strictEqual(res.start.line, 2); + assert.strictEqual(res.start.character, 11); assert.throws(() => range.intersection(null!)); assert.throws(() => range.intersection(undefined!)); @@ -286,14 +286,14 @@ suite('ExtHostTypes', function () { let res: types.Range; res = ran1.union(new types.Range(2, 2, 9, 9)); assert.ok(res.start === ran1.start); - assert.equal(res.end.line, 9); - assert.equal(res.end.character, 9); + assert.strictEqual(res.end.line, 9); + assert.strictEqual(res.end.character, 9); ran1 = new types.Range(2, 1, 5, 3); res = ran1.union(new types.Range(1, 0, 4, 2)); assert.ok(res.end === ran1.end); - assert.equal(res.start.line, 1); - assert.equal(res.start.character, 0); + assert.strictEqual(res.start.line, 1); + assert.strictEqual(res.start.character, 0); }); test('Range, with', function () { @@ -311,22 +311,22 @@ suite('ExtHostTypes', function () { assert.ok(range.with({ end: new types.Position(2, 11) }) === range); let res = range.with(undefined, new types.Position(9, 8)); - assert.equal(res.end.line, 9); - assert.equal(res.end.character, 8); - assert.equal(res.start.line, 1); - assert.equal(res.start.character, 1); + assert.strictEqual(res.end.line, 9); + assert.strictEqual(res.end.character, 8); + assert.strictEqual(res.start.line, 1); + assert.strictEqual(res.start.character, 1); res = range.with({ end: new types.Position(9, 8) }); - assert.equal(res.end.line, 9); - assert.equal(res.end.character, 8); - assert.equal(res.start.line, 1); - assert.equal(res.start.character, 1); + assert.strictEqual(res.end.line, 9); + assert.strictEqual(res.end.character, 8); + assert.strictEqual(res.start.line, 1); + assert.strictEqual(res.start.character, 1); res = range.with({ end: new types.Position(9, 8), start: new types.Position(2, 3) }); - assert.equal(res.end.line, 9); - assert.equal(res.end.character, 8); - assert.equal(res.start.line, 2); - assert.equal(res.start.character, 3); + assert.strictEqual(res.end.line, 9); + assert.strictEqual(res.end.character, 8); + assert.strictEqual(res.start.line, 2); + assert.strictEqual(res.start.character, 3); assert.throws(() => range.with(null!)); assert.throws(() => range.with(undefined, null!)); @@ -336,14 +336,14 @@ suite('ExtHostTypes', function () { let range = new types.Range(1, 1, 2, 11); let edit = new types.TextEdit(range, undefined!); - assert.equal(edit.newText, ''); + assert.strictEqual(edit.newText, ''); assertToJSON(edit, { range: [{ line: 1, character: 1 }, { line: 2, character: 11 }], newText: '' }); edit = new types.TextEdit(range, null!); - assert.equal(edit.newText, ''); + assert.strictEqual(edit.newText, ''); edit = new types.TextEdit(range, ''); - assert.equal(edit.newText, ''); + assert.strictEqual(edit.newText, ''); }); test('WorkspaceEdit', () => { @@ -356,13 +356,13 @@ suite('ExtHostTypes', function () { edit.set(a, [types.TextEdit.insert(new types.Position(0, 0), 'fff')]); assert.ok(edit.has(a)); - assert.equal(edit.size, 1); + assert.strictEqual(edit.size, 1); assertToJSON(edit, [[a.toJSON(), [{ range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: 'fff' }]]]); edit.insert(b, new types.Position(1, 1), 'fff'); edit.delete(b, new types.Range(0, 0, 0, 0)); assert.ok(edit.has(b)); - assert.equal(edit.size, 2); + assert.strictEqual(edit.size, 2); assertToJSON(edit, [ [a.toJSON(), [{ range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: 'fff' }]], [b.toJSON(), [{ range: [{ line: 1, character: 1 }, { line: 1, character: 1 }], newText: 'fff' }, { range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: '' }]] @@ -370,10 +370,10 @@ suite('ExtHostTypes', function () { edit.set(b, undefined!); assert.ok(!edit.has(b)); - assert.equal(edit.size, 1); + assert.strictEqual(edit.size, 1); edit.set(b, [types.TextEdit.insert(new types.Position(0, 0), 'ffff')]); - assert.equal(edit.get(b).length, 1); + assert.strictEqual(edit.get(b).length, 1); }); test('WorkspaceEdit - keep order of text and file changes', function () { @@ -385,21 +385,21 @@ suite('ExtHostTypes', function () { edit.replace(URI.parse('foo:b'), new types.Range(3, 1, 3, 1), 'bazz'); const all = edit._allEntries(); - assert.equal(all.length, 4); + assert.strictEqual(all.length, 4); const [first, second, third, fourth] = all; assertType(first._type === types.FileEditType.Text); - assert.equal(first.uri.toString(), 'foo:a'); + assert.strictEqual(first.uri.toString(), 'foo:a'); assertType(second._type === types.FileEditType.File); - assert.equal(second.from!.toString(), 'foo:a'); - assert.equal(second.to!.toString(), 'foo:b'); + assert.strictEqual(second.from!.toString(), 'foo:a'); + assert.strictEqual(second.to!.toString(), 'foo:b'); assertType(third._type === types.FileEditType.Text); - assert.equal(third.uri.toString(), 'foo:a'); + assert.strictEqual(third.uri.toString(), 'foo:a'); assertType(fourth._type === types.FileEditType.Text); - assert.equal(fourth.uri.toString(), 'foo:b'); + assert.strictEqual(fourth.uri.toString(), 'foo:b'); }); test('WorkspaceEdit - two edits for one resource', function () { @@ -408,13 +408,13 @@ suite('ExtHostTypes', function () { edit.insert(uri, new types.Position(0, 0), 'Hello'); edit.insert(uri, new types.Position(0, 0), 'Foo'); - assert.equal(edit._allEntries().length, 2); + assert.strictEqual(edit._allEntries().length, 2); let [first, second] = edit._allEntries(); assertType(first._type === types.FileEditType.Text); assertType(second._type === types.FileEditType.Text); - assert.equal(first.edit.newText, 'Hello'); - assert.equal(second.edit.newText, 'Foo'); + assert.strictEqual(first.edit.newText, 'Hello'); + assert.strictEqual(second.edit.newText, 'Foo'); }); test('DocumentLink', () => { @@ -463,7 +463,7 @@ suite('ExtHostTypes', function () { let info = new types.SymbolInformation('foo', types.SymbolKind.Array, new types.Range(1, 1, 2, 3)); assert.ok(info.location instanceof types.Location); - assert.equal(info.location.uri, undefined); + assert.strictEqual(info.location.uri, undefined); }); test('SnippetString, builder-methods', function () { @@ -471,78 +471,78 @@ suite('ExtHostTypes', function () { let string: types.SnippetString; string = new types.SnippetString(); - assert.equal(string.appendText('I need $ and $').value, 'I need \\$ and \\$'); + assert.strictEqual(string.appendText('I need $ and $').value, 'I need \\$ and \\$'); string = new types.SnippetString(); - assert.equal(string.appendText('I need \\$').value, 'I need \\\\\\$'); + assert.strictEqual(string.appendText('I need \\$').value, 'I need \\\\\\$'); string = new types.SnippetString(); string.appendPlaceholder('fo$o}'); - assert.equal(string.value, '${1:fo\\$o\\}}'); + assert.strictEqual(string.value, '${1:fo\\$o\\}}'); string = new types.SnippetString(); string.appendText('foo').appendTabstop(0).appendText('bar'); - assert.equal(string.value, 'foo$0bar'); + assert.strictEqual(string.value, 'foo$0bar'); string = new types.SnippetString(); string.appendText('foo').appendTabstop().appendText('bar'); - assert.equal(string.value, 'foo$1bar'); + assert.strictEqual(string.value, 'foo$1bar'); string = new types.SnippetString(); string.appendText('foo').appendTabstop(42).appendText('bar'); - assert.equal(string.value, 'foo$42bar'); + assert.strictEqual(string.value, 'foo$42bar'); string = new types.SnippetString(); string.appendText('foo').appendPlaceholder('farboo').appendText('bar'); - assert.equal(string.value, 'foo${1:farboo}bar'); + assert.strictEqual(string.value, 'foo${1:farboo}bar'); string = new types.SnippetString(); string.appendText('foo').appendPlaceholder('far$boo').appendText('bar'); - assert.equal(string.value, 'foo${1:far\\$boo}bar'); + assert.strictEqual(string.value, 'foo${1:far\\$boo}bar'); string = new types.SnippetString(); string.appendText('foo').appendPlaceholder(b => b.appendText('abc').appendPlaceholder('nested')).appendText('bar'); - assert.equal(string.value, 'foo${1:abc${2:nested}}bar'); + assert.strictEqual(string.value, 'foo${1:abc${2:nested}}bar'); string = new types.SnippetString(); string.appendVariable('foo'); - assert.equal(string.value, '${foo}'); + assert.strictEqual(string.value, '${foo}'); string = new types.SnippetString(); string.appendText('foo').appendVariable('TM_SELECTED_TEXT').appendText('bar'); - assert.equal(string.value, 'foo${TM_SELECTED_TEXT}bar'); + assert.strictEqual(string.value, 'foo${TM_SELECTED_TEXT}bar'); string = new types.SnippetString(); string.appendVariable('BAR', b => b.appendPlaceholder('ops')); - assert.equal(string.value, '${BAR:${1:ops}}'); + assert.strictEqual(string.value, '${BAR:${1:ops}}'); string = new types.SnippetString(); string.appendVariable('BAR', b => { }); - assert.equal(string.value, '${BAR}'); + assert.strictEqual(string.value, '${BAR}'); string = new types.SnippetString(); string.appendChoice(['b', 'a', 'r']); - assert.equal(string.value, '${1|b,a,r|}'); + assert.strictEqual(string.value, '${1|b,a,r|}'); string = new types.SnippetString(); string.appendChoice(['b,1', 'a,2', 'r,3']); - assert.equal(string.value, '${1|b\\,1,a\\,2,r\\,3|}'); + assert.strictEqual(string.value, '${1|b\\,1,a\\,2,r\\,3|}'); string = new types.SnippetString(); string.appendChoice(['b', 'a', 'r'], 0); - assert.equal(string.value, '${0|b,a,r|}'); + assert.strictEqual(string.value, '${0|b,a,r|}'); string = new types.SnippetString(); string.appendText('foo').appendChoice(['far', 'boo']).appendText('bar'); - assert.equal(string.value, 'foo${1|far,boo|}bar'); + assert.strictEqual(string.value, 'foo${1|far,boo|}bar'); string = new types.SnippetString(); string.appendText('foo').appendChoice(['far', '$boo']).appendText('bar'); - assert.equal(string.value, 'foo${1|far,\\$boo|}bar'); + assert.strictEqual(string.value, 'foo${1|far,\\$boo|}bar'); string = new types.SnippetString(); string.appendText('foo').appendPlaceholder('farboo').appendChoice(['far', 'boo']).appendText('bar'); - assert.equal(string.value, 'foo${1:farboo}${2|far,boo|}bar'); + assert.strictEqual(string.value, 'foo${1:farboo}${2|far,boo|}bar'); }); test('instanceof doesn\'t work for FileSystemError #49386', function () { @@ -584,7 +584,7 @@ suite('ExtHostTypes', function () { builder.push(1, 0, 5, 1, 1); builder.push(1, 10, 4, 2, 2); builder.push(2, 2, 3, 2, 2); - assert.deepEqual(toArr(builder.build().data), [ + assert.deepStrictEqual(toArr(builder.build().data), [ 1, 0, 5, 1, 1, 0, 10, 4, 2, 2, 1, 2, 3, 2, 2 @@ -596,7 +596,7 @@ suite('ExtHostTypes', function () { builder.push(1, 0, 5, 1); builder.push(1, 10, 4, 2); builder.push(2, 2, 3, 2); - assert.deepEqual(toArr(builder.build().data), [ + assert.deepStrictEqual(toArr(builder.build().data), [ 1, 0, 5, 1, 0, 0, 10, 4, 2, 0, 1, 2, 3, 2, 0 @@ -609,7 +609,7 @@ suite('ExtHostTypes', function () { builder.push(2, 10, 1, 2, 2); builder.push(2, 15, 2, 3, 3); builder.push(1, 0, 4, 4, 4); - assert.deepEqual(toArr(builder.build().data), [ + assert.deepStrictEqual(toArr(builder.build().data), [ 1, 0, 4, 4, 4, 1, 0, 5, 1, 1, 0, 10, 1, 2, 2, @@ -621,7 +621,7 @@ suite('ExtHostTypes', function () { const builder = new types.SemanticTokensBuilder(); builder.push(2, 10, 5, 1, 1); builder.push(2, 2, 4, 2, 2); - assert.deepEqual(toArr(builder.build().data), [ + assert.deepStrictEqual(toArr(builder.build().data), [ 2, 2, 4, 2, 2, 0, 8, 5, 1, 1 ]); @@ -636,7 +636,7 @@ suite('ExtHostTypes', function () { builder.push(new types.Range(1, 0, 1, 5), 'bType'); builder.push(new types.Range(2, 0, 2, 4), 'cType', ['mod0', 'mod5']); builder.push(new types.Range(3, 0, 3, 3), 'dType', ['mod2', 'mod4']); - assert.deepEqual(toArr(builder.build().data), [ + assert.deepStrictEqual(toArr(builder.build().data), [ 1, 0, 5, 1, 0, 1, 0, 4, 2, 1 | (1 << 5), 1, 0, 3, 3, (1 << 2) | (1 << 4) @@ -645,7 +645,7 @@ suite('ExtHostTypes', function () { test('Markdown codeblock rendering is swapped #111604', function () { const md = new types.MarkdownString().appendCodeblock('', 'html'); - assert.deepEqual(md.value, '\n```html\n\n```\n'); + assert.deepStrictEqual(md.value, '\n```html\n\n```\n'); }); }); diff --git a/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts index a3eacd6e2989..894d43726d43 100644 --- a/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/browser/api/extHostWorkspace.test.ts @@ -52,7 +52,7 @@ suite('ExtHostWorkspace', function () { function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) { const actual = workspace.getRelativePath(input, includeWorkspace); - assert.equal(actual, expected); + assert.strictEqual(actual, expected); } test('asRelativePath', () => { @@ -116,19 +116,19 @@ suite('ExtHostWorkspace', function () { test('getPath, legacy', function () { let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService()); - assert.equal(ws.getPath(), undefined); + assert.strictEqual(ws.getPath(), undefined); ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService()); - assert.equal(ws.getPath(), undefined); + assert.strictEqual(ws.getPath(), undefined); ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService()); - assert.equal(ws.getPath(), undefined); + assert.strictEqual(ws.getPath(), undefined); ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService()); - assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); + assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService()); - assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); + assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { @@ -136,10 +136,10 @@ suite('ExtHostWorkspace', function () { const [one, two] = ws.getWorkspaceFolders()!; - assert.equal(one.name, 'One'); - assert.equal(one.index, 0); - assert.equal(two.name, 'Two'); - assert.equal(two.index, 1); + assert.strictEqual(one.name, 'One'); + assert.strictEqual(one.index, 0); + assert.strictEqual(two.name, 'Two'); + assert.strictEqual(two.index, 1); }); test('getContainingWorkspaceFolder', () => { @@ -154,40 +154,40 @@ suite('ExtHostWorkspace', function () { }, new NullLogService()); let folder = ws.getWorkspaceFolder(URI.file('/foo/bar')); - assert.equal(folder, undefined); + assert.strictEqual(folder, undefined); folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'))!; - assert.equal(folder.name, 'One'); + assert.strictEqual(folder.name, 'One'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'))!; - assert.equal(folder.name, 'Two'); + assert.strictEqual(folder.name, 'Two'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'))!; - assert.equal(folder.name, 'Two'); + assert.strictEqual(folder.name, 'Two'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'))!; - assert.equal(folder.name, 'Nested'); + assert.strictEqual(folder.name, 'Nested'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'))!; - assert.equal(folder.name, 'Nested'); + assert.strictEqual(folder.name, 'Nested'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true)!; - assert.equal(folder.name, 'Two'); + assert.strictEqual(folder.name, 'Two'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true)!; - assert.equal(folder.name, 'Two'); + assert.strictEqual(folder.name, 'Two'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'))!; - assert.equal(folder.name, 'Nested'); + assert.strictEqual(folder.name, 'Nested'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'))!; - assert.equal(folder.name, 'Nested'); + assert.strictEqual(folder.name, 'Nested'); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true)!; - assert.equal(folder, undefined); + assert.strictEqual(folder, undefined); folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false)!; - assert.equal(folder.name, 'Two'); + assert.strictEqual(folder.name, 'Two'); }); test('Multiroot change event should have a delta, #29641', function (done) { @@ -203,8 +203,8 @@ suite('ExtHostWorkspace', function () { let sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.added, []); - assert.deepEqual(e.removed, []); + assert.deepStrictEqual(e.added, []); + assert.deepStrictEqual(e.removed, []); } catch (error) { finish(error); } @@ -214,9 +214,9 @@ suite('ExtHostWorkspace', function () { sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.removed, []); - assert.equal(e.added.length, 1); - assert.equal(e.added[0].uri.toString(), 'foo:bar'); + assert.deepStrictEqual(e.removed, []); + assert.strictEqual(e.added.length, 1); + assert.strictEqual(e.added[0].uri.toString(), 'foo:bar'); } catch (error) { finish(error); } @@ -226,9 +226,9 @@ suite('ExtHostWorkspace', function () { sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.removed, []); - assert.equal(e.added.length, 1); - assert.equal(e.added[0].uri.toString(), 'foo:bar2'); + assert.deepStrictEqual(e.removed, []); + assert.strictEqual(e.added.length, 1); + assert.strictEqual(e.added[0].uri.toString(), 'foo:bar2'); } catch (error) { finish(error); } @@ -238,12 +238,12 @@ suite('ExtHostWorkspace', function () { sub = ws.onDidChangeWorkspace(e => { try { - assert.equal(e.removed.length, 2); - assert.equal(e.removed[0].uri.toString(), 'foo:bar'); - assert.equal(e.removed[1].uri.toString(), 'foo:bar2'); + assert.strictEqual(e.removed.length, 2); + assert.strictEqual(e.removed[0].uri.toString(), 'foo:bar'); + assert.strictEqual(e.removed[1].uri.toString(), 'foo:bar2'); - assert.equal(e.added.length, 1); - assert.equal(e.added[0].uri.toString(), 'foo:bar3'); + assert.strictEqual(e.added.length, 1); + assert.strictEqual(e.added[0].uri.toString(), 'foo:bar3'); } catch (error) { finish(error); } @@ -259,13 +259,13 @@ suite('ExtHostWorkspace', function () { let firstFolder = ws.getWorkspaceFolders()![0]; ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] }); - assert.equal(ws.getWorkspaceFolders()![1], firstFolder); - assert.equal(firstFolder.index, 1); - assert.equal(firstFolder.name, 'renamed'); + assert.strictEqual(ws.getWorkspaceFolders()![1], firstFolder); + assert.strictEqual(firstFolder.index, 1); + assert.strictEqual(firstFolder.name, 'renamed'); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] }); - assert.equal(ws.getWorkspaceFolders()![2], firstFolder); - assert.equal(firstFolder.index, 2); + assert.strictEqual(ws.getWorkspaceFolders()![2], firstFolder); + assert.strictEqual(firstFolder.index, 2); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] }); @@ -276,18 +276,18 @@ suite('ExtHostWorkspace', function () { test('updateWorkspaceFolders - invalid arguments', function () { let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService()); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1)); ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService()); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2)); - assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar')))); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2)); + assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar')))); }); test('updateWorkspaceFolders - valid arguments', function (done) { @@ -312,38 +312,38 @@ suite('ExtHostWorkspace', function () { // Add one folder // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar')))); - assert.equal(1, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar')))); + assert.strictEqual(1, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); const firstAddedFolder = ws.getWorkspaceFolders()![0]; let gotEvent = false; let sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.removed, []); - assert.equal(e.added.length, 1); - assert.equal(e.added[0].uri.toString(), 'foo:bar'); - assert.equal(e.added[0], firstAddedFolder); // verify object is still live + assert.deepStrictEqual(e.removed, []); + assert.strictEqual(e.added.length, 1); + assert.strictEqual(e.added[0].uri.toString(), 'foo:bar'); + assert.strictEqual(e.added[0], firstAddedFolder); // verify object is still live gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live // // Add two more folders // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2')))); - assert.equal(3, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); - assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString()); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2')))); + assert.strictEqual(3, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString()); const secondAddedFolder = ws.getWorkspaceFolders()![1]; const thirdAddedFolder = ws.getWorkspaceFolders()![2]; @@ -351,91 +351,91 @@ suite('ExtHostWorkspace', function () { gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.removed, []); - assert.equal(e.added.length, 2); - assert.equal(e.added[0].uri.toString(), 'foo:bar1'); - assert.equal(e.added[1].uri.toString(), 'foo:bar2'); - assert.equal(e.added[0], secondAddedFolder); - assert.equal(e.added[1], thirdAddedFolder); + assert.deepStrictEqual(e.removed, []); + assert.strictEqual(e.added.length, 2); + assert.strictEqual(e.added[0].uri.toString(), 'foo:bar1'); + assert.strictEqual(e.added[1].uri.toString(), 'foo:bar2'); + assert.strictEqual(e.added[0], secondAddedFolder); + assert.strictEqual(e.added[1], thirdAddedFolder); gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1), aWorkspaceFolderData(URI.parse('foo:bar2'), 2)] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live // // Remove one folder // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1)); - assert.equal(2, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1)); + assert.strictEqual(2, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.added, []); - assert.equal(e.removed.length, 1); - assert.equal(e.removed[0], thirdAddedFolder); + assert.deepStrictEqual(e.added, []); + assert.strictEqual(e.removed.length, 1); + assert.strictEqual(e.removed[0], thirdAddedFolder); gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live // // Rename folder // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2'))); - assert.equal(2, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); - assert.equal(ws.workspace!.folders[0].name, 'renamed 1'); - assert.equal(ws.workspace!.folders[1].name, 'renamed 2'); - assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1'); - assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2'); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2'))); + assert.strictEqual(2, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1'); + assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2'); + assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1'); + assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2'); gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.deepEqual(e.added, []); - assert.equal(e.removed.length, []); + assert.deepStrictEqual(e.added, []); + assert.strictEqual(e.removed.length, 0); gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0, 'renamed 1'), aWorkspaceFolderData(URI.parse('foo:bar1'), 1, 'renamed 2')] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live - assert.equal(ws.workspace!.folders[0].name, 'renamed 1'); - assert.equal(ws.workspace!.folders[1].name, 'renamed 2'); - assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1'); - assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2'); + assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live + assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1'); + assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2'); + assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1'); + assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2'); // // Add and remove folders // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4')))); - assert.equal(2, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString()); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4')))); + assert.strictEqual(2, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString()); const fourthAddedFolder = ws.getWorkspaceFolders()![0]; const fifthAddedFolder = ws.getWorkspaceFolders()![1]; @@ -443,71 +443,71 @@ suite('ExtHostWorkspace', function () { gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.equal(e.added.length, 2); - assert.equal(e.added[0], fourthAddedFolder); - assert.equal(e.added[1], fifthAddedFolder); - assert.equal(e.removed.length, 2); - assert.equal(e.removed[0], firstAddedFolder); - assert.equal(e.removed[1], secondAddedFolder); + assert.strictEqual(e.added.length, 2); + assert.strictEqual(e.added[0], fourthAddedFolder); + assert.strictEqual(e.added[1], fifthAddedFolder); + assert.strictEqual(e.removed.length, 2); + assert.strictEqual(e.removed[0], firstAddedFolder); + assert.strictEqual(e.removed[1], secondAddedFolder); gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live // // Swap folders // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3')))); - assert.equal(2, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3')))); + assert.strictEqual(2, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.equal(e.added.length, 0); - assert.equal(e.removed.length, 0); + assert.strictEqual(e.added.length, 0); + assert.strictEqual(e.removed.length, 0); gotEvent = true; } catch (error) { finish(error); } }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live - assert.equal(fifthAddedFolder.index, 0); - assert.equal(fourthAddedFolder.index, 1); + assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live + assert.strictEqual(fifthAddedFolder.index, 0); + assert.strictEqual(fourthAddedFolder.index, 1); // // Add one folder after the other without waiting for confirmation (not supported currently) // - assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5')))); + assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5')))); - assert.equal(3, ws.workspace!.folders.length); - assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); - assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString()); + assert.strictEqual(3, ws.workspace!.folders.length); + assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); + assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); + assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString()); const sixthAddedFolder = ws.getWorkspaceFolders()![2]; gotEvent = false; sub = ws.onDidChangeWorkspace(e => { try { - assert.equal(e.added.length, 1); - assert.equal(e.added[0], sixthAddedFolder); + assert.strictEqual(e.added.length, 1); + assert.strictEqual(e.added[0], sixthAddedFolder); gotEvent = true; } catch (error) { finish(error); @@ -520,12 +520,12 @@ suite('ExtHostWorkspace', function () { aWorkspaceFolderData(URI.parse('foo:bar5'), 2) ] }); // simulate acknowledgement from main side - assert.equal(gotEvent, true); + assert.strictEqual(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live + assert.strictEqual(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live finish(); }); @@ -591,10 +591,10 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(includePattern, 'foo'); - assert.equal(_includeFolder, null); - assert.equal(excludePatternOrDisregardExcludes, null); - assert.equal(maxResults, 10); + assert.strictEqual(includePattern, 'foo'); + assert.strictEqual(_includeFolder, null); + assert.strictEqual(excludePatternOrDisregardExcludes, null); + assert.strictEqual(maxResults, 10); return Promise.resolve(null); } }); @@ -613,9 +613,9 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(includePattern, 'glob/**'); - assert.deepEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON()); - assert.equal(excludePatternOrDisregardExcludes, null); + assert.strictEqual(includePattern, 'glob/**'); + assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON()); + assert.strictEqual(excludePatternOrDisregardExcludes, null); return Promise.resolve(null); } }); @@ -642,9 +642,9 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(includePattern, 'glob/**'); - assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); - assert.equal(excludePatternOrDisregardExcludes, false); + assert.strictEqual(includePattern, 'glob/**'); + assert.deepStrictEqual(_includeFolder, URI.file('/other/folder').toJSON()); + assert.strictEqual(excludePatternOrDisregardExcludes, false); return Promise.resolve(null); } }); @@ -702,10 +702,10 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(query.pattern, 'foo'); - assert.equal(folder, null); - assert.equal(options.includePattern, null); - assert.equal(options.excludePattern, null); + assert.strictEqual(query.pattern, 'foo'); + assert.strictEqual(folder, null); + assert.strictEqual(options.includePattern, undefined); + assert.strictEqual(options.excludePattern, undefined); return null; } }); @@ -723,10 +723,10 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(query.pattern, 'foo'); - assert.equal(folder, null); - assert.equal(options.includePattern, '**/files'); - assert.equal(options.excludePattern, null); + assert.strictEqual(query.pattern, 'foo'); + assert.strictEqual(folder, null); + assert.strictEqual(options.includePattern, '**/files'); + assert.strictEqual(options.excludePattern, undefined); return null; } }); @@ -744,10 +744,10 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(query.pattern, 'foo'); - assert.deepEqual(folder, URI.file('/other/folder').toJSON()); - assert.equal(options.includePattern, 'glob/**'); - assert.equal(options.excludePattern, null); + assert.strictEqual(query.pattern, 'foo'); + assert.deepStrictEqual(folder, URI.file('/other/folder').toJSON()); + assert.strictEqual(options.includePattern, 'glob/**'); + assert.strictEqual(options.excludePattern, undefined); return null; } }); @@ -783,10 +783,10 @@ suite('ExtHostWorkspace', function () { rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise { mainThreadCalled = true; - assert.equal(query.pattern, 'foo'); - assert.deepEqual(folder, null); - assert.equal(options.includePattern, null); - assert.equal(options.excludePattern, 'glob/**'); // exclude folder is ignored... + assert.strictEqual(query.pattern, 'foo'); + assert.deepStrictEqual(folder, null); + assert.strictEqual(options.includePattern, undefined); + assert.strictEqual(options.excludePattern, 'glob/**'); // exclude folder is ignored... return null; } }); diff --git a/src/vs/workbench/test/browser/api/mainThreadCommands.test.ts b/src/vs/workbench/test/browser/api/mainThreadCommands.test.ts index f761c11ce08f..65dc8e42be38 100644 --- a/src/vs/workbench/test/browser/api/mainThreadCommands.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadCommands.test.ts @@ -15,7 +15,7 @@ suite('MainThreadCommands', function () { test('dispose on unregister', function () { const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock() { }); - assert.equal(CommandsRegistry.getCommand('foo'), undefined); + assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); // register commands.$registerCommand('foo'); @@ -23,13 +23,13 @@ suite('MainThreadCommands', function () { // unregister commands.$unregisterCommand('foo'); - assert.equal(CommandsRegistry.getCommand('foo'), undefined); + assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); }); test('unregister all on dispose', function () { const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock() { }); - assert.equal(CommandsRegistry.getCommand('foo'), undefined); + assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); commands.$registerCommand('foo'); commands.$registerCommand('bar'); @@ -39,8 +39,8 @@ suite('MainThreadCommands', function () { commands.dispose(); - assert.equal(CommandsRegistry.getCommand('foo'), undefined); - assert.equal(CommandsRegistry.getCommand('bar'), undefined); + assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); + assert.strictEqual(CommandsRegistry.getCommand('bar'), undefined); }); test('activate and throw when needed', async function () { @@ -70,18 +70,18 @@ suite('MainThreadCommands', function () { await commands.$executeCommand('bazz', [1, 2, { n: 3 }], true); assert.ok(false); } catch (e) { - assert.deepEqual(activations, ['onCommand:bazz']); - assert.equal((e).message, '$executeCommand:retry'); + assert.deepStrictEqual(activations, ['onCommand:bazz']); + assert.strictEqual((e).message, '$executeCommand:retry'); } // case 2: no arguments and retry runs.length = 0; await commands.$executeCommand('bazz', [], true); - assert.deepEqual(runs, ['bazz']); + assert.deepStrictEqual(runs, ['bazz']); // case 3: arguments and no retry runs.length = 0; await commands.$executeCommand('bazz', [1, 2, true], false); - assert.deepEqual(runs, ['bazz']); + assert.deepStrictEqual(runs, ['bazz']); }); }); diff --git a/src/vs/workbench/test/browser/api/mainThreadConfiguration.test.ts b/src/vs/workbench/test/browser/api/mainThreadConfiguration.test.ts index db13edd9507f..23455e4ef1ba 100644 --- a/src/vs/workbench/test/browser/api/mainThreadConfiguration.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadConfiguration.test.ts @@ -65,7 +65,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -74,7 +74,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -83,7 +83,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -92,7 +92,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { @@ -101,7 +101,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -110,7 +110,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -119,7 +119,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to folder', function () { @@ -128,7 +128,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('update configuration with user configuration target', function () { @@ -137,7 +137,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(ConfigurationTarget.USER, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.USER, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.USER, target.args[0][3]); }); test('update configuration with workspace configuration target', function () { @@ -146,7 +146,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update configuration with folder configuration target', function () { @@ -155,7 +155,7 @@ suite('MainThreadConfiguration', function () { testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE_FOLDER, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -164,7 +164,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -173,7 +173,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -182,7 +182,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { @@ -191,7 +191,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { @@ -200,7 +200,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { @@ -209,7 +209,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { @@ -218,7 +218,7 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', undefined, undefined); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove configuration without configuration target defaults to folder', function () { @@ -227,6 +227,6 @@ suite('MainThreadConfiguration', function () { testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', { resource: URI.file('abc') }, undefined); - assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); + assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); }); diff --git a/src/vs/workbench/test/browser/api/mainThreadDiagnostics.test.ts b/src/vs/workbench/test/browser/api/mainThreadDiagnostics.test.ts index 958e2a2f7ca0..6f28fccec7b8 100644 --- a/src/vs/workbench/test/browser/api/mainThreadDiagnostics.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadDiagnostics.test.ts @@ -53,8 +53,8 @@ suite('MainThreadDiagnostics', function () { source: 'me' }]]]); - assert.equal(markerService.read().length, 1); + assert.strictEqual(markerService.read().length, 1); diag.dispose(); - assert.equal(markerService.read().length, 0); + assert.strictEqual(markerService.read().length, 0); }); }); diff --git a/src/vs/workbench/test/browser/api/mainThreadDocumentContentProviders.test.ts b/src/vs/workbench/test/browser/api/mainThreadDocumentContentProviders.test.ts index f8f606f9829d..44e7a8a7e084 100644 --- a/src/vs/workbench/test/browser/api/mainThreadDocumentContentProviders.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadDocumentContentProviders.test.ts @@ -23,13 +23,13 @@ suite('MainThreadDocumentContentProviders', function () { let providers = new MainThreadDocumentContentProviders(new TestRPCProtocol(), null!, null!, new class extends mock() { getModel(_uri: URI) { - assert.equal(uri.toString(), _uri.toString()); + assert.strictEqual(uri.toString(), _uri.toString()); return model; } }, new class extends mock() { computeMoreMinimalEdits(_uri: URI, data: TextEdit[] | undefined) { - assert.equal(model.getValue(), '1'); + assert.strictEqual(model.getValue(), '1'); return Promise.resolve(data); } }, diff --git a/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts b/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts index 7740d677a42a..57be38dfd980 100644 --- a/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts @@ -32,7 +32,7 @@ suite('BoundModelReferenceCollection', () => { }); await timeout(30); - assert.equal(didDispose, true); + assert.strictEqual(didDispose, true); }); test('max size', () => { @@ -66,7 +66,7 @@ suite('BoundModelReferenceCollection', () => { } }); - assert.deepEqual(disposed, [0, 1]); + assert.deepStrictEqual(disposed, [0, 1]); }); test('dispose uri', () => { @@ -119,15 +119,15 @@ suite('BoundModelReferenceCollection', () => { }); col.remove(URI.parse('test:///unknown')); - assert.equal(disposed.length, 0); + assert.strictEqual(disposed.length, 0); col.remove(URI.parse('test:///farboo')); - assert.deepEqual(disposed, [0]); + assert.deepStrictEqual(disposed, [0]); disposed = []; col.remove(URI.parse('test:///boo')); - assert.deepEqual(disposed, [2, 3]); + assert.deepStrictEqual(disposed, [2, 3]); }); }); diff --git a/src/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts index d99fdd7abb77..da3e167dfd20 100644 --- a/src/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts @@ -110,14 +110,14 @@ suite('MainThreadDocumentsAndEditors', () => { modelService.createModel('farboo', null); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); const [delta] = deltas; - assert.equal(delta.addedDocuments!.length, 1); - assert.equal(delta.removedDocuments, undefined); - assert.equal(delta.addedEditors, undefined); - assert.equal(delta.removedEditors, undefined); - assert.equal(delta.newActiveEditor, null); + assert.strictEqual(delta.addedDocuments!.length, 1); + assert.strictEqual(delta.removedDocuments, undefined); + assert.strictEqual(delta.addedEditors, undefined); + assert.strictEqual(delta.removedEditors, undefined); + assert.strictEqual(delta.newActiveEditor, undefined); }); test('ignore huge model', function () { @@ -126,13 +126,13 @@ suite('MainThreadDocumentsAndEditors', () => { const model = modelService.createModel(hugeModelString, null); assert.ok(model.isTooLargeForSyncing()); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); const [delta] = deltas; - assert.equal(delta.newActiveEditor, null); - assert.equal(delta.addedDocuments, undefined); - assert.equal(delta.removedDocuments, undefined); - assert.equal(delta.addedEditors, undefined); - assert.equal(delta.removedEditors, undefined); + assert.strictEqual(delta.newActiveEditor, null); + assert.strictEqual(delta.addedDocuments, undefined); + assert.strictEqual(delta.removedDocuments, undefined); + assert.strictEqual(delta.addedEditors, undefined); + assert.strictEqual(delta.removedEditors, undefined); }); test('ignore simple widget model', function () { @@ -141,13 +141,13 @@ suite('MainThreadDocumentsAndEditors', () => { const model = modelService.createModel('test', null, undefined, true); assert.ok(model.isForSimpleWidget); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); const [delta] = deltas; - assert.equal(delta.newActiveEditor, null); - assert.equal(delta.addedDocuments, undefined); - assert.equal(delta.removedDocuments, undefined); - assert.equal(delta.addedEditors, undefined); - assert.equal(delta.removedEditors, undefined); + assert.strictEqual(delta.newActiveEditor, null); + assert.strictEqual(delta.addedDocuments, undefined); + assert.strictEqual(delta.removedDocuments, undefined); + assert.strictEqual(delta.addedEditors, undefined); + assert.strictEqual(delta.removedEditors, undefined); }); test('ignore huge model from editor', function () { @@ -156,22 +156,22 @@ suite('MainThreadDocumentsAndEditors', () => { const model = modelService.createModel(hugeModelString, null); const editor = myCreateTestCodeEditor(model); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); deltas.length = 0; - assert.equal(deltas.length, 0); + assert.strictEqual(deltas.length, 0); editor.dispose(); }); test('ignore editor w/o model', () => { const editor = myCreateTestCodeEditor(undefined); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); const [delta] = deltas; - assert.equal(delta.newActiveEditor, null); - assert.equal(delta.addedDocuments, undefined); - assert.equal(delta.removedDocuments, undefined); - assert.equal(delta.addedEditors, undefined); - assert.equal(delta.removedEditors, undefined); + assert.strictEqual(delta.newActiveEditor, null); + assert.strictEqual(delta.addedDocuments, undefined); + assert.strictEqual(delta.removedDocuments, undefined); + assert.strictEqual(delta.addedEditors, undefined); + assert.strictEqual(delta.removedEditors, undefined); editor.dispose(); }); @@ -182,19 +182,19 @@ suite('MainThreadDocumentsAndEditors', () => { const model = modelService.createModel('farboo', null); const editor = myCreateTestCodeEditor(model); - assert.equal(deltas.length, 2); + assert.strictEqual(deltas.length, 2); const [first, second] = deltas; - assert.equal(first.addedDocuments!.length, 1); - assert.equal(first.newActiveEditor, null); - assert.equal(first.removedDocuments, undefined); - assert.equal(first.addedEditors, undefined); - assert.equal(first.removedEditors, undefined); + assert.strictEqual(first.addedDocuments!.length, 1); + assert.strictEqual(first.newActiveEditor, undefined); + assert.strictEqual(first.removedDocuments, undefined); + assert.strictEqual(first.addedEditors, undefined); + assert.strictEqual(first.removedEditors, undefined); - assert.equal(second.addedEditors!.length, 1); - assert.equal(second.addedDocuments, undefined); - assert.equal(second.removedDocuments, undefined); - assert.equal(second.removedEditors, undefined); - assert.equal(second.newActiveEditor, undefined); + assert.strictEqual(second.addedEditors!.length, 1); + assert.strictEqual(second.addedDocuments, undefined); + assert.strictEqual(second.removedDocuments, undefined); + assert.strictEqual(second.removedEditors, undefined); + assert.strictEqual(second.newActiveEditor, undefined); editor.dispose(); }); @@ -208,14 +208,14 @@ suite('MainThreadDocumentsAndEditors', () => { deltas.length = 0; modelService.destroyModel(model.uri); - assert.equal(deltas.length, 1); + assert.strictEqual(deltas.length, 1); const [first] = deltas; - assert.equal(first.newActiveEditor, null); - assert.equal(first.removedEditors!.length, 1); - assert.equal(first.removedDocuments!.length, 1); - assert.equal(first.addedDocuments, undefined); - assert.equal(first.addedEditors, undefined); + assert.strictEqual(first.newActiveEditor, undefined); + assert.strictEqual(first.removedEditors!.length, 1); + assert.strictEqual(first.removedDocuments!.length, 1); + assert.strictEqual(first.addedDocuments, undefined); + assert.strictEqual(first.addedEditors, undefined); editor.dispose(); }); diff --git a/src/vs/workbench/test/browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/browser/api/mainThreadEditors.test.ts index 3313fbb0102a..aa78d9fcde23 100644 --- a/src/vs/workbench/test/browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadEditors.test.ts @@ -199,7 +199,7 @@ suite('MainThreadEditors', () => { model.applyEdits([EditOperation.insert(new Position(0, 0), 'something')]); return editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit] }).then((result) => { - assert.equal(result, false); + assert.strictEqual(result, false); }); }); @@ -228,11 +228,11 @@ suite('MainThreadEditors', () => { let p1 = editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit1] }).then((result) => { // first edit request succeeds - assert.equal(result, true); + assert.strictEqual(result, true); }); let p2 = editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit2] }).then((result) => { // second edit request fails - assert.equal(result, false); + assert.strictEqual(result, false); }); return Promise.all([p1, p2]); }); @@ -245,10 +245,10 @@ suite('MainThreadEditors', () => { { _type: WorkspaceEditType.File, oldUri: resource, newUri: undefined, options: undefined } ] }).then((result) => { - assert.equal(result, true); - assert.equal(movedResources.get(resource), resource); - assert.equal(createdResources.has(resource), true); - assert.equal(deletedResources.has(resource), true); + assert.strictEqual(result, true); + assert.strictEqual(movedResources.get(resource), resource); + assert.strictEqual(createdResources.has(resource), true); + assert.strictEqual(deletedResources.has(resource), true); }); }); }); diff --git a/yarn.lock b/yarn.lock index c6f15827b5e6..246eff87a362 100644 --- a/yarn.lock +++ b/yarn.lock @@ -348,11 +348,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== -"@types/node@^13.13.5": - version "13.13.34" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.34.tgz#c9300a1b6560d90817fb2bba650e250116a575f9" - integrity sha512-g8D1HF2dMDKYSDl5+79izRwRgNPsSynmWMbj50mj7GZ0b7Lv4p8EmZjbo3h0h+6iLr6YmVz9VnF6XVZ3O6V1Ug== - "@types/semver@^5.4.0", "@types/semver@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" @@ -1194,9 +1189,11 @@ asn1.js@^4.0.0: minimalistic-assert "^1.0.0" asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" @@ -1377,9 +1374,9 @@ base@^0.11.1: pascalcase "^0.1.1" bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - integrity sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40= + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" @@ -1471,9 +1468,9 @@ boom@5.x.x: hoek "4.x.x" brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - integrity sha1-wHshHHyVLsH479Uad+8NHTmQopI= + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -2313,11 +2310,11 @@ concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0: typedarray "^0.0.6" concat-with-sourcemaps@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz#f55b3be2aeb47601b10a2d5259ccfb70fd2f1dd6" - integrity sha1-9Vs74q60dgGxCi1SWcz7cP0vHdY= + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== dependencies: - source-map "^0.5.1" + source-map "^0.6.1" config-chain@^1.1.11, config-chain@^1.1.12: version "1.1.12" @@ -2991,11 +2988,12 @@ each-props@^1.3.0: object.defaults "^1.1.0" ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU= + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" + safer-buffer "^2.1.0" editorconfig@^0.15.0: version "0.15.0" @@ -4115,9 +4113,9 @@ fsevents@~2.3.1: integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -4302,7 +4300,7 @@ glob-watcher@^5.0.0: just-debounce "^1.0.0" object.defaults "^1.1.0" -glob@7.1.6, glob@^7.1.4, glob@^7.1.6: +glob@7.1.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -4325,7 +4323,7 @@ glob@^5.0.13, glob@^5.0.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -4337,18 +4335,6 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-agent@^2.0.2: version "2.1.7" resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.1.7.tgz#12d7bc2b07cd862d0fa76b0f1b2c48cd5ffcf150" @@ -4494,21 +4480,16 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@4.2.3, graceful-fs@^4.2.0: +graceful-fs@4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== -graceful-fs@4.X, graceful-fs@^4.1.15, graceful-fs@^4.2.3: +graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= - growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -4994,9 +4975,9 @@ hmac-drbg@^1.0.0: minimalistic-crypto-utils "^1.0.1" hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ== + version "4.2.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" + integrity sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA== homedir-polyfill@^1.0.1: version "1.0.1" @@ -5195,20 +5176,20 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.7" @@ -6374,9 +6355,9 @@ lru-cache@^6.0.0: yallist "^4.0.0" macaddress@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" - integrity sha1-WQTcU3w57G2+/q6QIycTX6hRHxI= + version "0.2.9" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.9.tgz#3579b8b9acd5b96b4553abf0f394185a86813cb3" + integrity sha512-k4F1JUof6cQXxNFzx3thLby4oJzXTXQueAOOts944Vqizn+Rjc2QNFenT9FJSLU1CH3PmrHRSyZs2E+Cqw+P2w== make-dir@^2.0.0: version "2.1.0" @@ -6747,9 +6728,9 @@ mississippi@^3.0.0: through2 "^2.0.0" mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -6759,14 +6740,14 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" -mkdirp@^0.5.3: +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -8931,34 +8912,20 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2, rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^2.2.8: - version "2.6.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" - integrity sha1-wjOOxkPfeht/5cVPqG9XQopV8z0= - dependencies: - glob "^7.0.5" - -rimraf@^2.4.2, rimraf@^2.5.4, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== - dependencies: - glob "^7.0.5" - -rimraf@^2.6.3: +rimraf@2, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -9041,7 +9008,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -9502,18 +9469,18 @@ sprintf-js@~1.0.2: integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - integrity sha1-US322mKHFEMW3EwY/hzx2UBzm+M= + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" ecc-jsbn "~0.1.1" + getpass "^0.1.1" jsbn "~0.1.0" + safer-buffer "^2.0.2" tweetnacl "~0.14.0" ssri@^6.0.1: @@ -9711,9 +9678,9 @@ string_decoder@~1.0.3: safe-buffer "~5.1.0" stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= + version "0.0.6" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -10218,6 +10185,13 @@ ts-morph@^3.1.3: multimatch "^4.0.0" typescript "^3.0.1" +tsec@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/tsec/-/tsec-0.1.1.tgz#aed25d4aeea0d1f641d4c941c3da23db1a7d1ce2" + integrity sha512-hAQJlm4SXO5c8//rWNdIwa8CX9wcXeyxo0S+D5pgU+m88LEbXqd+FGyVaysbfnVf6yywpQFte3dpXaudOl+NeQ== + dependencies: + glob "^7.1.1" + tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -10292,11 +10266,6 @@ typescript@^3.0.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== -typescript@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" - integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== - typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" @@ -10749,16 +10718,6 @@ vscode-textmate@5.2.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== -vscode-tsec@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/vscode-tsec/-/vscode-tsec-0.0.3.tgz#2c9b4fbf822a9bcb177cd9e9ab46a782bba4628b" - integrity sha512-qak2mD8+FDRbC9mSjWQumc9vi1f3ATS7oLsROd3mJ9SFg+GTiRlpOmOpPPY+p+JI5AWNgkWDb/ztsFNGRex8jw== - dependencies: - "@types/glob" "^7.1.1" - "@types/node" "^13.13.5" - glob "^7.1.1" - typescript "^4.1.2" - vscode-windows-ca-certs@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.3.0.tgz#324e1f8ba842bbf048a39e7c0ee8fe655e9adfcc"