diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index c0063946355..d1f341353ec 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -223,6 +223,11 @@ "default": false, "description": "%emmetPreferencesOutputReverseAttributes%" }, + "output.selfClosingStyle": { + "type": "string", + "default": "html", + "description": "%emmetPreferencesOutputSelfClosingStyle%" + }, "css.color.short": { "type": "boolean", "default": true, diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index c7c5a7d7296..f8420144064 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -57,5 +57,6 @@ "emmetOptimizeStylesheetParsing": "When set to `false`, the whole file is parsed to determine if current position is valid for expanding Emmet abbreviations. When set to `true`, only the content around the current position in CSS/SCSS/Less files is parsed.", "emmetPreferencesOutputInlineBreak": "The number of sibling inline elements needed for line breaks to be placed between those elements. If `0`, inline elements are always expanded onto a single line.", "emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets.", + "emmetPreferencesOutputSelfClosingStyle": "Style of self-closing tags: html (`
`), xml (`
`) or xhtml (`
`).", "emmetPreferencesCssColorShort": "If `true`, color values like #f will be expanded to #fff instead of #ffffff." } diff --git a/extensions/emmet/src/selectItemHTML.ts b/extensions/emmet/src/selectItemHTML.ts index f818f5783a3..6400913396c 100644 --- a/extensions/emmet/src/selectItemHTML.ts +++ b/extensions/emmet/src/selectItemHTML.ts @@ -19,7 +19,7 @@ export function nextItemHTML(document: vscode.TextDocument, selectionStart: vsco if (currentNode.type !== 'comment') { // If cursor is in the tag name, select tag if (currentNode.open && - selectionEndOffset < currentNode.open.start + currentNode.name.length) { + selectionEndOffset <= currentNode.open.start + currentNode.name.length) { return getSelectionFromNode(document, currentNode); } diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index 6c8a9adeafd..091bf90f6c7 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -439,7 +439,7 @@ suite('Tests for jsx, xml and xsl', () => { return withRandomFileEditor('img', 'javascriptreact', async (editor, _doc) => { editor.selection = new Selection(0, 6, 0, 6); await expandEmmetAbbreviation({ language: 'javascriptreact' }); - assert.strictEqual(editor.document.getText(), ''); + assert.strictEqual(editor.document.getText(), ''); return Promise.resolve(); }); }); @@ -449,7 +449,7 @@ suite('Tests for jsx, xml and xsl', () => { return withRandomFileEditor('img', 'javascriptreact', async (editor, _doc) => { editor.selection = new Selection(0, 6, 0, 6); await expandEmmetAbbreviation({ language: 'javascriptreact' }); - assert.strictEqual(editor.document.getText(), '\'\'/'); + assert.strictEqual(editor.document.getText(), '\'\''); return workspace.getConfiguration('emmet').update('syntaxProfiles', oldValueForSyntaxProfiles ? oldValueForSyntaxProfiles.globalValue : undefined, ConfigurationTarget.Global); }); }); diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 3a3b8516d64..2eb808a8fd2 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -84,19 +84,19 @@ export function migrateEmmetExtensionsPath() { * Mapping between languages that support Emmet and completion trigger characters */ export const LANGUAGE_MODES: { [id: string]: string[] } = { - 'html': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'jade': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'slim': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'haml': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'xml': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'xsl': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'html': ['!', '.', '}', ':', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'jade': ['!', '.', '}', ':', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'slim': ['!', '.', '}', ':', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'haml': ['!', '.', '}', ':', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'xml': ['.', '}', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'xsl': ['!', '.', '}', '*', '$', '/', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'css': [':', '!', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'scss': [':', '!', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'sass': [':', '!', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'less': [':', '!', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'stylus': [':', '!', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'javascriptreact': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'typescriptreact': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] + 'javascriptreact': ['!', '.', '}', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'typescriptreact': ['!', '.', '}', '*', '$', ']', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] }; export function isStyleSheet(syntax: string): boolean { @@ -376,32 +376,36 @@ export const allowedMimeTypesInScriptTag = ['text/html', 'text/plain', 'text/x-t * If position is inside a script tag of type template, then it will be parsed to find the inner HTML node as well */ export function getHtmlFlatNode(documentText: string, root: FlatNode | undefined, offset: number, includeNodeBoundary: boolean): HtmlFlatNode | undefined { - const currentNode: HtmlFlatNode | undefined = getFlatNode(root, offset, includeNodeBoundary); + let currentNode: HtmlFlatNode | undefined = getFlatNode(root, offset, includeNodeBoundary); if (!currentNode) { return; } - const isTemplateScript = currentNode.name === 'script' && - (currentNode.attributes && - currentNode.attributes.some(x => x.name.toString() === 'type' - && allowedMimeTypesInScriptTag.includes(x.value.toString()))); - if (isTemplateScript - && currentNode.open - && offset > currentNode.open.end - && (!currentNode.close || offset < currentNode.close.start)) { - // blank out the rest of the document and search for the node within - const beforePadding = ' '.repeat(currentNode.open.end); - const endToUse = currentNode.close ? currentNode.close.start : currentNode.end; - const scriptBodyText = beforePadding + documentText.substring(currentNode.open.end, endToUse); - const innerRoot: HtmlFlatNode = parse(scriptBodyText); - const scriptBodyNode = getHtmlFlatNode(scriptBodyText, innerRoot, offset, includeNodeBoundary); - if (scriptBodyNode) { - scriptBodyNode.parent = currentNode; - currentNode.children.push(scriptBodyNode); - return scriptBodyNode; - } + // If the currentNode is a script one, first set up its subtree and then find HTML node. + if (currentNode.name === 'script' && currentNode.children.length === 0) { + setUpScriptNodeSubtree(documentText, currentNode); + currentNode = getFlatNode(currentNode, offset, includeNodeBoundary) ?? currentNode; } return currentNode; } +export function setUpScriptNodeSubtree(documentText: string, scriptNode: HtmlFlatNode): void { + const isTemplateScript = scriptNode.name === 'script' && + (scriptNode.attributes && + scriptNode.attributes.some(x => x.name.toString() === 'type' + && allowedMimeTypesInScriptTag.includes(x.value.toString()))); + if (isTemplateScript + && scriptNode.open) { + // blank out the rest of the document and generate the subtree. + const beforePadding = ' '.repeat(scriptNode.open.end); + const endToUse = scriptNode.close ? scriptNode.close.start : scriptNode.end; + const scriptBodyText = beforePadding + documentText.substring(scriptNode.open.end, endToUse); + const innerRoot: HtmlFlatNode = parse(scriptBodyText); + innerRoot.children.forEach(child => { + scriptNode.children.push(child); + child.parent = scriptNode; + }); + } +} + export function isOffsetInsideOpenOrCloseTag(node: FlatNode, offset: number): boolean { const htmlNode = node as HtmlFlatNode; if ((htmlNode.open && offset > htmlNode.open.start && offset < htmlNode.open.end) @@ -579,7 +583,7 @@ export function getEmmetConfiguration(syntax: string) { ) { syntaxProfiles[syntax] = { ...syntaxProfiles[syntax], - selfClosingStyle: 'xml' + selfClosingStyle: syntax === 'jsx' ? 'xhtml' : 'xml' }; } } diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 8e106ef4f12..76e3f8d72c3 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -77,9 +77,9 @@ jsonc-parser@^2.3.0: integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== vscode-emmet-helper@^2.3.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.4.3.tgz#c536006b7a36deec746725bde10331dca733936a" - integrity sha512-9VpzAMSF99TMqXrhptHu9reCoyAgELk1mw5Jdyaf9jFL2dGwrejY+636jLdIwCGLmZBOZVJ1ZV9R44Elx2HIoA== + version "2.4.4" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.4.4.tgz#f255120de921e2a017c5d48ca2f06e021430af99" + integrity sha512-I7yjgf4vMJRXFD1fN6kWt8WgCidjmcxGa4h+1nO0gSrtoj1/f0FNJ06o64HWt+2rTkwp8eQ9OU3imt5kQkdZ5A== dependencies: emmet "^2.3.0" jsonc-parser "^2.3.0" diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index f78f2cc369e..ae318036756 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -11,7 +11,7 @@ import * as which from 'which'; import { EventEmitter } from 'events'; import * as iconv from 'iconv-lite-umd'; import * as filetype from 'file-type'; -import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util'; +import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter, Versions } from './util'; import { CancellationToken, Progress, Uri } from 'vscode'; import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git'; @@ -377,6 +377,10 @@ export class Git { this.env = options.env || {}; } + compareGitVersionTo(version: string): -1 | 0 | 1 { + return Versions.compare(Versions.fromString(this.version), Versions.fromString(version)); + } + open(repository: string, dotGit: string): Repository { return new Repository(this, repository, dotGit); } @@ -1977,7 +1981,16 @@ export class Repository { return this.getHEAD(); } - const args = ['for-each-ref', '--format=%(refname)%00%(upstream:short)%00%(upstream:track)%00%(objectname)']; + const args = ['for-each-ref']; + + let supportsAheadBehind = true; + if (this._git.compareGitVersionTo('1.9.0') === -1) { + args.push('--format=%(refname)%00%(upstream:short)%00%(objectname)'); + supportsAheadBehind = false; + } else { + args.push('--format=%(refname)%00%(upstream:short)%00%(objectname)%00%(upstream:track)'); + } + if (/^refs\/(head|remotes)\//i.test(name)) { args.push(name); } else { @@ -1986,7 +1999,7 @@ export class Repository { const result = await this.exec(args); const branches: Branch[] = result.stdout.trim().split('\n').map(line => { - let [branchName, upstream, status, ref] = line.trim().split('\0'); + let [branchName, upstream, ref, status] = line.trim().split('\0'); if (branchName.startsWith('refs/heads/')) { branchName = branchName.substring(11); @@ -2026,7 +2039,19 @@ export class Repository { }).filter((b?: Branch): b is Branch => !!b); if (branches.length) { - return branches[0]; + const [branch] = branches; + + if (!supportsAheadBehind && branch.upstream) { + try { + const result = await this.exec(['rev-list', '--left-right', '--count', `${branch.name}...${branch.upstream.remote}/${branch.upstream.name}`]); + const [ahead, behind] = result.stdout.trim().split('\t'); + + (branch as any).ahead = Number(ahead) || 0; + (branch as any).behind = Number(behind) || 0; + } catch { } + } + + return branch; } return Promise.reject(new Error('No such branch')); diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index 89c7cbe688b..b5a46554ca1 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -414,3 +414,56 @@ export class PromiseSource { } } } + +export namespace Versions { + declare type VersionComparisonResult = -1 | 0 | 1; + + export interface Version { + major: number; + minor: number; + patch: number; + pre?: string; + } + + export function compare(v1: string | Version, v2: string | Version): VersionComparisonResult { + if (typeof v1 === 'string') { + v1 = fromString(v1); + } + if (typeof v2 === 'string') { + v2 = fromString(v2); + } + + if (v1.major > v2.major) { return 1; } + if (v1.major < v2.major) { return -1; } + + if (v1.minor > v2.minor) { return 1; } + if (v1.minor < v2.minor) { return -1; } + + if (v1.patch > v2.patch) { return 1; } + if (v1.patch < v2.patch) { return -1; } + + if (v1.pre === undefined && v2.pre !== undefined) { return 1; } + if (v1.pre !== undefined && v2.pre === undefined) { return -1; } + + if (v1.pre !== undefined && v2.pre !== undefined) { + return v1.pre.localeCompare(v2.pre) as VersionComparisonResult; + } + + return 0; + } + + export function from(major: string | number, minor: string | number, patch?: string | number, pre?: string): Version { + return { + major: typeof major === 'string' ? parseInt(major, 10) : major, + minor: typeof minor === 'string' ? parseInt(minor, 10) : minor, + patch: patch === undefined || patch === null ? 0 : typeof patch === 'string' ? parseInt(patch, 10) : patch, + pre: pre, + }; + } + + export function fromString(version: string): Version { + const [ver, pre] = version.split('-'); + const [major, minor, patch] = ver.split('.'); + return from(major, minor, patch, pre); + } +} diff --git a/extensions/typescript-language-features/src/tsServer/versionManager.ts b/extensions/typescript-language-features/src/tsServer/versionManager.ts index cdd85fb02d6..0115ced57c1 100644 --- a/extensions/typescript-language-features/src/tsServer/versionManager.ts +++ b/extensions/typescript-language-features/src/tsServer/versionManager.ts @@ -39,7 +39,7 @@ export class TypeScriptVersionManager extends Disposable { } } else { setImmediate(() => { - vscode.workspace.requireWorkspaceTrust({ modal: false }) + vscode.workspace.requestWorkspaceTrust({ modal: false }) .then(trustState => { if (trustState === vscode.WorkspaceTrustState.Trusted && this.versionProvider.localVersion) { this.updateActiveVersion(this.versionProvider.localVersion); @@ -120,7 +120,7 @@ export class TypeScriptVersionManager extends Disposable { description: version.displayName, detail: version.pathLabel, run: async () => { - const trustState = await vscode.workspace.requireWorkspaceTrust(); + const trustState = await vscode.workspace.requestWorkspaceTrust(); if (trustState === vscode.WorkspaceTrustState.Trusted) { await this.workspaceState.update(useWorkspaceTsdkStorageKey, true); const tsConfig = vscode.workspace.getConfiguration('typescript'); diff --git a/extensions/vscode-colorize-tests/test/colorize-fixtures/test-92369.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-92369.cpp deleted file mode 100644 index b91dec67af6..00000000000 --- a/extensions/vscode-colorize-tests/test/colorize-fixtures/test-92369.cpp +++ /dev/null @@ -1,3 +0,0 @@ -std::tuple_element<0, std::pair, pugi::xml_node, std::less >, std::allocator, pugi::xml_node> > > > >::type dnode - -std::_Rb_tree_iterator, pugi::xml_node, std::less >, std::allocator, pugi::xml_node> > > > > > dnode_it = dnodes_.find(uid.position) diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test-92369_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test-92369_cpp.json deleted file mode 100644 index 6a3254db6f6..00000000000 --- a/extensions/vscode-colorize-tests/test/colorize-results/test-92369_cpp.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "c": "std::tuple_element<0, std::pair, pugi::xml_node, std::less >, std::allocator, pugi::xml_node> > > > >::type dnode", - "t": "source.cpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "std::_Rb_tree_iterator, pugi::xml_node, std::less >, std::allocator, pugi::xml_node> > > > > > dnode_it = dnodes_.find(uid.position)", - "t": "source.cpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - } -] \ No newline at end of file diff --git a/package.json b/package.json index 3eb522416e2..ed43148b1a5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.56.0", - "distro": "0f81994093bec05b2cf192fc9fdb76ce5f114fcf", + "distro": "307045ac2e7717469648489b42182dfca29bdb30", "author": { "name": "Microsoft Corporation" }, @@ -79,7 +79,7 @@ "tas-client-umd": "0.1.4", "v8-inspect-profiler": "^0.0.20", "vscode-oniguruma": "1.3.1", - "vscode-proxy-agent": "^0.9.0", + "vscode-proxy-agent": "^0.8.2", "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.11.1", "vscode-sqlite3": "4.0.10", diff --git a/product.json b/product.json index 54c42bcb79f..c3947cdbe79 100644 --- a/product.json +++ b/product.json @@ -93,7 +93,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.55.1", + "version": "1.55.2", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", diff --git a/remote/package.json b/remote/package.json index aa061f1d847..c7a5e6b44f5 100644 --- a/remote/package.json +++ b/remote/package.json @@ -18,7 +18,7 @@ "spdlog": "^0.11.1", "tas-client-umd": "0.1.4", "vscode-oniguruma": "1.3.1", - "vscode-proxy-agent": "^0.9.0", + "vscode-proxy-agent": "^0.8.2", "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.11.1", "vscode-textmate": "5.2.0", diff --git a/remote/yarn.lock b/remote/yarn.lock index 3abe7dfea03..66f199e0404 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@tootallnate/once@1", "@tootallnate/once@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - agent-base@4: version "4.2.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" @@ -19,13 +14,6 @@ agent-base@5: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== -agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" @@ -33,6 +21,13 @@ agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" +agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + anymatch@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" @@ -94,16 +89,6 @@ cookie@^0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -data-uri-to-buffer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== - debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -118,13 +103,6 @@ debug@4: dependencies: ms "^2.1.1" -debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - diagnostic-channel-publishers@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" @@ -161,11 +139,6 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -file-uri-to-path@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" - integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -173,40 +146,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fsevents@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f" integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== -ftp@^0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - -get-uri@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" - integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== - dependencies: - "@tootallnate/once" "1" - data-uri-to-buffer "3" - debug "4" - file-uri-to-path "2" - fs-extra "^8.1.0" - ftp "^0.3.10" - glob-parent@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" @@ -219,11 +163,6 @@ graceful-fs@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.1.6, graceful-fs@^4.2.0: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - http-proxy-agent@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" @@ -232,15 +171,6 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - https-proxy-agent@^2.2.3: version "2.2.4" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" @@ -257,24 +187,11 @@ https-proxy-agent@^4.0.0: agent-base "5" debug "4" -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - iconv-lite-umd@0.6.8: version "0.6.8" resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.8.tgz#5ad310ec126b260621471a2d586f7f37b9958ec0" integrity sha512-zvXJ5gSwMC9JD3wDzH8CoZGc1pbiJn12Tqjk8BXYCnYz3hYL5GRjHW8LEykjXhV9WgNGI4rgpgHcbIiBfrRq6A== -inherits@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -304,23 +221,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - jschardet@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75" integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g== -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -338,7 +243,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.2, ms@^2.1.1: +ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -407,16 +312,6 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readdirp@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -429,27 +324,26 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== +socks-proxy-agent@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" + agent-base "~4.2.1" + socks "~2.3.2" -socks@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2" - integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw== +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== dependencies: ip "^1.1.5" - smart-buffer "^4.1.0" + smart-buffer "4.0.2" spdlog@^0.11.1: version "0.11.1" @@ -460,11 +354,6 @@ spdlog@^0.11.1: mkdirp "^0.5.1" nan "^2.14.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - tas-client-umd@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.4.tgz#49db4130dd63a8342fabf77185a740fc6a7bea80" @@ -477,28 +366,20 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - vscode-oniguruma@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f" integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ== -vscode-proxy-agent@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.9.0.tgz#da6501b0bb9a6c8cc2fe0e31756c91eb4d5d900b" - integrity sha512-DvLLaYNy8MBlm7O2CBUpmSpQCnNH88f95yXT1l9ovKO7GmTKkbbEJ6ZtzatUezqOlUuOFI0CwenhGGPYAlJ37A== +vscode-proxy-agent@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.8.2.tgz#5125e7f1efedd84e0114abe9f38cef3f7b33eb50" + integrity sha512-pRNhgAqrgMB4k1rZTHthCLVH+CtJ3TFlKKhFlt4IMxDRZnMEAbPiAGthvEt/Ku6qS4Vuca8b2PqT+rJlbmnznQ== dependencies: - "@tootallnate/once" "^1.1.2" - agent-base "^6.0.2" - debug "^4.3.1" - get-uri "^3.0.2" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - socks-proxy-agent "^5.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + socks-proxy-agent "^4.0.1" vscode-regexpp@^3.1.0: version "3.1.0" @@ -537,11 +418,6 @@ windows-process-tree@0.2.4: dependencies: nan "^2.13.2" -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= - xterm-addon-search@0.9.0-beta.1: version "0.9.0-beta.1" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.1.tgz#139515da723a129c6d27c4e1a2319ef1344d76a6" diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index a08e7b668ff..eb10108abb0 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -34,11 +34,9 @@ * @param {string[]} modulePaths * @param {(result: unknown, configuration: import('./vs/base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => Promise | undefined} resultCallback * @param {{ - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean, + * configureDeveloperKeybindings?: (config: import('./vs/base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, * canModifyDOM?: (config: import('./vs/base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => void, - * beforeLoaderConfig?: (config: import('./vs/base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration, loaderConfig: object) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, * beforeRequire?: () => void * }} [options] */ @@ -55,11 +53,12 @@ const configuration = await preloadGlobals.context.configuration; performance.mark('code/didWaitForWindowConfig'); - // Developer tools - const enableDeveloperKeybindings = safeProcess.env['VSCODE_DEV'] || configuration.forceEnableDeveloperKeybindings || options?.forceEnableDeveloperKeybindings; + // Developer keybindings + const { forceEnableDeveloperKeybindings, disallowReloadKeybinding, removeDeveloperKeybindingsAfterLoad } = typeof options?.configureDeveloperKeybindings === 'function' ? options.configureDeveloperKeybindings(configuration) : { forceEnableDeveloperKeybindings: false, disallowReloadKeybinding: false, removeDeveloperKeybindingsAfterLoad: false }; + const enableDeveloperKeybindings = safeProcess.env['VSCODE_DEV'] || forceEnableDeveloperKeybindings; let developerDeveloperKeybindingsDisposable; if (enableDeveloperKeybindings) { - developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(options?.disallowReloadKeybinding); + developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding); } // Enable ASAR support @@ -143,7 +142,7 @@ // Signal before require.config() if (typeof options?.beforeLoaderConfig === 'function') { - options.beforeLoaderConfig(configuration, loaderConfig); + options.beforeLoaderConfig(loaderConfig); } // Configure loader @@ -177,7 +176,7 @@ if (callbackResult instanceof Promise) { await callbackResult; - if (developerDeveloperKeybindingsDisposable && options?.removeDeveloperKeybindingsAfterLoad) { + if (developerDeveloperKeybindingsDisposable && removeDeveloperKeybindingsAfterLoad) { developerDeveloperKeybindingsDisposable(); } } @@ -267,7 +266,6 @@ } return { - load, - globals + load }; })); diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 0ebc24f9ff7..ee8fd156e23 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -680,12 +680,12 @@ export class ListView implements ISpliceable, IDisposable { if (this.supportDynamicHeights) { this._rerender(this.scrollTop, this.renderHeight); } + } - if (this.horizontalScrolling) { - this.scrollableElement.setScrollDimensions({ - width: typeof width === 'number' ? width : getContentWidth(this.domNode) - }); - } + if (this.horizontalScrolling) { + this.scrollableElement.setScrollDimensions({ + width: typeof width === 'number' ? width : getContentWidth(this.domNode) + }); } } diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts new file mode 100644 index 00000000000..a0e4d4458c0 --- /dev/null +++ b/src/vs/base/common/product.ts @@ -0,0 +1,161 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IStringDictionary } from 'vs/base/common/collections'; + +export interface IBuiltInExtension { + readonly name: string; + readonly version: string; + readonly repo: string; + readonly metadata: any; +} + +export type ConfigurationSyncStore = { + url: string, + insidersUrl: string, + stableUrl: string, + canSwitch: boolean, + authenticationProviders: IStringDictionary<{ scopes: string[] }> +}; + +export interface IProductConfiguration { + readonly version: string; + readonly date?: string; + readonly quality?: string; + readonly commit?: string; + + readonly nameShort: string; + readonly nameLong: string; + + readonly win32AppUserModelId?: string; + readonly win32MutexName?: string; + readonly applicationName: string; + + readonly urlProtocol: string; + readonly dataFolderName: string; // location for extensions (e.g. ~/.vscode-insiders) + + readonly builtInExtensions?: IBuiltInExtension[]; + + readonly downloadUrl?: string; + readonly updateUrl?: string; + readonly webEndpointUrl?: string; + readonly target?: string; + + readonly settingsSearchBuildId?: number; + readonly settingsSearchUrl?: string; + + readonly tasConfig?: { + endpoint: string; + telemetryEventName: string; + featuresTelemetryPropertyName: string; + assignmentContextTelemetryPropertyName: string; + }; + + readonly experimentsUrl?: string; + + readonly extensionsGallery?: { + readonly serviceUrl: string; + readonly itemUrl: string; + readonly controlUrl: string; + readonly recommendationsUrl: string; + }; + + readonly extensionTips?: { [id: string]: string; }; + readonly extensionImportantTips?: IStringDictionary; + readonly configBasedExtensionTips?: { [id: string]: IConfigBasedExtensionTip; }; + readonly exeBasedExtensionTips?: { [id: string]: IExeBasedExtensionTip; }; + readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; }; + readonly extensionKeywords?: { [extension: string]: readonly string[]; }; + readonly keymapExtensionTips?: readonly string[]; + readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; }; + + readonly crashReporter?: { + readonly companyName: string; + readonly productName: string; + }; + + readonly enableTelemetry?: boolean; + readonly aiConfig?: { + readonly asimovKey: string; + }; + + readonly sendASmile?: { + readonly reportIssueUrl: string, + readonly requestFeatureUrl: string + }; + + readonly documentationUrl?: string; + readonly releaseNotesUrl?: string; + readonly keyboardShortcutsUrlMac?: string; + readonly keyboardShortcutsUrlLinux?: string; + readonly keyboardShortcutsUrlWin?: string; + readonly introductoryVideosUrl?: string; + readonly tipsAndTricksUrl?: string; + readonly newsletterSignupUrl?: string; + readonly twitterUrl?: string; + readonly requestFeatureUrl?: string; + readonly reportIssueUrl?: string; + readonly reportMarketplaceIssueUrl?: string; + readonly licenseUrl?: string; + readonly privacyStatementUrl?: string; + readonly telemetryOptOutUrl?: string; + + readonly npsSurveyUrl?: string; + readonly cesSurveyUrl?: string; + readonly surveys?: readonly ISurveyData[]; + + readonly checksums?: { [path: string]: string; }; + readonly checksumFailMoreInfoUrl?: string; + + readonly appCenter?: IAppCenterConfiguration; + + readonly portable?: string; + + readonly extensionKind?: { readonly [extensionId: string]: ('ui' | 'workspace' | 'web')[]; }; + readonly extensionSyncedKeys?: { readonly [extensionId: string]: string[]; }; + readonly extensionAllowedProposedApi?: readonly string[]; + + readonly msftInternalDomains?: string[]; + readonly linkProtectionTrustedDomains?: readonly string[]; + + readonly 'configurationSync.store'?: ConfigurationSyncStore; + + readonly darwinUniversalAssetId?: string; +} + +export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean }; + +export interface IAppCenterConfiguration { + readonly 'win32-ia32': string; + readonly 'win32-x64': string; + readonly 'linux-x64': string; + readonly 'darwin': string; +} + +export interface IConfigBasedExtensionTip { + configPath: string; + configName: string; + recommendations: IStringDictionary<{ name: string, remotes?: string[], important?: boolean, isExtensionPack?: boolean }>; +} + +export interface IExeBasedExtensionTip { + friendlyName: string; + windowsPath?: string; + important?: boolean; + recommendations: IStringDictionary<{ name: string, important?: boolean, isExtensionPack?: boolean }>; +} + +export interface IRemoteExtensionTip { + friendlyName: string; + extensionId: string; +} + +export interface ISurveyData { + surveyId: string; + surveyUrl: string; + languageId: string; + editCount: number; + userProbability: number; +} diff --git a/src/vs/base/parts/sandbox/common/sandboxTypes.ts b/src/vs/base/parts/sandbox/common/sandboxTypes.ts index bc6a7144410..d8c3b69abbf 100644 --- a/src/vs/base/parts/sandbox/common/sandboxTypes.ts +++ b/src/vs/base/parts/sandbox/common/sandboxTypes.ts @@ -24,6 +24,4 @@ export interface ISandboxConfiguration { zoomLevel?: number; nodeCachedDataDir?: string; - - forceEnableDeveloperKeybindings?: boolean; } diff --git a/src/vs/base/parts/sandbox/electron-browser/preload.js b/src/vs/base/parts/sandbox/electron-browser/preload.js index 02545028a8b..c1470e033cd 100644 --- a/src/vs/base/parts/sandbox/electron-browser/preload.js +++ b/src/vs/base/parts/sandbox/electron-browser/preload.js @@ -238,6 +238,7 @@ try { if (validateIPC(windowConfigIpcChannel)) { + /** @type {import('../common/sandboxTypes').ISandboxConfiguration} */ const configuration = await ipcRenderer.invoke(windowConfigIpcChannel); // Apply zoom level early before even building the diff --git a/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts b/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts index ceffcb0c50d..b7bcaa259da 100644 --- a/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts +++ b/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts @@ -7,11 +7,13 @@ import * as assert from 'assert'; import { ipcRenderer, crashReporter, webFrame, context, process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; suite('Sandbox', () => { - test('globals', () => { + test('globals', async () => { assert.ok(typeof ipcRenderer.send === 'function'); assert.ok(typeof crashReporter.addExtraParameter === 'function'); assert.ok(typeof webFrame.setZoomLevel === 'function'); - assert.ok(context.configuration instanceof Promise); assert.ok(typeof process.platform === 'string'); + + const config = await context.configuration; + assert.ok(config); }); }); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index 3820fc37606..6d4a80f840c 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -28,7 +28,16 @@ /** * @returns {{ - * load: (modules: string[], resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown) => Promise + * load: ( + * modules: string[], + * resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown, + * options?: { + * configureDeveloperKeybindings?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, + * canModifyDOM?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise * }} */ function bootstrapWindowLib() { diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 003f8d91e23..c05058da2fe 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -32,11 +32,16 @@ return require('vs/workbench/electron-browser/desktop.main').main(configuration); }, { - removeDeveloperKeybindingsAfterLoad: true, + configureDeveloperKeybindings: function (windowConfig) { + return { + forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath), + removeDeveloperKeybindingsAfterLoad: true + }; + }, canModifyDOM: function (windowConfig) { showPartsSplash(windowConfig); }, - beforeLoaderConfig: function (windowConfig, loaderConfig) { + beforeLoaderConfig: function (loaderConfig) { loaderConfig.recordStats = true; }, beforeRequire: function () { @@ -66,7 +71,16 @@ /** * @returns {{ - * load: (modules: string[], resultCallback: (result, configuration: import('../../../platform/windows/common/windows').INativeWindowConfiguration) => unknown, options: object) => Promise + * load: ( + * modules: string[], + * resultCallback: (result, configuration: import('../../../platform/windows/common/windows').INativeWindowConfiguration) => unknown, + * options?: { + * configureDeveloperKeybindings?: (config: import('../../../platform/windows/common/windows').INativeWindowConfiguration & object) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, + * canModifyDOM?: (config: import('../../../platform/windows/common/windows').INativeWindowConfiguration & object) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise * }} */ function bootstrapWindowLib() { diff --git a/src/vs/code/electron-sandbox/issue/issueReporter.js b/src/vs/code/electron-sandbox/issue/issueReporter.js index 784ca9acc17..0c2c935ad28 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporter.js +++ b/src/vs/code/electron-sandbox/issue/issueReporter.js @@ -11,12 +11,30 @@ // Load issue reporter into window bootstrapWindow.load(['vs/code/electron-sandbox/issue/issueReporterMain'], function (issueReporter, configuration) { - issueReporter.startup(configuration); - }, { forceEnableDeveloperKeybindings: true, disallowReloadKeybinding: true }); + return issueReporter.startup(configuration); + }, + { + configureDeveloperKeybindings: function () { + return { + forceEnableDeveloperKeybindings: true, + disallowReloadKeybinding: true + }; + } + } + ); /** * @returns {{ - * load: (modules: string[], resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown, options?: { forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean }) => Promise + * load: ( + * modules: string[], + * resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown, + * options?: { + * configureDeveloperKeybindings?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, + * canModifyDOM?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise * }} */ function bootstrapWindowLib() { diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js index fad8641ce69..ab99c5e40d0 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js @@ -11,12 +11,27 @@ // Load process explorer into window bootstrapWindow.load(['vs/code/electron-sandbox/processExplorer/processExplorerMain'], function (processExplorer, configuration) { - processExplorer.startup(configuration); - }, { forceEnableDeveloperKeybindings: true }); + return processExplorer.startup(configuration); + }, { + configureDeveloperKeybindings: function () { + return { + forceEnableDeveloperKeybindings: true + }; + }, + }); /** * @returns {{ - * load: (modules: string[], resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown, options?: { forceEnableDeveloperKeybindings?: boolean }) => Promise + * load: ( + * modules: string[], + * resultCallback: (result, configuration: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => unknown, + * options?: { + * configureDeveloperKeybindings?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, + * canModifyDOM?: (config: import('../../../base/parts/sandbox/common/sandboxTypes').ISandboxConfiguration) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise * }} */ function bootstrapWindowLib() { diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index 52b100f2b42..50efcc62571 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -32,11 +32,16 @@ return require('vs/workbench/electron-sandbox/desktop.main').main(configuration); }, { - removeDeveloperKeybindingsAfterLoad: true, + configureDeveloperKeybindings: function (windowConfig) { + return { + forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath), + removeDeveloperKeybindingsAfterLoad: true + }; + }, canModifyDOM: function (windowConfig) { // TODO@sandbox part-splash is non-sandboxed only }, - beforeLoaderConfig: function (windowConfig, loaderConfig) { + beforeLoaderConfig: function (loaderConfig) { loaderConfig.recordStats = true; }, beforeRequire: function () { @@ -66,7 +71,16 @@ /** * @returns {{ - * load: (modules: string[], resultCallback: (result, configuration: import('../../../platform/windows/common/windows').INativeWindowConfiguration) => unknown, options: object) => Promise + * load: ( + * modules: string[], + * resultCallback: (result, configuration: import('../../../platform/windows/common/windows').INativeWindowConfiguration) => unknown, + * options?: { + * configureDeveloperKeybindings?: (config: import('../../../platform/windows/common/windows').INativeWindowConfiguration & object) => {forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean}, + * canModifyDOM?: (config: import('../../../platform/windows/common/windows').INativeWindowConfiguration & object) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise * }} */ function bootstrapWindowLib() { diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 9814d83c222..6e01f85c7c5 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -2106,10 +2106,42 @@ export class TextModel extends Disposable implements model.ITextModel { return this._matchBracket(this.validatePosition(position)); } + private _establishBracketSearchOffsets(position: Position, lineTokens: LineTokens, modeBrackets: RichEditBrackets, tokenIndex: number) { + const tokenCount = lineTokens.getCount(); + const currentLanguageId = lineTokens.getLanguageId(tokenIndex); + + // limit search to not go before `maxBracketLength` + let searchStartOffset = Math.max(0, position.column - 1 - modeBrackets.maxBracketLength); + for (let i = tokenIndex - 1; i >= 0; i--) { + const tokenEndOffset = lineTokens.getEndOffset(i); + if (tokenEndOffset <= searchStartOffset) { + break; + } + if (ignoreBracketsInToken(lineTokens.getStandardTokenType(i)) || lineTokens.getLanguageId(i) !== currentLanguageId) { + searchStartOffset = tokenEndOffset; + break; + } + } + + // limit search to not go after `maxBracketLength` + let searchEndOffset = Math.min(lineTokens.getLineContent().length, position.column - 1 + modeBrackets.maxBracketLength); + for (let i = tokenIndex + 1; i < tokenCount; i++) { + const tokenStartOffset = lineTokens.getStartOffset(i); + if (tokenStartOffset >= searchEndOffset) { + break; + } + if (ignoreBracketsInToken(lineTokens.getStandardTokenType(i)) || lineTokens.getLanguageId(i) !== currentLanguageId) { + searchEndOffset = tokenStartOffset; + break; + } + } + + return { searchStartOffset, searchEndOffset }; + } + private _matchBracket(position: Position): [Range, Range] | null { const lineNumber = position.lineNumber; const lineTokens = this._getLineTokens(lineNumber); - const tokenCount = lineTokens.getCount(); const lineText = this._buffer.getLineContent(lineNumber); const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); @@ -2120,19 +2152,8 @@ export class TextModel extends Disposable implements model.ITextModel { // check that the token is not to be ignored if (currentModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))) { - // limit search to not go before `maxBracketLength` - let searchStartOffset = Math.max(0, position.column - 1 - currentModeBrackets.maxBracketLength); - for (let i = tokenIndex - 1; i >= 0; i--) { - const tokenEndOffset = lineTokens.getEndOffset(i); - if (tokenEndOffset <= searchStartOffset) { - break; - } - if (ignoreBracketsInToken(lineTokens.getStandardTokenType(i))) { - searchStartOffset = tokenEndOffset; - } - } - // limit search to not go after `maxBracketLength` - const searchEndOffset = Math.min(lineText.length, position.column - 1 + currentModeBrackets.maxBracketLength); + + let { searchStartOffset, searchEndOffset } = this._establishBracketSearchOffsets(position, lineTokens, currentModeBrackets, tokenIndex); // it might be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets // `bestResult` will contain the most right-side result @@ -2171,18 +2192,9 @@ export class TextModel extends Disposable implements model.ITextModel { // check that previous token is not to be ignored if (prevModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(prevTokenIndex))) { - // limit search in case previous token is very large, there's no need to go beyond `maxBracketLength` - const searchStartOffset = Math.max(0, position.column - 1 - prevModeBrackets.maxBracketLength); - let searchEndOffset = Math.min(lineText.length, position.column - 1 + prevModeBrackets.maxBracketLength); - for (let i = prevTokenIndex + 1; i < tokenCount; i++) { - const tokenStartOffset = lineTokens.getStartOffset(i); - if (tokenStartOffset >= searchEndOffset) { - break; - } - if (ignoreBracketsInToken(lineTokens.getStandardTokenType(i))) { - searchEndOffset = tokenStartOffset; - } - } + + let { searchStartOffset, searchEndOffset } = this._establishBracketSearchOffsets(position, lineTokens, prevModeBrackets, prevTokenIndex); + const foundBracket = BracketsUtils.findPrevBracketInRange(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); // check that we didn't hit a bracket too far away from position diff --git a/src/vs/editor/common/modes/supports/tokenization.ts b/src/vs/editor/common/modes/supports/tokenization.ts index e28c23d39b4..a8ffd6bae1f 100644 --- a/src/vs/editor/common/modes/supports/tokenization.ts +++ b/src/vs/editor/common/modes/supports/tokenization.ts @@ -313,11 +313,21 @@ export class ThemeTrieElementRule { export class ExternalThemeTrieElement { public readonly mainRule: ThemeTrieElementRule; - public readonly children: { [segment: string]: ExternalThemeTrieElement }; + public readonly children: Map; - constructor(mainRule: ThemeTrieElementRule, children?: { [segment: string]: ExternalThemeTrieElement }) { + constructor( + mainRule: ThemeTrieElementRule, + children: Map | { [key: string]: ExternalThemeTrieElement } = new Map() + ) { this.mainRule = mainRule; - this.children = children || Object.create(null); + if (children instanceof Map) { + this.children = children; + } else { + this.children = new Map(); + for (const key in children) { + this.children.set(key, children[key]); + } + } } } @@ -336,9 +346,9 @@ export class ThemeTrieElement { * used for testing purposes */ public toExternalThemeTrieElement(): ExternalThemeTrieElement { - let children: { [segment: string]: ExternalThemeTrieElement } = Object.create(null); + const children = new Map(); this._children.forEach((element, index) => { - children[index] = element.toExternalThemeTrieElement(); + children.set(index, element.toExternalThemeTrieElement()); }); return new ExternalThemeTrieElement(this._mainRule, children); } diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index e52fbf61a89..8c383913895 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -22,7 +21,7 @@ export interface ILanguageExtensionPoint { configuration?: URI; } -export interface ILanguageSelection extends IDisposable { +export interface ILanguageSelection { readonly languageIdentifier: LanguageIdentifier; readonly onDidChange: Event; } diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index f5a6eba1dad..9eee6901216 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; import { FrankensteinMode } from 'vs/editor/common/modes/abstractMode'; @@ -13,20 +13,28 @@ import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry'; import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService'; import { firstOrDefault } from 'vs/base/common/arrays'; -class LanguageSelection extends Disposable implements ILanguageSelection { +class LanguageSelection implements ILanguageSelection { public languageIdentifier: LanguageIdentifier; private readonly _selector: () => LanguageIdentifier; - - private readonly _onDidChange: Emitter = this._register(new Emitter()); - public readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange: Emitter; + public readonly onDidChange: Event; constructor(onLanguagesMaybeChanged: Event, selector: () => LanguageIdentifier) { - super(); this._selector = selector; this.languageIdentifier = this._selector(); - this._register(onLanguagesMaybeChanged(() => this._evaluate())); + + let listener: IDisposable; + this._onDidChange = new Emitter({ + onFirstListenerAdd: () => { + listener = onLanguagesMaybeChanged(() => this._evaluate()); + }, + onLastListenerRemove: () => { + listener.dispose(); + } + }); + this.onDidChange = this._onDidChange.event; } private _evaluate(): void { diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index c7bcc283b1b..af7000ffd9c 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -78,10 +78,6 @@ class ModelData implements IDisposable { this._languageSelectionListener.dispose(); this._languageSelectionListener = null; } - if (this._languageSelection) { - this._languageSelection.dispose(); - this._languageSelection = null; - } } public dispose(): void { diff --git a/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts index 703a760c7ad..f6cfeff1648 100644 --- a/src/vs/editor/test/common/mocks/mockMode.ts +++ b/src/vs/editor/test/common/mocks/mockMode.ts @@ -28,5 +28,4 @@ export class MockMode extends Disposable implements IMode { export class StaticLanguageSelector implements ILanguageSelection { readonly onDidChange: Event = Event.None; constructor(public readonly languageIdentifier: LanguageIdentifier) { } - public dispose(): void { } } diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index e4560fd8233..efbed2ef4c1 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; @@ -337,6 +337,97 @@ suite('TextModelWithTokens', () => { registration.dispose(); }); + test('issue #95843: Highlighting of closing braces is indicating wrong brace when cursor is behind opening brace', () => { + const mode1 = new LanguageIdentifier('testMode1', 3); + const mode2 = new LanguageIdentifier('testMode2', 4); + const otherMetadata1 = ( + (mode1.id << MetadataConsts.LANGUAGEID_OFFSET) + | (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET) + ) >>> 0; + const otherMetadata2 = ( + (mode2.id << MetadataConsts.LANGUAGEID_OFFSET) + | (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET) + ) >>> 0; + + const tokenizationSupport: ITokenizationSupport = { + getInitialState: () => NULL_STATE, + tokenize: undefined!, + tokenize2: (line, hasEOL, state) => { + switch (line) { + case 'function f() {': { + const tokens = new Uint32Array([ + 0, otherMetadata1, + 8, otherMetadata1, + 9, otherMetadata1, + 10, otherMetadata1, + 11, otherMetadata1, + 12, otherMetadata1, + 13, otherMetadata1, + ]); + return new TokenizationResult2(tokens, state); + } + case ' return

{true}

;': { + const tokens = new Uint32Array([ + 0, otherMetadata1, + 2, otherMetadata1, + 8, otherMetadata1, + 9, otherMetadata2, + 10, otherMetadata2, + 11, otherMetadata2, + 12, otherMetadata2, + 13, otherMetadata1, + 17, otherMetadata2, + 18, otherMetadata2, + 20, otherMetadata2, + 21, otherMetadata2, + 22, otherMetadata2, + ]); + return new TokenizationResult2(tokens, state); + } + case '}': { + const tokens = new Uint32Array([ + 0, otherMetadata1 + ]); + return new TokenizationResult2(tokens, state); + } + } + throw new Error(`Unexpected`); + } + }; + + const disposableStore = new DisposableStore(); + + disposableStore.add(TokenizationRegistry.register(mode1.language, tokenizationSupport)); + disposableStore.add(LanguageConfigurationRegistry.register(mode1, { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + })); + disposableStore.add(LanguageConfigurationRegistry.register(mode2, { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + })); + + const model = disposableStore.add(createTextModel([ + 'function f() {', + ' return

{true}

;', + '}', + ].join('\n'), undefined, mode1)); + + model.forceTokenization(1); + model.forceTokenization(2); + model.forceTokenization(3); + + assert.deepStrictEqual(model.matchBracket(new Position(2, 14)), [new Range(2, 13, 2, 14), new Range(2, 18, 2, 19)]); + + disposableStore.dispose(); + }); + test('issue #88075: TypeScript brace matching is incorrect in `${}` strings', () => { const mode = new LanguageIdentifier('testMode', 3); const otherMetadata = ( diff --git a/src/vs/editor/test/common/modes/supports/tokenization.test.ts b/src/vs/editor/test/common/modes/supports/tokenization.test.ts index a8f90408560..435ba7787a6 100644 --- a/src/vs/editor/test/common/modes/supports/tokenization.test.ts +++ b/src/vs/editor/test/common/modes/supports/tokenization.test.ts @@ -243,60 +243,60 @@ suite('Token theme resolving', () => { }); test('defaults are inherited', () => { - let actual = TokenTheme.createFromParsedTokenTheme([ + const actual = TokenTheme.createFromParsedTokenTheme([ new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'), new ParsedTokenThemeRule('var', -1, FontStyle.NotSet, 'ff0000', null) ], []); - let colorMap = new ColorMap(); + const colorMap = new ColorMap(); const _A = colorMap.getId('F8F8F2'); const _B = colorMap.getId('272822'); const _C = colorMap.getId('ff0000'); assert.deepStrictEqual(actual.getColorMap(), colorMap.getColorMap()); - let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { + const root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { 'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _C, _B)) }); - assert.deepEqual(actual.getThemeTrieElement(), root); + assert.deepStrictEqual(actual.getThemeTrieElement(), root); }); test('same rules get merged', () => { - let actual = TokenTheme.createFromParsedTokenTheme([ + const actual = TokenTheme.createFromParsedTokenTheme([ new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'), new ParsedTokenThemeRule('var', 1, FontStyle.Bold, null, null), new ParsedTokenThemeRule('var', 0, FontStyle.NotSet, 'ff0000', null), ], []); - let colorMap = new ColorMap(); + const colorMap = new ColorMap(); const _A = colorMap.getId('F8F8F2'); const _B = colorMap.getId('272822'); const _C = colorMap.getId('ff0000'); assert.deepStrictEqual(actual.getColorMap(), colorMap.getColorMap()); - let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { + const root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { 'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _C, _B)) }); - assert.deepEqual(actual.getThemeTrieElement(), root); + assert.deepStrictEqual(actual.getThemeTrieElement(), root); }); test('rules are inherited 1', () => { - let actual = TokenTheme.createFromParsedTokenTheme([ + const actual = TokenTheme.createFromParsedTokenTheme([ new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'), new ParsedTokenThemeRule('var', -1, FontStyle.Bold, 'ff0000', null), new ParsedTokenThemeRule('var.identifier', -1, FontStyle.NotSet, '00ff00', null), ], []); - let colorMap = new ColorMap(); + const colorMap = new ColorMap(); const _A = colorMap.getId('F8F8F2'); const _B = colorMap.getId('272822'); const _C = colorMap.getId('ff0000'); const _D = colorMap.getId('00ff00'); assert.deepStrictEqual(actual.getColorMap(), colorMap.getColorMap()); - let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { + const root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { 'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _C, _B), { 'identifier': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _D, _B)) }) }); - assert.deepEqual(actual.getThemeTrieElement(), root); + assert.deepStrictEqual(actual.getThemeTrieElement(), root); }); test('rules are inherited 2', () => { - let actual = TokenTheme.createFromParsedTokenTheme([ + const actual = TokenTheme.createFromParsedTokenTheme([ new ParsedTokenThemeRule('', -1, FontStyle.NotSet, 'F8F8F2', '272822'), new ParsedTokenThemeRule('var', -1, FontStyle.Bold, 'ff0000', null), new ParsedTokenThemeRule('var.identifier', -1, FontStyle.NotSet, '00ff00', null), @@ -306,7 +306,7 @@ suite('Token theme resolving', () => { new ParsedTokenThemeRule('constant.numeric.oct', 7, FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, null, null), new ParsedTokenThemeRule('constant.numeric.dec', 8, FontStyle.None, '300000', null), ], []); - let colorMap = new ColorMap(); + const colorMap = new ColorMap(); const _A = colorMap.getId('F8F8F2'); const _B = colorMap.getId('272822'); const _C = colorMap.getId('100000'); @@ -315,7 +315,7 @@ suite('Token theme resolving', () => { const _F = colorMap.getId('ff0000'); const _G = colorMap.getId('00ff00'); assert.deepStrictEqual(actual.getColorMap(), colorMap.getColorMap()); - let root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { + const root = new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.None, _A, _B), { 'var': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _F, _B), { 'identifier': new ExternalThemeTrieElement(new ThemeTrieElementRule(FontStyle.Bold, _G, _B)) }), @@ -327,7 +327,7 @@ suite('Token theme resolving', () => { }) }) }); - assert.deepEqual(actual.getThemeTrieElement(), root); + assert.deepStrictEqual(actual.getThemeTrieElement(), root); }); test('custom colors are first in color map', () => { diff --git a/src/vs/loader.js b/src/vs/loader.js index c3bdda280d1..815516d9cc5 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -763,6 +763,9 @@ var AMDLoader; require.resolve = function resolve(request, options) { return Module._resolveFilename(request, mod, false, options); }; + require.resolve.paths = function paths(request) { + return Module._resolveLookupPaths(request, mod); + }; require.main = process.mainModule; require.extensions = Module._extensions; require.cache = Module._cache; diff --git a/src/vs/platform/extensionManagement/common/extensionTipsService.ts b/src/vs/platform/extensionManagement/common/extensionTipsService.ts index 9f5712ef3e0..410604bd15d 100644 --- a/src/vs/platform/extensionManagement/common/extensionTipsService.ts +++ b/src/vs/platform/extensionManagement/common/extensionTipsService.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { IProductService, IConfigBasedExtensionTip as IRawConfigBasedExtensionTip } from 'vs/platform/product/common/productService'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IConfigBasedExtensionTip as IRawConfigBasedExtensionTip } from 'vs/base/common/product'; import { IFileService } from 'vs/platform/files/common/files'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IExtensionTipsService, IExecutableBasedExtensionTip, IWorkspaceTips, IConfigBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement'; diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index 926e62463e1..3e609e64275 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -189,18 +189,9 @@ export class IssueMainService implements ICommonIssueService { if (this.issueReporterParentWindow) { const issueReporterDisposables = new DisposableStore(); - interface IIssueReporterWindowConfig extends ISandboxConfiguration { - [key: string]: unknown; - } - - const issueReporterWindowConfigUrl = issueReporterDisposables.add(this.protocolMainService.createIPCObjectUrl()); - const position = this.getWindowPosition(this.issueReporterParentWindow, 700, 800); - - this.issueReporterWindow = this.createBrowserWindow(position, issueReporterWindowConfigUrl, data.styles.backgroundColor, localize('issueReporter', "Issue Reporter"), data.zoomLevel); - - const configuration: IIssueReporterWindowConfig = { + const configuration = { appRoot: this.environmentMainService.appRoot, - windowId: this.issueReporterWindow.id, + windowId: 0, // filled in later machineId: this.machineId, userEnv: this.userEnv, data, @@ -221,6 +212,14 @@ export class IssueMainService implements ICommonIssueService { } }; + interface IIssueReporterWindowConfig extends ISandboxConfiguration, Extract { } + + const issueReporterWindowConfigUrl = issueReporterDisposables.add(this.protocolMainService.createIPCObjectUrl()); + const position = this.getWindowPosition(this.issueReporterParentWindow, 700, 800); + + this.issueReporterWindow = this.createBrowserWindow(position, issueReporterWindowConfigUrl, data.styles.backgroundColor, localize('issueReporter', "Issue Reporter"), data.zoomLevel); + configuration.windowId = this.issueReporterWindow.id; + // Store into config object URL issueReporterWindowConfigUrl.update(configuration); @@ -254,22 +253,21 @@ export class IssueMainService implements ICommonIssueService { if (this.processExplorerParentWindow) { const processExplorerDisposables = new DisposableStore(); - interface IProcessExplorerWindowConfig extends ISandboxConfiguration { - [key: string]: unknown; - } + const configuration = { + appRoot: this.environmentMainService.appRoot, + windowId: 0, // filled in later + userEnv: this.userEnv, + machineId: this.machineId, + data + }; + + interface IProcessExplorerWindowConfig extends ISandboxConfiguration, Extract { } const processExplorerWindowConfigUrl = processExplorerDisposables.add(this.protocolMainService.createIPCObjectUrl()); const position = this.getWindowPosition(this.processExplorerParentWindow, 800, 500); this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, data.styles.backgroundColor, localize('issueReporter', "Issue Reporter"), data.zoomLevel); - - const configuration: IProcessExplorerWindowConfig = { - appRoot: this.environmentMainService.appRoot, - windowId: this.processExplorerWindow.id, - userEnv: this.userEnv, - machineId: this.machineId, - data - }; + configuration.windowId = this.processExplorerWindow.id; // Store into config object URL processExplorerWindowConfigUrl.update(configuration); diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 0dadbc22726..749eb2de3a0 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -7,7 +7,7 @@ import { FileAccess } from 'vs/base/common/network'; import { isWeb } from 'vs/base/common/platform'; import { env } from 'vs/base/common/process'; import { dirname, joinPath } from 'vs/base/common/resources'; -import { IProductConfiguration } from 'vs/platform/product/common/productService'; +import { IProductConfiguration } from 'vs/base/common/product'; let product: IProductConfiguration; diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index 34acc149728..857189f8f0f 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { ExtensionKind } from 'vs/platform/extensions/common/extensions'; -import { IStringDictionary } from 'vs/base/common/collections'; +import { IProductConfiguration } from 'vs/base/common/product'; export const IProductService = createDecorator('productService'); @@ -14,158 +13,3 @@ export interface IProductService extends Readonly { readonly _serviceBrand: undefined; } - -export interface IBuiltInExtension { - readonly name: string; - readonly version: string; - readonly repo: string; - readonly metadata: any; -} - -export type ConfigurationSyncStore = { - url: string, - insidersUrl: string, - stableUrl: string, - canSwitch: boolean, - authenticationProviders: IStringDictionary<{ scopes: string[] }> -}; - -export interface IProductConfiguration { - readonly version: string; - readonly date?: string; - readonly quality?: string; - readonly commit?: string; - - readonly nameShort: string; - readonly nameLong: string; - - readonly win32AppUserModelId?: string; - readonly win32MutexName?: string; - readonly applicationName: string; - - readonly urlProtocol: string; - readonly dataFolderName: string; // location for extensions (e.g. ~/.vscode-insiders) - - readonly builtInExtensions?: IBuiltInExtension[]; - - readonly downloadUrl?: string; - readonly updateUrl?: string; - readonly webEndpointUrl?: string; - readonly target?: string; - - readonly settingsSearchBuildId?: number; - readonly settingsSearchUrl?: string; - - readonly tasConfig?: { - endpoint: string; - telemetryEventName: string; - featuresTelemetryPropertyName: string; - assignmentContextTelemetryPropertyName: string; - }; - - readonly experimentsUrl?: string; - - readonly extensionsGallery?: { - readonly serviceUrl: string; - readonly itemUrl: string; - readonly controlUrl: string; - readonly recommendationsUrl: string; - }; - - readonly extensionTips?: { [id: string]: string; }; - readonly extensionImportantTips?: IStringDictionary; - readonly configBasedExtensionTips?: { [id: string]: IConfigBasedExtensionTip; }; - readonly exeBasedExtensionTips?: { [id: string]: IExeBasedExtensionTip; }; - readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; }; - readonly extensionKeywords?: { [extension: string]: readonly string[]; }; - readonly keymapExtensionTips?: readonly string[]; - readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; }; - - readonly crashReporter?: { - readonly companyName: string; - readonly productName: string; - }; - - readonly enableTelemetry?: boolean; - readonly aiConfig?: { - readonly asimovKey: string; - }; - - readonly sendASmile?: { - readonly reportIssueUrl: string, - readonly requestFeatureUrl: string - }; - - readonly documentationUrl?: string; - readonly releaseNotesUrl?: string; - readonly keyboardShortcutsUrlMac?: string; - readonly keyboardShortcutsUrlLinux?: string; - readonly keyboardShortcutsUrlWin?: string; - readonly introductoryVideosUrl?: string; - readonly tipsAndTricksUrl?: string; - readonly newsletterSignupUrl?: string; - readonly twitterUrl?: string; - readonly requestFeatureUrl?: string; - readonly reportIssueUrl?: string; - readonly reportMarketplaceIssueUrl?: string; - readonly licenseUrl?: string; - readonly privacyStatementUrl?: string; - readonly telemetryOptOutUrl?: string; - - readonly npsSurveyUrl?: string; - readonly cesSurveyUrl?: string; - readonly surveys?: readonly ISurveyData[]; - - readonly checksums?: { [path: string]: string; }; - readonly checksumFailMoreInfoUrl?: string; - - readonly appCenter?: IAppCenterConfiguration; - - readonly portable?: string; - - readonly extensionKind?: { readonly [extensionId: string]: ExtensionKind[]; }; - readonly extensionSyncedKeys?: { readonly [extensionId: string]: string[]; }; - readonly extensionAllowedProposedApi?: readonly string[]; - - readonly msftInternalDomains?: string[]; - readonly linkProtectionTrustedDomains?: readonly string[]; - - readonly 'configurationSync.store'?: ConfigurationSyncStore; - - readonly darwinUniversalAssetId?: string; -} - -export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean }; - -export interface IAppCenterConfiguration { - readonly 'win32-ia32': string; - readonly 'win32-x64': string; - readonly 'linux-x64': string; - readonly 'darwin': string; -} - -export interface IConfigBasedExtensionTip { - configPath: string; - configName: string; - recommendations: IStringDictionary<{ name: string, remotes?: string[], important?: boolean, isExtensionPack?: boolean }>; -} - -export interface IExeBasedExtensionTip { - friendlyName: string; - windowsPath?: string; - important?: boolean; - recommendations: IStringDictionary<{ name: string, important?: boolean, isExtensionPack?: boolean }>; -} - -export interface IRemoteExtensionTip { - friendlyName: string; - extensionId: string; -} - -export interface ISurveyData { - surveyId: string; - surveyUrl: string; - languageId: string; - editCount: number; - userProbability: number; -} diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 1ca0d129eba..dfcf6f78f41 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -181,7 +181,8 @@ export class SharedProcess extends Disposable implements ISharedProcess { } }); - const config: ISharedProcessConfiguration = { + // Store into config object URL + configObjectUrl.update({ machineId: this.machineId, windowId: this.window.id, appRoot: this.environmentMainService.appRoot, @@ -190,10 +191,7 @@ export class SharedProcess extends Disposable implements ISharedProcess { userEnv: this.userEnv, args: this.environmentMainService.args, logLevel: this.logService.getLevel() - }; - - // Store into config object URL - configObjectUrl.update(config); + }); // Load with config this.window.loadURL(FileAccess.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require).toString(true)); diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index fd0d139c778..eaa3a72697e 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -96,6 +96,7 @@ export interface IOffProcessTerminalService { listProcesses(reduceGraceTime?: boolean): Promise; setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise; getTerminalLayoutInfo(): Promise; + reduceConnectionGraceTime(): void; } export const ILocalTerminalService = createDecorator('localTerminalService'); @@ -111,8 +112,8 @@ export interface IPtyService { readonly onPtyHostStart?: Event; readonly onPtyHostUnresponsive?: Event; readonly onPtyHostResponsive?: Event; - readonly onProcessData: Event<{ id: number, event: IProcessDataEvent | string }>; + readonly onProcessBinary: Event<{ id: number, event: string }>; readonly onProcessExit: Event<{ id: number, event: number | undefined }>; readonly onProcessReady: Event<{ id: number, event: { pid: number, cwd: string } }>; readonly onProcessTitleChanged: Event<{ id: number, event: string }>; @@ -142,10 +143,8 @@ export interface IPtyService { /** * Lists all orphaned processes, ie. those without a connected frontend. - * @param reduceGraceTime Whether to reduce the reconnection grace time for all orphaned - * terminals. */ - listProcesses(reduceGraceTime: boolean): Promise; + listProcesses(): Promise; start(id: number): Promise; shutdown(id: number, immediate: boolean): Promise; @@ -155,11 +154,13 @@ export interface IPtyService { getCwd(id: number): Promise; getLatency(id: number): Promise; acknowledgeDataEvent(id: number, charCount: number): Promise; + processBinary(id: number, data: string): void; /** Confirm the process is _not_ an orphan. */ orphanQuestionReply(id: number): Promise; setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise; getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise; + reduceConnectionGraceTime(): void; } export enum HeartbeatConstants { @@ -346,6 +347,7 @@ export interface ITerminalChildProcess { */ shutdown(immediate: boolean): void; input(data: string): void; + processBinary(data: string): void; resize(cols: number, rows: number): void; /** diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index 6d56aad168d..05aa00e1ef9 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -49,9 +49,10 @@ export class PtyHostService extends Disposable implements IPtyService { readonly onPtyHostUnresponsive = this._onPtyHostUnresponsive.event; private readonly _onPtyHostResponsive = this._register(new Emitter()); readonly onPtyHostResponsive = this._onPtyHostResponsive.event; - private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; + private readonly _onProcessBinary = this._register(new Emitter<{ id: number, event: string }>()); + readonly onProcessBinary = this._onProcessBinary.event; private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter<{ id: number, event: { pid: number, cwd: string } }>()); @@ -123,6 +124,7 @@ export class PtyHostService extends Disposable implements IPtyService { // Create proxy and forward events const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); + this._register(proxy.onProcessBinary(e => this._onProcessBinary.fire(e))); this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); this._register(proxy.onProcessReady(e => this._onProcessReady.fire(e))); this._register(proxy.onProcessTitleChanged(e => this._onProcessTitleChanged.fire(e))); @@ -153,10 +155,12 @@ export class PtyHostService extends Disposable implements IPtyService { detachFromProcess(id: number): Promise { return this._proxy.detachFromProcess(id); } - listProcesses(reduceGraceTime: boolean): Promise { - return this._proxy.listProcesses(reduceGraceTime); + listProcesses(): Promise { + return this._proxy.listProcesses(); + } + reduceConnectionGraceTime(): void { + return this._proxy.reduceConnectionGraceTime(); } - start(id: number): Promise { return this._proxy.start(id); } @@ -188,6 +192,9 @@ export class PtyHostService extends Disposable implements IPtyService { setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { return this._proxy.setTerminalLayoutInfo(args); } + processBinary(id: number, data: string): void { + this._proxy.processBinary(id, data); + } async getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise { return await this._proxy.getTerminalLayoutInfo(args); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 12197344598..76e20bcfab2 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -27,6 +27,8 @@ export class PtyService extends Disposable implements IPtyService { private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; + private readonly _onProcessBinary = this._register(new Emitter<{ id: number, event: string }>()); + readonly onProcessBinary = this._onProcessBinary.event; private readonly _onProcessReplay = this._register(new Emitter<{ id: number, event: IPtyHostProcessReplayEvent }>()); readonly onProcessReplay = this._onProcessReplay.event; private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); @@ -114,13 +116,13 @@ export class PtyService extends Disposable implements IPtyService { this._throwIfNoPty(id).detach(); } - async listProcesses(reduceGraceTime: boolean): Promise { - if (reduceGraceTime) { - for (const pty of this._ptys.values()) { - pty.reduceGraceTime(); - } + reduceConnectionGraceTime(): void { + for (const pty of this._ptys.values()) { + pty.reduceGraceTime(); } + } + async listProcesses(): Promise { const persistentProcesses = Array.from(this._ptys.entries()).filter(([_, pty]) => pty.shouldPersistTerminal); this._logService.info(`Listing ${persistentProcesses.length} persistent terminals, ${this._ptys.size} total terminals`); @@ -157,6 +159,10 @@ export class PtyService extends Disposable implements IPtyService { return this._throwIfNoPty(id).orphanQuestionReply(); } + processBinary(id: number, data: string): void { + return this._throwIfNoPty(id).writeBinary(data); + } + async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { this._workspaceLayoutInfos.set(args.workspaceId, args); } @@ -337,6 +343,9 @@ export class PersistentTerminalProcess extends Disposable { } return this._terminalProcess.input(data); } + writeBinary(data: string): void { + return this._terminalProcess.processBinary(data); + } resize(cols: number, rows: number): void { if (this._inReplay) { return; diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index 0ddec65dfe5..3916597f65a 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -311,23 +311,27 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public input(data: string): void { + public input(data: string, isBinary?: boolean): void { if (this._isDisposed || !this._ptyProcess) { return; } for (let i = 0; i <= Math.floor(data.length / WRITE_MAX_CHUNK_SIZE); i++) { this._writeQueue.push(data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE)); } - this._startWrite(); + this._startWrite(isBinary); } - private _startWrite(): void { + public processBinary(data: string): void { + this.input(data, true); + } + + private _startWrite(isBinary?: boolean): void { // Don't write if it's already queued of is there is nothing to write if (this._writeTimeout !== undefined || this._writeQueue.length === 0) { return; } - this._doWrite(); + this._doWrite(isBinary); // Don't queue more writes if the queue is empty if (this._writeQueue.length === 0) { @@ -342,10 +346,16 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess }, WRITE_INTERVAL_MS); } - private _doWrite(): void { + private _doWrite(isBinary?: boolean): void { + console.info('writing binary', isBinary); const data = this._writeQueue.shift()!; - this._logService.trace('IPty#write', `${data.length} characters`); - this._ptyProcess!.write(data); + if (isBinary) { + this._logService.info('IPty#write (binary)', `${data.length} characters`); + this._ptyProcess!.write(Buffer.from(data, 'binary') as any); + } else { + this._logService.info('IPty#write', `${data.length} characters`); + this._ptyProcess!.write(data); + } } public resize(cols: number, rows: number): void { diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index c12dedbad75..803296e4d8c 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -10,7 +10,8 @@ import { joinPath, relativePath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IProductService, ConfigurationSyncStore } from 'vs/platform/product/common/productService'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ConfigurationSyncStore } from 'vs/base/common/product'; import { getServiceMachineId } from 'vs/platform/serviceMachineId/common/serviceMachineId'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts index e20033a2571..79631bb5721 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts @@ -7,7 +7,8 @@ import * as assert from 'assert'; import { IUserDataSyncStoreService, SyncResource, UserDataSyncErrorCode, UserDataSyncStoreError, IUserDataSyncStoreManagementService, IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IProductService, ConfigurationSyncStore } from 'vs/platform/product/common/productService'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ConfigurationSyncStore } from 'vs/base/common/product'; import { isWeb } from 'vs/base/common/platform'; import { RequestsSession, UserDataSyncStoreService, UserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { CancellationToken } from 'vs/base/common/cancellation'; diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 03da743777a..52338d338ba 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -871,9 +871,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { release: release() }; - // Force enable developer tools for extension development - configuration.forceEnableDeveloperKeybindings = Array.isArray(configuration.extensionDevelopmentPath); - // Store into config object URL this.configObjectUrl.update(configuration); } diff --git a/src/vs/platform/workspace/common/workspaceTrust.ts b/src/vs/platform/workspace/common/workspaceTrust.ts index c840873f5dd..36988361eb6 100644 --- a/src/vs/platform/workspace/common/workspaceTrust.ts +++ b/src/vs/platform/workspace/common/workspaceTrust.ts @@ -45,14 +45,14 @@ export interface IWorkspaceTrustModel { } export interface WorkspaceTrustRequestButton { - label: string; - type: 'ContinueWithTrust' | 'ContinueWithoutTrust' | 'Manage' | 'Cancel' + readonly label: string; + readonly type: 'ContinueWithTrust' | 'ContinueWithoutTrust' | 'Manage' | 'Cancel' } export interface WorkspaceTrustRequestOptions { - buttons?: WorkspaceTrustRequestButton[]; - message?: string; - modal: boolean; + readonly buttons?: WorkspaceTrustRequestButton[]; + readonly message?: string; + readonly modal: boolean; } export interface IWorkspaceTrustRequestModel { @@ -68,8 +68,8 @@ export interface IWorkspaceTrustRequestModel { } export interface WorkspaceTrustStateChangeEvent { - previousTrustState: WorkspaceTrustState; - currentTrustState: WorkspaceTrustState; + readonly previousTrustState: WorkspaceTrustState; + readonly currentTrustState: WorkspaceTrustState; } export type WorkspaceTrustChangeEvent = Event; @@ -84,7 +84,7 @@ export interface IWorkspaceTrustService { onDidChangeTrustState: WorkspaceTrustChangeEvent; getWorkspaceTrustState(): WorkspaceTrustState; isWorkspaceTrustEnabled(): boolean; - requireWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise; + requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise; } export interface IWorkspaceTrustUriInfo { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7b783774c5b..d48a954994b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2806,12 +2806,12 @@ declare module 'vscode' { /** * Previous trust state of the workspace */ - previousTrustState: WorkspaceTrustState; + readonly previousTrustState: WorkspaceTrustState; /** * Current trust state of the workspace */ - currentTrustState: WorkspaceTrustState; + readonly currentTrustState: WorkspaceTrustState; } /** @@ -2822,7 +2822,7 @@ declare module 'vscode' { * When true, a modal dialog will be used to request workspace trust. * When false, a badge will be displayed on the Setting activity bar item */ - modal: boolean; + readonly modal: boolean; } export namespace workspace { @@ -2836,7 +2836,7 @@ declare module 'vscode' { * @param options Optional object describing the properties of the * workspace trust request */ - export function requireWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Thenable; + export function requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Thenable; /** * Event that fires when the trust state of the current workspace changes diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index 3cc31f08607..c88061cf34d 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -422,7 +422,7 @@ export class MainThreadTask implements MainThreadTaskShape { if (execution.task?.execution && CustomExecutionDTO.is(execution.task.execution) && event.resolvedVariables) { const dictionary: IStringDictionary = {}; Array.from(event.resolvedVariables.entries()).forEach(entry => dictionary[entry[0]] = entry[1]); - resolvedDefinition = await this._configurationResolverService.resolveAny(task.getWorkspaceFolder(), + resolvedDefinition = await this._configurationResolverService.resolveAnyAsync(task.getWorkspaceFolder(), execution.task.definition, dictionary); } this._proxy.$onDidStartTask(execution, event.terminalId!, resolvedDefinition); diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index bba94ce14df..75b1d7b857a 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -100,9 +100,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape public dispose(): void { this._toDispose.dispose(); this._linkProvider?.dispose(); - - // TODO@Daniel: Should all the previously created terminals be disposed - // when the extension host process goes down ? } private _getTerminalId(id: TerminalIdentifier): number | undefined { @@ -157,17 +154,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $dispose(id: TerminalIdentifier): void { - const terminalInstance = this._getTerminalInstance(id); - if (terminalInstance) { - terminalInstance.dispose(); - } + this._getTerminalInstance(id)?.dispose(); } public $sendText(id: TerminalIdentifier, text: string, addNewLine: boolean): void { - const terminalInstance = this._getTerminalInstance(id); - if (terminalInstance) { - terminalInstance.sendText(text, addNewLine); - } + this._getTerminalInstance(id)?.sendText(text, addNewLine); } public $startSendingDataEvents(): void { @@ -183,10 +174,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $stopSendingDataEvents(): void { - if (this._dataEventTracker) { - this._dataEventTracker.dispose(); - this._dataEventTracker = undefined; - } + this._dataEventTracker?.dispose(); + this._dataEventTracker = undefined; } public $startLinkProvider(): void { @@ -276,60 +265,35 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $sendProcessTitle(terminalId: number, title: string): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitTitle(title); - } + this._terminalProcessProxies.get(terminalId)?.emitTitle(title); } public $sendProcessData(terminalId: number, data: string): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitData(data); - } + this._terminalProcessProxies.get(terminalId)?.emitData(data); } public $sendProcessReady(terminalId: number, pid: number, cwd: string): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitReady(pid, cwd); - } + this._terminalProcessProxies.get(terminalId)?.emitReady(pid, cwd); } public $sendProcessExit(terminalId: number, exitCode: number | undefined): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitExit(exitCode); - this._terminalProcessProxies.delete(terminalId); - } + this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode); } public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitOverrideDimensions(dimensions); - } + this._terminalProcessProxies.get(terminalId)?.emitOverrideDimensions(dimensions); } public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitInitialCwd(initialCwd); - } + this._terminalProcessProxies.get(terminalId)?.emitInitialCwd(initialCwd); } public $sendProcessCwd(terminalId: number, cwd: string): void { - const terminalProcess = this._terminalProcessProxies.get(terminalId); - if (terminalProcess) { - terminalProcess.emitCwd(cwd); - } + this._terminalProcessProxies.get(terminalId)?.emitCwd(cwd); } public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void { - const instance = this._terminalService.getInstanceFromId(terminalId); - if (instance) { - this._getTerminalProcess(terminalId)?.emitResolvedShellLaunchConfig(shellLaunchConfig); - } + this._getTerminalProcess(terminalId)?.emitResolvedShellLaunchConfig(shellLaunchConfig); } private async _onRequestLatency(terminalId: number): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index f7177ef7717..38dd25cadc7 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { onUnexpectedError } from 'vs/base/common/errors'; -import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; @@ -81,7 +81,6 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc private readonly _webviewInputs = new WebviewInputStore(); private readonly _editorProviders = new Map(); - private readonly _webviewFromDiffEditorHandles = new Set(); private readonly _revivers = new Map(); @@ -99,18 +98,17 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewPanels); this._register(_editorService.onDidActiveEditorChange(() => { - const activeInput = this._editorService.activeEditor; - if (activeInput instanceof DiffEditorInput && activeInput.primary instanceof WebviewInput && activeInput.secondary instanceof WebviewInput) { - this.registerWebviewFromDiffEditorListeners(activeInput); - } - - this.updateWebviewViewStates(activeInput); + this.updateWebviewViewStates(this._editorService.activeEditor); })); this._register(_editorService.onDidVisibleEditorsChange(() => { this.updateWebviewViewStates(this._editorService.activeEditor); })); + this._register(_webviewWorkbenchService.onDidChangeActiveWebviewEditor(input => { + this.updateWebviewViewStates(input); + })); + // This reviver's only job is to activate extensions. // This should trigger the real reviver to be registered from the extension host side. this._register(_webviewWorkbenchService.registerResolver({ @@ -260,27 +258,6 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc this._revivers.delete(viewType); } - private registerWebviewFromDiffEditorListeners(diffEditorInput: DiffEditorInput): void { - const primary = diffEditorInput.primary as WebviewInput; - const secondary = diffEditorInput.secondary as WebviewInput; - - if (this._webviewFromDiffEditorHandles.has(primary.id) || this._webviewFromDiffEditorHandles.has(secondary.id)) { - return; - } - - this._webviewFromDiffEditorHandles.add(primary.id); - this._webviewFromDiffEditorHandles.add(secondary.id); - - const disposables = new DisposableStore(); - disposables.add(primary.webview.onDidFocus(() => this.updateWebviewViewStates(primary))); - disposables.add(secondary.webview.onDidFocus(() => this.updateWebviewViewStates(secondary))); - disposables.add(diffEditorInput.onWillDispose(() => { - this._webviewFromDiffEditorHandles.delete(primary.id); - this._webviewFromDiffEditorHandles.delete(secondary.id); - dispose(disposables); - })); - } - private updateWebviewViewStates(activeEditorInput: IEditorInput | undefined) { if (!this._webviewInputs.size) { return; diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index fd65baf6741..46eae31ecc5 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -208,8 +208,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- trust --- - $requireWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise { - return this._workspaceTrustService.requireWorkspaceTrust(options); + $requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise { + return this._workspaceTrustService.requestWorkspaceTrust(options); } private getWorkspaceTrustState(): WorkspaceTrustState { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index dd52a8254fe..25a7e4fdb2d 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -912,9 +912,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return extHostWorkspace.trustState; }, - requireWorkspaceTrust: (options?: vscode.WorkspaceTrustRequestOptions) => { + requestWorkspaceTrust: (options?: vscode.WorkspaceTrustRequestOptions) => { checkProposedApiEnabled(extension); - return extHostWorkspace.requireWorkspaceTrust(options); + return extHostWorkspace.requestWorkspaceTrust(options); }, onDidChangeWorkspaceTrustState: (listener, thisArgs?, disposables?) => { return extHostWorkspace.onDidChangeWorkspaceTrustState(listener, thisArgs, disposables); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 541891d7cdd..356eb5c85c1 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -927,7 +927,7 @@ export interface MainThreadWorkspaceShape extends IDisposable { $saveAll(includeUntitled?: boolean): Promise; $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string; }[]): Promise; $resolveProxy(url: string): Promise; - $requireWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise; + $requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise; } export interface IFileChangeDto { diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 7f8e37a632b..bc6dc84f2a2 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -225,6 +225,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { } } + processBinary(data: string) { + throw new Error('not implemented'); + } + acknowledgeDataEvent(charCount: number): void { // No-op, flow control is not supported in extension owned terminals. If this is ever // implemented it will need new pause and resume VS Code APIs. diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index 07e1a00e390..714df5a4e9b 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -563,8 +563,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac return this._workspaceTrustState; } - requireWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise { - return this._proxy.$requireWorkspaceTrust(options); + requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise { + return this._proxy.$requestWorkspaceTrust(options); } $onDidChangeWorkspaceTrustState(state: WorkspaceTrustStateChangeEvent): void { diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 5bf9fbb81f9..dd250c83c29 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -153,19 +153,19 @@ export class ExtHostTask extends ExtHostTaskBase { } }; for (let variable of toResolve.variables) { - result.variables[variable] = resolver.resolve(ws, variable); + result.variables[variable] = await resolver.resolveAsync(ws, variable); } if (toResolve.process !== undefined) { let paths: string[] | undefined = undefined; if (toResolve.process.path !== undefined) { paths = toResolve.process.path.split(path.delimiter); for (let i = 0; i < paths.length; i++) { - paths[i] = resolver.resolve(ws, paths[i]); + paths[i] = await resolver.resolveAsync(ws, paths[i]); } } result.process = await win32.findExecutable( - resolver.resolve(ws, toResolve.process.name), - toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined, + await resolver.resolveAsync(ws, toResolve.process.name), + toResolve.process.cwd !== undefined ? await resolver.resolveAsync(ws, toResolve.process.cwd) : undefined, paths ); } diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index fad39115832..6b113e86abd 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -70,7 +70,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { protected async _beforeAlmostReadyToRunExtensions(): Promise { const mainThreadConsole = this._extHostContext.getProxy(MainContext.MainThreadConsole); - wrapConsoleMethods(mainThreadConsole); + wrapConsoleMethods(mainThreadConsole, this._initData.environment.isExtensionDevelopmentDebug); // initialize API and register actors const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors); @@ -173,15 +173,19 @@ function ensureSuffix(path: string, suffix: string): string { } // copied from bootstrap-fork.js -function wrapConsoleMethods(service: MainThreadConsoleShape) { +function wrapConsoleMethods(service: MainThreadConsoleShape, callToNative: boolean) { wrap('info', 'log'); wrap('log', 'log'); wrap('warn', 'warn'); wrap('error', 'error'); function wrap(method: 'error' | 'warn' | 'info' | 'log', severity: 'error' | 'warn' | 'log') { + const original = console[method]; console[method] = function () { service.$logExtensionHostMessage({ type: '__$console', severity, arguments: safeToArray(arguments) }); + if (callToNative) { + original.apply(console, arguments as any); + } }; } diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index 8274e3dfe3c..f53737da402 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -149,7 +149,7 @@ class ViewMenuActions extends CompositeMenuActions { const scopedContextKeyService = contextKeyService.createScoped(element); scopedContextKeyService.createKey('view', viewId); const viewLocationKey = scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(viewId)!)); - super(menuId, contextMenuId, undefined, scopedContextKeyService, menuService); + super(menuId, contextMenuId, { shouldForwardArgs: true }, scopedContextKeyService, menuService); this._register(scopedContextKeyService); this._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === viewId))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(viewId)!)))); } diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 155e8889007..32db51de439 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -305,7 +305,7 @@ class ViewContainerMenuActions extends CompositeMenuActions { const scopedContextKeyService = contextKeyService.createScoped(element); scopedContextKeyService.createKey('viewContainer', viewContainer.id); const viewContainerLocationKey = scopedContextKeyService.createKey('viewContainerLocation', ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)); - super(MenuId.ViewContainerTitle, MenuId.ViewContainerTitleContext, undefined, scopedContextKeyService, menuService); + super(MenuId.ViewContainerTitle, MenuId.ViewContainerTitleContext, { shouldForwardArgs: true }, scopedContextKeyService, menuService); this._register(scopedContextKeyService); this._register(Event.filter(viewDescriptorService.onDidChangeContainerLocation, e => e.viewContainer === viewContainer)(() => viewContainerLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewContainerLocation(viewContainer)!)))); } diff --git a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts index cab0ed9a70a..984defd93ce 100644 --- a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts +++ b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts @@ -12,7 +12,8 @@ import { IExtensionsViewPaneContainer, IExtensionsWorkbenchService, IExtension } import { CancellationToken } from 'vs/base/common/cancellation'; import { localize } from 'vs/nls'; import { StorageScope, IStorageService, StorageTarget } from 'vs/platform/storage/common/storage'; -import { ImportantExtensionTip, IProductService } from 'vs/platform/product/common/productService'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ImportantExtensionTip } from 'vs/base/common/product'; import { forEach, IStringDictionary } from 'vs/base/common/collections'; import { ITextModel } from 'vs/editor/common/model'; import { Schemas } from 'vs/base/common/network'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index a29c52ae4d3..1534fb16b42 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -270,7 +270,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD updateItems.push({ output: key, cellTop: cellTop, - outputOffset: outputOffset + outputOffset: outputOffset, + forceDisplay: false }); } } @@ -280,7 +281,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD removedItems.forEach(output => activeWebview.removeInset(output)); if (updateItems.length) { - activeWebview.updateViewScrollTop(-scrollTop, false, updateItems); + activeWebview.updateScrollTops(updateItems, []); } } } @@ -575,10 +576,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - const scrollTop = this._list.scrollTop; const outputIndex = cellViewModel.outputsViewModels.indexOf(output.source); const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - activeWebview.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); + activeWebview.updateScrollTops([{ output: output.source, cellTop, outputOffset, forceDisplay: true }], []); } }); } @@ -622,10 +622,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - const scrollTop = this._list.scrollTop; const outputIndex = cellViewModel.outputsViewModels.indexOf(displayOutput); const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - activeWebview.updateViewScrollTop(-scrollTop, true, [{ output: displayOutput, cellTop, outputOffset }]); + activeWebview.updateScrollTops([{ output: displayOutput, cellTop, outputOffset, forceDisplay: true }], []); }); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index acf2af1d3a1..27fc285e9d4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -140,6 +140,7 @@ export interface IDisplayOutputLayoutUpdateRequest { output: IDisplayOutputViewModel; cellTop: number; outputOffset: number; + forceDisplay: boolean; } export interface ICommonCellInfo { @@ -480,7 +481,6 @@ export interface INotebookEditor extends ICommonNotebookEditor { unhideMarkdownPreview(cell: ICellViewModel): Promise; hideMarkdownPreview(cell: ICellViewModel): Promise; removeMarkdownPreview(cell: ICellViewModel): Promise; - updateMarkdownPreviewSelectionState(cell: ICellViewModel, isSelected: boolean): Promise; /** * Render the output in webview layer diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index cd6d235c6a7..730c39262ca 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1119,87 +1119,80 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._localStore.add(this.viewModel.onDidChangeSelection(() => { this._onDidChangeSelection.fire(); + this.updateSelectedMarkdownPreviews(); })); this._localStore.add(this._list.onWillScroll(e => { if (this._webview?.isResolved()) { - this._webview.updateViewScrollTop(-e.scrollTop, true, []); this._webviewTransparentCover!.style.top = `${e.scrollTop}px`; } })); + let hasPendingChangeContentHeight = false; this._localStore.add(this._list.onDidChangeContentHeight(() => { + if (hasPendingChangeContentHeight) { + return; + } + hasPendingChangeContentHeight = true; + DOM.scheduleAtNextAnimationFrame(() => { - if (this._isDisposed) { + hasPendingChangeContentHeight = false; + if (this._isDisposed || !this._webview?.isResolved()) { return; } - const scrollTop = this._list.scrollTop; const scrollHeight = this._list.scrollHeight; - - if (!this._webview?.isResolved()) { - return; - } - this._webview!.element.style.height = `${scrollHeight}px`; - if (this._webview?.insetMapping) { - const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; - const removedItems: ICellOutputViewModel[] = []; - this._webview?.insetMapping.forEach((value, key) => { - const cell = this.viewModel?.getCellByHandle(value.cellInfo.cellHandle); - if (!cell || !(cell instanceof CodeCellViewModel)) { - return; - } + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; + const removedItems: ICellOutputViewModel[] = []; + this._webview?.insetMapping.forEach((value, key) => { + const cell = this.viewModel?.getCellByHandle(value.cellInfo.cellHandle); + if (!cell || !(cell instanceof CodeCellViewModel)) { + return; + } - const viewIndex = this._list.getViewIndex(cell); + this.viewModel?.viewCells.find(cell => cell.handle === value.cellInfo.cellHandle); + const viewIndex = this._list.getViewIndex(cell); - if (viewIndex === undefined) { - return; - } + if (viewIndex === undefined) { + return; + } - if (cell.outputsViewModels.indexOf(key) < 0) { - // output is already gone - removedItems.push(key); - } + if (cell.outputsViewModels.indexOf(key) < 0) { + // output is already gone + removedItems.push(key); + } + const cellTop = this._list.getAbsoluteTopOfElement(cell); + if (this._webview!.shouldUpdateInset(cell, key, cellTop)) { + const outputIndex = cell.outputsViewModels.indexOf(key); + + const outputOffset = cellTop + cell.getOutputOffset(outputIndex); + + updateItems.push({ + output: key, + cellTop: cellTop, + outputOffset, + forceDisplay: false, + }); + } + }); + + removedItems.forEach(output => this._webview?.removeInset(output)); + + const markdownUpdateItems: { id: string, top: number }[] = []; + for (const cellId of this._webview.markdownPreviewMapping.keys()) { + const cell = this.viewModel?.viewCells.find(cell => cell.id === cellId); + if (cell) { const cellTop = this._list.getAbsoluteTopOfElement(cell); - if (this._webview!.shouldUpdateInset(cell, key, cellTop)) { - const outputIndex = cell.outputsViewModels.indexOf(key); - - const outputOffset = cellTop + cell.getOutputOffset(outputIndex); - - updateItems.push({ - output: key, - cellTop: cellTop, - outputOffset - }); - } - }); - - removedItems.forEach(output => this._webview?.removeInset(output)); - - if (updateItems.length) { - this._debug('_list.onDidChangeContentHeight/outputs', updateItems); - this._webview?.updateViewScrollTop(-scrollTop, false, updateItems); + markdownUpdateItems.push({ id: cellId, top: cellTop }); } } - if (this._webview?.markdownPreviewMapping) { - const updateItems: { id: string, top: number }[] = []; - this._webview.markdownPreviewMapping.forEach((_, cellId) => { - const cell = this.viewModel?.viewCells.find(cell => cell.id === cellId); - if (cell) { - const cellTop = this._list.getAbsoluteTopOfElement(cell); - updateItems.push({ id: cellId, top: cellTop }); - } - }); - - if (updateItems.length) { - this._debug('_list.onDidChangeContentHeight/markdown', updateItems); - this._webview?.updateMarkdownScrollTop(updateItems); - } - + if (markdownUpdateItems.length || updateItems.length) { + this._debug('_list.onDidChangeContentHeight/markdown', markdownUpdateItems); + this._webview?.updateScrollTops(updateItems, markdownUpdateItems); } }); })); @@ -1308,10 +1301,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor // no cached view state so we are rendering the first viewport // after above async call, we already get init height for markdown cells, we can update their offset let offset = 0; - let offsetUpdateRequests: { id: string, top: number }[] = []; + const offsetUpdateRequests: { id: string, top: number }[] = []; const scrollBottom = Math.max(this._dimension?.height ?? 0, 1080); - for (let i = 0; i < viewModel.length; i++) { - const cell = viewModel.cellAt(i)!; + for (const cell of viewModel.viewCells) { if (cell.cellKind === CellKind.Markdown) { offsetUpdateRequests.push({ id: cell.id, top: offset }); } @@ -1323,7 +1315,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } - this._webview?.updateMarkdownScrollTop(offsetUpdateRequests); + this._webview?.updateScrollTops([], offsetUpdateRequests); } } @@ -2196,13 +2188,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor await this._webview?.removeMarkdownPreview(cell.id); } - async updateMarkdownPreviewSelectionState(cell: ICellViewModel, isSelected: boolean): Promise { - if (!this.useRenderer) { - // TODO: handle case where custom renderer is disabled? - return; - } - - if (!this._webview) { + private async updateSelectedMarkdownPreviews(): Promise { + if (!this.useRenderer || !this._webview) { return; } @@ -2210,7 +2197,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor await this._resolveWebview(); } - await this._webview?.updateMarkdownPreviewSelectionState(cell.id, isSelected); + const selectedCells = this.getSelectionViewModels().map(cell => cell.id); + + // Only show selection when there is more than 1 cell selected + await this._webview?.updateMarkdownPreviewSelections(selectedCells.length > 1 ? selectedCells : []); } async createOutput(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise { @@ -2223,16 +2213,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor await this._resolveWebview(); } + const cellTop = this._list.getAbsoluteTopOfElement(cell); if (!this._webview!.insetMapping.has(output.source)) { - const cellTop = this._list.getAbsoluteTopOfElement(cell); await this._webview!.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset); } else { - const cellTop = this._list.getAbsoluteTopOfElement(cell); - const scrollTop = this._list.scrollTop; const outputIndex = cell.outputsViewModels.indexOf(output.source); const outputOffset = cellTop + cell.getOutputOffset(outputIndex); - this._webview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); + this._webview!.updateScrollTops([{ output: output.source, cellTop, outputOffset, forceDisplay: true }], []); } }); } 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 8ba74c9465f..55bd58b916a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -26,6 +26,7 @@ import { IWebviewService, WebviewContentPurpose, WebviewElement } from 'vs/workb import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import * as nls from 'vs/nls'; +import { coalesce } from 'vs/base/common/arrays'; interface BaseToWebviewMessage { readonly __vscode_notebook_message: true; @@ -35,14 +36,18 @@ export interface WebviewIntialized extends BaseToWebviewMessage { type: 'initialized'; } -export interface IDimensionMessage extends BaseToWebviewMessage { - type: 'dimension'; +export interface DimensionUpdate { id: string; init?: boolean; data: { height: number }; isOutput?: boolean; } +export interface IDimensionMessage extends BaseToWebviewMessage { + type: 'dimension'; + updates: readonly DimensionUpdate[]; +} + export interface IMouseEnterMessage extends BaseToWebviewMessage { type: 'mouseenter'; id: string; @@ -183,20 +188,13 @@ export interface ICreationRequestMessage { export interface IContentWidgetTopRequest { id: string; top: number; - left: number; + forceDisplay: boolean; } export interface IViewScrollTopRequestMessage { type: 'view-scroll'; - top?: number; - forceDisplay: boolean; widgets: IContentWidgetTopRequest[]; - version: number; -} - -export interface IViewScrollMarkdownRequestMessage { - type: 'view-scroll-markdown'; - cells: { id: string; top: number }[]; + markdownPreviews: { id: string; top: number }[]; } export interface IScrollRequestMessage { @@ -287,10 +285,9 @@ export interface IShowMarkdownMessage { top: number; } -export interface IUpdateMarkdownPreviewSelectionState { - readonly type: 'updateMarkdownPreviewSelectionState', - readonly id: string; - readonly isSelected: boolean; +export interface IUpdateSelectedMarkdownPreviews { + readonly type: 'updateSelectedMarkdownPreviews', + readonly selectedCellIds: readonly string[] } export interface IInitializeMarkdownMessage { @@ -337,9 +334,8 @@ export type ToWebviewMessage = | IShowMarkdownMessage | IHideMarkdownMessage | IUnhideMarkdownMessage - | IUpdateMarkdownPreviewSelectionState - | IInitializeMarkdownMessage - | IViewScrollMarkdownRequestMessage; + | IUpdateSelectedMarkdownPreviews + | IInitializeMarkdownMessage; export type AnyMessage = FromWebviewMessage | ToWebviewMessage; @@ -367,12 +363,11 @@ export interface IResolvedBackLayerWebview { webview: WebviewElement; } -let version = 0; export class BackLayerWebView extends Disposable { element: HTMLElement; webview: WebviewElement | undefined = undefined; insetMapping: Map> = new Map(); - markdownPreviewMapping = new Map(); + readonly markdownPreviewMapping = new Map(); hiddenInsetMapping: Set = new Set(); reversedInsetMapping: Map = new Map(); localResourceRootsCache: URI[] | undefined = undefined; @@ -838,18 +833,20 @@ var requirejs = (function() { switch (data.type) { case 'dimension': { - if (data.isOutput) { - const height = data.data.height; - const outputHeight = height; + for (const update of data.updates) { + if (update.isOutput) { + const height = update.data.height; + const outputHeight = height; - const resolvedResult = this.resolveOutputId(data.id); - if (resolvedResult) { - const { cellInfo, output } = resolvedResult; - this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight, !!data.init, 'webview#dimension'); + const resolvedResult = this.resolveOutputId(update.id); + if (resolvedResult) { + const { cellInfo, output } = resolvedResult; + this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight, !!update.init, 'webview#dimension'); + } + } else { + const cellId = update.id.substr(0, update.id.length - '_preview'.length); + this.notebookEditor.updateMarkdownCellHeight(cellId, update.data.height, !!update.init); } - } else { - const cellId = data.id.substr(0, data.id.length - '_preview'.length); - this.notebookEditor.updateMarkdownCellHeight(cellId, data.data.height, !!data.init); } break; } @@ -1109,20 +1106,16 @@ var requirejs = (function() { return true; } - updateMarkdownScrollTop(items: { id: string, top: number }[]) { - this._sendMessageToWebview({ - type: 'view-scroll-markdown', - cells: items - }); - } - - updateViewScrollTop(top: number, forceDisplay: boolean, items: IDisplayOutputLayoutUpdateRequest[]) { + updateScrollTops(outputs: IDisplayOutputLayoutUpdateRequest[], markdownPreviews: { id: string, top: number }[]) { if (this._disposed) { return; } - const widgets: IContentWidgetTopRequest[] = items.map(item => { - const outputCache = this.insetMapping.get(item.output)!; + const widgets = coalesce(outputs.map((item): IContentWidgetTopRequest | undefined => { + const outputCache = this.insetMapping.get(item.output); + if (!outputCache) { + return; + } const id = outputCache.outputId; const outputOffset = item.outputOffset; outputCache.cachedCreation.top = outputOffset; @@ -1131,16 +1124,18 @@ var requirejs = (function() { return { id: id, top: outputOffset, - left: 0 + forceDisplay: item.forceDisplay, }; - }); + })); + + if (!widgets.length && !markdownPreviews.length) { + return; + } this._sendMessageToWebview({ - top, type: 'view-scroll', - version: version++, - forceDisplay, - widgets: widgets + widgets: widgets, + markdownPreviews, }); } @@ -1256,21 +1251,14 @@ var requirejs = (function() { }); } - async updateMarkdownPreviewSelectionState(cellId: any, isSelected: boolean) { + async updateMarkdownPreviewSelections(selectedCellsIds: string[]) { if (this._disposed) { return; } - if (!this.markdownPreviewMapping.has(cellId)) { - // TODO: this currently seems expected on first load - // console.error(`Try to update selection state for preview that does not exist: ${cellId}`); - return; - } - this._sendMessageToWebview({ - type: 'updateMarkdownPreviewSelectionState', - id: cellId, - isSelected + type: 'updateSelectedMarkdownPreviews', + selectedCellIds: selectedCellsIds.filter(id => this.markdownPreviewMapping.has(id)), }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index dd390711ee8..b92b769d478 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -198,15 +198,6 @@ export class StatefulMarkdownCell extends Disposable { if (this.viewCell.layoutInfo.totalHeight > 0) { this.relayoutCell(); } - - // Update for selection - this._register(this.notebookEditor.onDidChangeSelection(() => { - const selectedCells = this.notebookEditor.getSelectionViewModels(); - - // Only show selection if there are more than one cells selected - const isSelected = selectedCells.length > 1 && selectedCells.some(selectedCell => selectedCell === viewCell); - this.notebookEditor.updateMarkdownPreviewSelectionState(viewCell, isSelected); - })); } // apply decorations diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 2397e729de4..50489962e84 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -6,7 +6,7 @@ import type { Event } from 'vs/base/common/event'; import type { IDisposable } from 'vs/base/common/lifecycle'; import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { FromWebviewMessage, IBlurOutputMessage, ICellDropMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, ICustomRendererMessage, IDimensionMessage, IClickMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage, ICellDragEndMessage, IOutputFocusMessage, IOutputBlurMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; +import { FromWebviewMessage, IBlurOutputMessage, ICellDropMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, ICustomRendererMessage, IDimensionMessage, IClickMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage, ICellDragEndMessage, IOutputFocusMessage, IOutputBlurMessage, DimensionUpdate } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; // !! IMPORTANT !! everything must be in-line within the webviewPreloads // function. Imports are not allowed. This is stringifies and injected into @@ -136,6 +136,26 @@ function webviewPreloads() { const outputObservers = new Map(); + const dimensionUpdater = new class { + private readonly pending = new Map(); + + update(id: string, update: DimensionUpdate) { + if (!this.pending.size) { + setTimeout(() => { + if (!this.pending.size) { + return; + } + + postNotebookMessage('dimension', { + updates: Array.from(this.pending.values()) + }); + this.pending.clear(); + }, 0); + } + this.pending.set(id, update); + } + }; + const resizeObserve = (container: Element, id: string, output: boolean) => { const resizeObserver = new ResizeObserver(entries => { for (const entry of entries) { @@ -145,27 +165,20 @@ function webviewPreloads() { if (entry.target.id === id && entry.contentRect) { if (output) { + let height = 0; if (entry.contentRect.height !== 0) { entry.target.style.padding = `${__outputNodePadding__}px ${__outputNodePadding__}px ${__outputNodePadding__}px ${output ? __outputNodeLeftPadding__ : __leftMargin__}px`; - postNotebookMessage('dimension', { - id: id, - data: { - height: entry.contentRect.height + __outputNodePadding__ * 2 - }, - isOutput: true - }); + height = entry.contentRect.height + __outputNodePadding__ * 2; } else { entry.target.style.padding = `0px`; - postNotebookMessage('dimension', { - id: id, - data: { - height: entry.contentRect.height - }, - isOutput: true - }); } + dimensionUpdater.update(id, { + id: id, + data: { height }, + isOutput: true + }); } else { - postNotebookMessage('dimension', { + dimensionUpdater.update(id, { id: id, data: { // entry.contentRect does not include padding @@ -537,12 +550,22 @@ function webviewPreloads() { } } break; - case 'updateMarkdownPreviewSelectionState': + case 'updateSelectedMarkdownPreviews': { - const data = event.data; - const previewNode = document.getElementById(`${data.id}_preview`); - if (previewNode) { - previewNode.classList.toggle('selected', data.isSelected); + const selectedCellIds = new Set(event.data.selectedCellIds); + + for (const oldSelected of document.querySelectorAll('.preview.selected')) { + const id = oldSelected.id.replace('_preview', ''); + if (!selectedCellIds.has(id)) { + oldSelected.classList.remove('selected'); + } + } + + for (const newSelected of selectedCellIds) { + const previewNode = document.getElementById(`${newSelected}_preview`); + if (previewNode) { + previewNode.classList.add('selected'); + } } } break; @@ -634,7 +657,7 @@ function webviewPreloads() { if (clientHeight !== 0 && cps.padding === '0px') { // we set padding to zero if the output height is zero (then we can have a zero-height output DOM node) // thus we need to ensure the padding is accounted when updating the init height of the output - postNotebookMessage('dimension', { + dimensionUpdater.update(outputId, { id: outputId, isOutput: true, init: true, @@ -645,7 +668,7 @@ function webviewPreloads() { outputNode.style.padding = `${__outputNodePadding__}px ${__outputNodePadding__}px ${__outputNodePadding__}px ${__outputNodeLeftPadding__}px`; } else { - postNotebookMessage('dimension', { + dimensionUpdater.update(outputId, { id: outputId, isOutput: true, init: true, @@ -656,7 +679,7 @@ function webviewPreloads() { } // don't hide until after this step so that the height is right - cellOutputContainer.style.display = data.initiallyHidden ? 'none' : 'block'; + cellOutputContainer.style.visibility = data.initiallyHidden ? 'hidden' : 'visible'; }); break; case 'view-scroll': @@ -664,34 +687,22 @@ function webviewPreloads() { // const date = new Date(); // console.log('----- will scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds()); - for (let i = 0; i < event.data.widgets.length; i++) { - const widget = document.getElementById(event.data.widgets[i].id)!; + for (const request of event.data.widgets) { + const widget = document.getElementById(request.id)!; if (widget) { - widget.style.top = event.data.widgets[i].top + 'px'; - if (event.data.forceDisplay) { - widget.parentElement!.style.display = 'block'; + widget.style.top = request.top + 'px'; + if (request.forceDisplay) { + widget.parentElement!.style.visibility = 'visible'; } } } - break; - } - case 'view-scroll-markdown': - { - // const date = new Date(); - // console.log(`${date.getSeconds()}:${date.getMilliseconds().toString().padStart(3, '0')}`, '[iframe]: view-scroll-markdown', event.data.cells); - event.data.cells.map(cell => { - const widget = document.getElementById(`${cell.id}_preview`)!; + for (const cell of event.data.markdownPreviews) { + const widget = document.getElementById(`${cell.id}_preview`)!; if (widget) { widget.style.top = `${cell.top}px`; } - - const markdownPreview = document.getElementById(`${cell.id}`); - - if (markdownPreview) { - markdownPreview.style.display = 'block'; - } - }); + } break; } @@ -721,7 +732,7 @@ function webviewPreloads() { enqueueOutputAction(event.data, ({ outputId }) => { const container = document.getElementById(outputId)?.parentElement; if (container) { - container.style.display = 'none'; + container.style.visibility = 'hidden'; } }); break; @@ -729,10 +740,10 @@ function webviewPreloads() { enqueueOutputAction(event.data, ({ outputId, top }) => { const output = document.getElementById(outputId); if (output) { - output.parentElement!.style.display = 'block'; + output.parentElement!.style.visibility = 'visible'; output.style.top = top + 'px'; - postNotebookMessage('dimension', { + dimensionUpdater.update(outputId, { id: outputId, isOutput: true, data: { @@ -767,13 +778,8 @@ function webviewPreloads() { case 'decorations': { const outputContainer = document.getElementById(event.data.cellId); - event.data.addedClassNames.forEach(n => { - outputContainer?.classList.add(n); - }); - - event.data.removedClassNames.forEach(n => { - outputContainer?.classList.remove(n); - }); + outputContainer?.classList.add(...event.data.addedClassNames); + outputContainer?.classList.remove(...event.data.removedClassNames); } break; @@ -839,8 +845,7 @@ function webviewPreloads() { cellContainer.appendChild(previewContainerNode); - previewContainerNode.attachShadow({ mode: 'open' }); - const previewRoot = previewContainerNode.shadowRoot! as any as HTMLElement; + const previewRoot = previewContainerNode.attachShadow({ mode: 'open' }); // Add default webview style const defaultStyles = document.getElementById('_defaultStyles') as HTMLStyleElement; @@ -894,7 +899,7 @@ function webviewPreloads() { } } - postNotebookMessage('dimension', { + dimensionUpdater.update(`${cellId}_preview`, { id: `${cellId}_preview`, data: { height: previewContainerNode.clientHeight, diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 6993e08a59f..b50dca22023 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -104,7 +104,6 @@ class PerfModelContentProvider implements ITextModelContentProvider { this._model.setMode(e); } })); - this._modelDisposables.push(langId); this._modelDisposables.push(this._extensionService.onDidChangeExtensionsStatus(this._updateModel, this)); writeTransientState(this._model, { wordWrapOverride: 'off' }, this._editorService); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 87131ec930f..1f397c9244f 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -1025,24 +1025,21 @@ export class DefaultPreferencesEditor extends BaseTextEditor { return options; } - setInput(input: DefaultPreferencesEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { - return super.setInput(input, options, context, token) - .then(() => this.input!.resolve() - .then(editorModel => { - if (token.isCancellationRequested) { - return undefined; - } - - return editorModel!.resolve(); - }) - .then(editorModel => { - if (token.isCancellationRequested) { - return; - } - - const editor = assertIsDefined(this.getControl()); - editor.setModel((editorModel).textEditorModel); - })); + async setInput(input: DefaultPreferencesEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + await super.setInput(input, options, context, token); + const editorModel = await this.input!.resolve(); + if (!editorModel) { + return; + } + if (token.isCancellationRequested) { + return; + } + await editorModel.resolve(); + if (token.isCancellationRequested) { + return; + } + const editor = assertIsDefined(this.getControl()); + editor.setModel((editorModel).textEditorModel); } clearInput(): void { diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 32f568b22bd..9aa879ad2cb 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -94,11 +94,11 @@ export class ForwardedPortsView extends Disposable implements IWorkbenchContribu private enableBadgeAndStatusBar() { const disposable = Registry.as(Extensions.ViewsRegistry).onViewsRegistered(e => { if (e.find(view => view.views.find(viewDescriptor => viewDescriptor.id === TUNNEL_VIEW_ID))) { - this._register(this.remoteExplorerService.tunnelModel.onForwardPort(() => { + this._register(Event.debounce(this.remoteExplorerService.tunnelModel.onForwardPort, (_last, e) => e, 50)(() => { this.updateActivityBadge(); this.updateStatusBar(); })); - this._register(this.remoteExplorerService.tunnelModel.onClosePort(() => { + this._register(Event.debounce(this.remoteExplorerService.tunnelModel.onClosePort, (_last, e) => e, 50)(() => { this.updateActivityBadge(); this.updateStatusBar(); })); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 1c933344fdf..e20534ded31 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -664,6 +664,10 @@ export class TunnelPanel extends ViewPane { })); } + get portCount(): number { + return this.remoteExplorerService.tunnelModel.forwarded.size + this.remoteExplorerService.tunnelModel.detected.size; + } + protected renderBody(container: HTMLElement): void { super.renderBody(container); @@ -719,8 +723,12 @@ export class TunnelPanel extends ViewPane { const rerender = () => this.table.splice(0, Number.POSITIVE_INFINITY, this.viewModel.all); rerender(); - this._register(this.viewModel.onForwardedPortsChanged(() => { - this._onDidChangeViewWelcomeState.fire(); + let lastPortCount = this.portCount; + this._register(Event.debounce(this.viewModel.onForwardedPortsChanged, (_last, e) => e, 50)(() => { + const newPortCount = this.portCount; + if (((lastPortCount === 0) || (newPortCount === 0)) && (lastPortCount !== newPortCount)) { + this._onDidChangeViewWelcomeState.fire(); + } rerender(); })); diff --git a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts index d7452466e3a..6cae0d75ea4 100644 --- a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts @@ -10,7 +10,8 @@ import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { ISurveyData, IProductService } from 'vs/platform/product/common/productService'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ISurveyData } from 'vs/base/common/product'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Severity, INotificationService } from 'vs/platform/notification/common/notification'; import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index a7e27c56982..1179b8ee12e 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2058,6 +2058,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0]; workspaceFolders.push(workspaceFolder); executionEngine = this.computeExecutionEngine(workspaceFolder); + const telemetryData: { [key: string]: any; } = { + executionEngineVersion: executionEngine + }; + /* __GDPR__ + "taskService.engineVersion" : { + "executionEngineVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('taskService.engineVersion', telemetryData); schemaVersion = this.computeJsonSchemaVersion(workspaceFolder); } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { workspace = this.contextService.getWorkspace(); diff --git a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts index 74ce4b72106..4e2b12579c9 100644 --- a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts +++ b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts @@ -116,7 +116,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut public static async promptForPermission(taskService: ITaskService, storageService: IStorageService, notificationService: INotificationService, workspaceTrustService: IWorkspaceTrustService, openerService: IOpenerService, workspaceTaskResult: Map) { - const isWorkspaceTrusted = await workspaceTrustService.requireWorkspaceTrust({ modal: false }) === WorkspaceTrustState.Trusted; + const isWorkspaceTrusted = await workspaceTrustService.requestWorkspaceTrust({ modal: false }) === WorkspaceTrustState.Trusted; if (!isWorkspaceTrusted) { return; } diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 6695bfb1c25..c65f1c112bb 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -81,21 +81,30 @@ class InstanceManager { } class VariableResolver { - + private static regex = /\$\{(.*?)\}/g; constructor(public workspaceFolder: IWorkspaceFolder | undefined, public taskSystemInfo: TaskSystemInfo | undefined, public readonly values: Map, private _service: IConfigurationResolverService | undefined) { } - resolve(value: string): string { - return value.replace(/\$\{(.*?)\}/g, (match: string, variable: string) => { - // Strip out the ${} because the map contains them variables without those characters. - let result = this.values.get(match.substring(2, match.length - 1)); - if ((result !== undefined) && (result !== null)) { - return result; - } - if (this._service) { - return this._service.resolve(this.workspaceFolder, match); - } + async resolve(value: string): Promise { + const replacers: Promise[] = []; + value.replace(VariableResolver.regex, (match, ...args) => { + replacers.push(this.replacer(match, args)); return match; }); + const resolvedReplacers = await Promise.all(replacers); + return value.replace(VariableResolver.regex, () => resolvedReplacers.shift()!); + + } + + private async replacer(match: string, args: string[]): Promise { + // Strip out the ${} because the map contains them variables without those characters. + let result = this.values.get(match.substring(2, match.length - 1)); + if ((result !== undefined) && (result !== null)) { + return result; + } + if (this._service) { + return this._service.resolveAsync(this.workspaceFolder, match); + } + return match; } } @@ -534,9 +543,9 @@ export class TerminalTaskSystem implements ITaskSystem { } private async resolveAndFindExecutable(systemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, cwd: string | undefined, envPath: string | undefined): Promise { - const command = this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)); - cwd = cwd ? this.configurationResolverService.resolve(workspaceFolder, cwd) : undefined; - const paths = envPath ? envPath.split(path.delimiter).map(p => this.configurationResolverService.resolve(workspaceFolder, p)) : undefined; + const command = await this.configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); + cwd = cwd ? await this.configurationResolverService.resolveAsync(workspaceFolder, cwd) : undefined; + const paths = envPath ? await Promise.all(envPath.split(path.delimiter).map(p => this.configurationResolverService.resolveAsync(workspaceFolder, p))) : undefined; let foundExecutable = await systemInfo?.findExecutable(command, cwd, paths); if (!foundExecutable) { foundExecutable = path.join(cwd ?? '', command); @@ -633,7 +642,7 @@ export class TerminalTaskSystem implements ITaskSystem { if (Platform.isWindows) { processVarValue = await this.resolveAndFindExecutable(taskSystemInfo, workspaceFolder, task, cwd, envPath); } else { - processVarValue = this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)); + processVarValue = await this.configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); } resolvedVariablesMap.set(TerminalTaskSystem.ProcessVarName, processVarValue); } @@ -726,7 +735,7 @@ export class TerminalTaskSystem implements ITaskSystem { let error: TaskError | undefined = undefined; let promise: Promise | undefined = undefined; if (task.configurationProperties.isBackground) { - const problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); + const problemMatchers = await this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService); if ((problemMatchers.length > 0) && !watchingProblemMatcher.isWatching()) { this.appendOutput(nls.localize('TerminalTaskSystem.nonWatchingMatcher', 'Task {0} is a background task but uses a problem matcher without a background pattern', task._label)); @@ -871,7 +880,7 @@ export class TerminalTaskSystem implements ITaskSystem { const mapKey = task.getMapKey(); this.busyTasks[mapKey] = task; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task)); - let problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); + let problemMatchers = await this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService); let skipLine: boolean = (!!task.command.presentation && task.command.presentation.echo); const onData = terminal.onLineData((line) => { @@ -1006,11 +1015,11 @@ export class TerminalTaskSystem implements ITaskSystem { let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell; if (shellOptions) { if (shellOptions.executable) { - shellLaunchConfig.executable = this.resolveVariable(variableResolver, shellOptions.executable); + shellLaunchConfig.executable = await this.resolveVariable(variableResolver, shellOptions.executable); shellSpecified = true; } if (shellOptions.args) { - shellLaunchConfig.args = this.resolveVariables(variableResolver, shellOptions.args.slice()); + shellLaunchConfig.args = await this.resolveVariables(variableResolver, shellOptions.args.slice()); } else { shellLaunchConfig.args = []; } @@ -1082,7 +1091,7 @@ export class TerminalTaskSystem implements ITaskSystem { } else { let commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution) ? CommandString.value(command) : undefined; let executable = !isShellCommand - ? this.resolveVariable(variableResolver, this.resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}')) + ? await this.resolveVariable(variableResolver, await this.resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}')) : commandExecutable; // When we have a process task there is no need to quote arguments. So we go ahead and take the string value. @@ -1129,7 +1138,7 @@ export class TerminalTaskSystem implements ITaskSystem { private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise<[ITerminalInstance | undefined, string | undefined, TaskError | undefined]> { let platform = resolver.taskSystemInfo ? resolver.taskSystemInfo.platform : Platform.platform; - let options = this.resolveOptions(resolver, task.command.options); + let options = await this.resolveOptions(resolver, task.command.options); let waitOnExit: boolean | string = false; const presentationOptions = task.command.presentation; @@ -1161,7 +1170,7 @@ export class TerminalTaskSystem implements ITaskSystem { isFeatureTerminal: true }; } else { - let resolvedResult: { command: CommandString, args: CommandString[] } = this.resolveCommandAndArgs(resolver, task.command); + let resolvedResult: { command: CommandString, args: CommandString[] } = await this.resolveCommandAndArgs(resolver, task.command); command = resolvedResult.command; args = resolvedResult.args; commandExecutable = CommandString.value(command); @@ -1466,26 +1475,26 @@ export class TerminalTaskSystem implements ITaskSystem { } while (matches); } - private resolveCommandAndArgs(resolver: VariableResolver, commandConfig: CommandConfiguration): { command: CommandString, args: CommandString[] } { + private async resolveCommandAndArgs(resolver: VariableResolver, commandConfig: CommandConfiguration): Promise<{ command: CommandString, args: CommandString[] }> { // First we need to use the command args: let args: CommandString[] = commandConfig.args ? commandConfig.args.slice() : []; - args = this.resolveVariables(resolver, args); - let command: CommandString = this.resolveVariable(resolver, commandConfig.name); + args = await this.resolveVariables(resolver, args); + let command: CommandString = await this.resolveVariable(resolver, commandConfig.name); return { command, args }; } - private resolveVariables(resolver: VariableResolver, value: string[]): string[]; - private resolveVariables(resolver: VariableResolver, value: CommandString[]): CommandString[]; - private resolveVariables(resolver: VariableResolver, value: CommandString[]): CommandString[] { - return value.map(s => this.resolveVariable(resolver, s)); + private async resolveVariables(resolver: VariableResolver, value: string[]): Promise; + private async resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise; + private async resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise { + return Promise.all(value.map(s => this.resolveVariable(resolver, s))); } - private resolveMatchers(resolver: VariableResolver, values: Array | undefined): ProblemMatcher[] { + private async resolveMatchers(resolver: VariableResolver, values: Array | undefined): Promise { if (values === undefined || values === null || values.length === 0) { return []; } let result: ProblemMatcher[] = []; - values.forEach((value) => { + for (const value of values) { let matcher: ProblemMatcher; if (Types.isString(value)) { if (value[0] === '$') { @@ -1498,7 +1507,7 @@ export class TerminalTaskSystem implements ITaskSystem { } if (!matcher) { this.appendOutput(nls.localize('unknownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored')); - return; + continue; } let taskSystemInfo: TaskSystemInfo | undefined = resolver.taskSystemInfo; let hasFilePrefix = matcher.filePrefix !== undefined; @@ -1511,23 +1520,23 @@ export class TerminalTaskSystem implements ITaskSystem { copy.uriProvider = taskSystemInfo.uriProvider; } if (hasFilePrefix) { - copy.filePrefix = this.resolveVariable(resolver, copy.filePrefix); + copy.filePrefix = await this.resolveVariable(resolver, copy.filePrefix); } result.push(copy); } - }); + } return result; } - private resolveVariable(resolver: VariableResolver, value: string | undefined): string; - private resolveVariable(resolver: VariableResolver, value: CommandString | undefined): CommandString; - private resolveVariable(resolver: VariableResolver, value: CommandString | undefined): CommandString { + private async resolveVariable(resolver: VariableResolver, value: string | undefined): Promise; + private async resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise; + private async resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise { // TODO@Dirk Task.getWorkspaceFolder should return a WorkspaceFolder that is defined in workspace.ts if (Types.isString(value)) { return resolver.resolve(value); } else if (value !== undefined) { return { - value: resolver.resolve(value.value), + value: await resolver.resolve(value.value), quoting: value.quoting }; } else { // This should never happen @@ -1535,29 +1544,29 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private resolveOptions(resolver: VariableResolver, options: CommandOptions | undefined): CommandOptions { + private async resolveOptions(resolver: VariableResolver, options: CommandOptions | undefined): Promise { if (options === undefined || options === null) { let cwd: string | undefined; try { - cwd = this.resolveVariable(resolver, '${workspaceFolder}'); + cwd = await this.resolveVariable(resolver, '${workspaceFolder}'); } catch (e) { // No workspace } return { cwd }; } let result: CommandOptions = Types.isString(options.cwd) - ? { cwd: this.resolveVariable(resolver, options.cwd) } - : { cwd: this.resolveVariable(resolver, '${workspaceFolder}') }; + ? { cwd: await this.resolveVariable(resolver, options.cwd) } + : { cwd: await this.resolveVariable(resolver, '${workspaceFolder}') }; if (options.env) { result.env = Object.create(null); - Object.keys(options.env).forEach((key) => { + for (const key of Object.keys(options.env)) { let value: any = options.env![key]; if (Types.isString(value)) { - result.env![key] = this.resolveVariable(resolver, value); + result.env![key] = await this.resolveVariable(resolver, value); } else { result.env![key] = value.toString(); } - }); + } } return result; } diff --git a/src/vs/workbench/contrib/terminal/browser/remotePty.ts b/src/vs/workbench/contrib/terminal/browser/remotePty.ts index a3a04aa97aa..66c9199989f 100644 --- a/src/vs/workbench/contrib/terminal/browser/remotePty.ts +++ b/src/vs/workbench/contrib/terminal/browser/remotePty.ts @@ -17,6 +17,8 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { public readonly _onProcessData = this._register(new Emitter()); public readonly onProcessData: Event = this._onProcessData.event; + public readonly _onProcessBinary = this._register(new Emitter()); + public readonly onProcessBinary: Event = this._onProcessBinary.event; private readonly _onProcessExit = this._register(new Emitter()); public readonly onProcessExit: Event = this._onProcessExit.event; public readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>()); @@ -118,6 +120,9 @@ export class RemotePty extends Disposable implements ITerminalChildProcess { handleData(e: string | IProcessDataEvent) { this._onProcessData.fire(e); } + processBinary(e: string) { + this._onProcessBinary.fire(e); + } handleExit(e: number | undefined) { this._onProcessExit.fire(e); } diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts index eca405fb55a..94ae8f9158b 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts @@ -49,6 +49,7 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal this._remoteTerminalChannel = channel; channel.onProcessData(e => this._ptys.get(e.id)?.handleData(e.event)); + channel.onProcessBinary(e => this._ptys.get(e.id)?.processBinary(e.event)); channel.onProcessExit(e => { const pty = this._ptys.get(e.id); if (pty) { @@ -168,8 +169,8 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal return undefined; } - public async listProcesses(reduceGraceTime: boolean = false): Promise { - const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listProcesses(reduceGraceTime) : []; + public async listProcesses(): Promise { + const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listProcesses() : []; return terms.map(termDto => { return { id: termDto.id, @@ -190,8 +191,14 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal return this._remoteTerminalChannel.setTerminalLayoutInfo(layout); } + public reduceConnectionGraceTime(): void { + if (!this._remoteTerminalChannel) { + throw new Error('Cannot reduce grace time when there is no remote'); + } + this._remoteTerminalChannel.reduceConnectionGraceTime(); + } + public async getTerminalLayoutInfo(): Promise { - await this._remoteTerminalChannel?.listProcesses(true); if (!this._remoteTerminalChannel) { throw new Error(`Cannot call getActiveInstanceId when there is no remote`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d7388f681a9..ee16f2378ff 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -292,6 +292,11 @@ export interface ITerminalInstance { */ onData: Event; + /** + * Attach a listener to the binary data stream coming from xterm and going to pty + */ + onBinary: Event; + /** * Attach a listener to listen for new lines added to this terminal instance. * diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index e00f4ff1ebb..9edcb33288f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -683,9 +683,13 @@ export function registerTerminalActions() { const labelService = accessor.get(ILabelService); const remoteAgentService = accessor.get(IRemoteAgentService); const notificationService = accessor.get(INotificationService); - const offProcTerminalService = remoteAgentService.getConnection() ? accessor.get(IRemoteTerminalService) : accessor.get(ILocalTerminalService); - const remoteTerms = await offProcTerminalService.listProcesses(); - const unattachedTerms = remoteTerms.filter(term => !terminalService.isAttachedToTerminal(term)); + let offProcTerminalService = remoteAgentService.getConnection() ? accessor.get(IRemoteTerminalService) : accessor.get(ILocalTerminalService); + + const terms = await offProcTerminalService.listProcesses(); + + offProcTerminalService.reduceConnectionGraceTime(); + + const unattachedTerms = terms.filter(term => !terminalService.isAttachedToTerminal(term)); const items = unattachedTerms.map(term => { const cwdLabel = labelService.getUriLabel(URI.file(term.cwd)); return { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index bf3f0908d21..5ace875fb3f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -184,6 +184,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { public get onTitleChanged(): Event { return this._onTitleChanged.event; } private readonly _onData = new Emitter(); public get onData(): Event { return this._onData.event; } + private readonly _onBinary = new Emitter(); + public get onBinary(): Event { return this._onBinary.event; } private readonly _onLineData = new Emitter(); public get onLineData(): Event { return this._onLineData.event; } private readonly _onRequestExtHostProcess = new Emitter(); @@ -468,6 +470,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._processManager.onProcessData(e => this._onProcessData(e)); this._xterm.onData(data => this._processManager.write(data)); + this._xterm.onBinary(data => this._processManager.processBinary(data)); this.processReady.then(async () => { if (this._linkManager) { this._linkManager.processCwd = await this._processManager.getInitialCwd(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index 9744d4ff0f5..6e4f9a1ec22 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -102,6 +102,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal } } + processBinary(data: string): void { + throw new Error('not implemented'); + } + public async start(): Promise { if (!this._shellLaunchConfig.isExtensionCustomPtyTerminal) { throw new Error('Attempt to start an ext host process that is not an extension terminal'); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 88890f6a3db..098a6c78f6a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -499,6 +499,10 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce } } + public processBinary(data: string): void { + this._process?.processBinary(data); + } + public getInitialCwd(): Promise { return Promise.resolve(this._initialCwd ? this._initialCwd : ''); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f172b2cde49..6e6c2f4ac92 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -189,6 +189,7 @@ export class TerminalService implements ITerminalService { private async _reconnectToRemoteTerminals(): Promise { // Reattach to all remote terminals const layoutInfo = await this._remoteTerminalService.getTerminalLayoutInfo(); + this._remoteTerminalService.reduceConnectionGraceTime(); const reconnectCounter = this._recreateTerminalTabs(layoutInfo); /* __GDPR__ "terminalReconnection" : { @@ -210,6 +211,7 @@ export class TerminalService implements ITerminalService { } // Reattach to all local terminals const layoutInfo = await this._localTerminalService.getTerminalLayoutInfo(); + this._localTerminalService.reduceConnectionGraceTime(); if (layoutInfo && layoutInfo.tabs.length > 0) { this._recreateTerminalTabs(layoutInfo); } diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index e055f798fb3..321518c4940 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -95,6 +95,9 @@ export class RemoteTerminalChannelClient { public get onProcessData(): Event<{ id: number, event: IProcessDataEvent | string }> { return this._channel.listen<{ id: number, event: IProcessDataEvent | string }>('$onProcessDataEvent'); } + public get onProcessBinary(): Event<{ id: number, event: string }> { + return this._channel.listen<{ id: number, event: string }>('$onProcessBinaryEvent'); + } public get onProcessExit(): Event<{ id: number, event: number | undefined }> { return this._channel.listen<{ id: number, event: number | undefined }>('$onProcessExitEvent'); } @@ -232,11 +235,12 @@ export class RemoteTerminalChannelClient { public attachToProcess(id: number): Promise { return this._channel.call('$attachToProcess', [id]); } - - public listProcesses(reduceGraceTime: boolean): Promise { - return this._channel.call('$listProcesses', [reduceGraceTime]); + public listProcesses(): Promise { + return this._channel.call('$listProcesses'); + } + public reduceConnectionGraceTime(): Promise { + return this._channel.call('$reduceConnectionGraceTime'); } - public start(id: number): Promise { return this._channel.call('$start', [id]); } @@ -261,7 +265,6 @@ export class RemoteTerminalChannelClient { public orphanQuestionReply(id: number): Promise { return this._channel.call('$orphanQuestionReply', [id]); } - public sendCommandResult(reqId: number, isError: boolean, payload: any): Promise { return this._channel.call('$sendCommandResult', [reqId, isError, payload]); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index f672eac3045..2cabd079017 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -306,6 +306,7 @@ export interface ITerminalProcessManager extends IDisposable { setDimensions(cols: number, rows: number, sync: false): Promise; setDimensions(cols: number, rows: number, sync: true): void; acknowledgeDataEvent(charCount: number): void; + processBinary(data: string): void; getInitialCwd(): Promise; getCwd(): Promise; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index 334b75367db..527496aa225 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -50,6 +50,12 @@ export class LocalPty extends Disposable implements ITerminalChildProcess { shutdown(immediate: boolean): void { this._localPtyService.shutdown(this.id, immediate); } + processBinary(data: string): void { + if (this._inReplay) { + return; + } + this._localPtyService.processBinary(this.id, data); + } input(data: string): void { if (this._inReplay) { return; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts index c892298e0c5..68ba3153571 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts @@ -116,8 +116,12 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe return undefined; } - public async listProcesses(reduceGraceTime: boolean): Promise { - return this._localPtyService.listProcesses(reduceGraceTime); + public async listProcesses(): Promise { + return this._localPtyService.listProcesses(); + } + + public reduceConnectionGraceTime(): void { + this._localPtyService.reduceConnectionGraceTime(); } public async setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise { @@ -136,6 +140,10 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe return result; } + public processBinary(id: number, data: string): void { + this._localPtyService.processBinary(id, data); + } + private _getWorkspaceId(): string { return this._workspaceContextService.getWorkspace().id; } diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index 5764a055c11..f2621627d62 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -32,6 +32,11 @@ export interface IWebviewService { */ readonly activeWebview: Webview | undefined; + /** + * Fired when the currently focused webview changes. + */ + readonly onDidChangeActiveWebview: Event; + /** * Create a basic webview dom element. */ diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 1269566449f..25e922e271d 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -3,13 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; import { IWebviewService, Webview, WebviewContentOptions, WebviewElement, WebviewExtensionDescription, WebviewOptions, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; -export class WebviewService implements IWebviewService { +export class WebviewService extends Disposable implements IWebviewService { declare readonly _serviceBrand: undefined; protected readonly _webviewThemeDataProvider: WebviewThemeDataProvider; @@ -17,12 +19,24 @@ export class WebviewService implements IWebviewService { constructor( @IInstantiationService protected readonly _instantiationService: IInstantiationService, ) { + super(); this._webviewThemeDataProvider = this._instantiationService.createInstance(WebviewThemeDataProvider); } private _activeWebview?: Webview; + public get activeWebview() { return this._activeWebview; } + private updateActiveWebview(value: Webview | undefined) { + if (value !== this._activeWebview) { + this._activeWebview = value; + this._onDidChangeActiveWebview.fire(value); + } + } + + private readonly _onDidChangeActiveWebview = this._register(new Emitter()); + public readonly onDidChangeActiveWebview = this._onDidChangeActiveWebview.event; + createWebviewElement( id: string, options: WebviewOptions, @@ -47,12 +61,12 @@ export class WebviewService implements IWebviewService { protected addWebviewListeners(webview: Webview) { webview.onDidFocus(() => { - this._activeWebview = webview; + this.updateActiveWebview(webview); }); const onBlur = () => { if (this._activeWebview === webview) { - this._activeWebview = undefined; + this.updateActiveWebview(undefined); } }; diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts index 8e776fc388b..1ff457bf6ee 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts @@ -7,11 +7,13 @@ import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { memoize } from 'vs/base/common/decorators'; import { isPromiseCanceledError } from 'vs/base/common/errors'; +import { Event, Emitter } from 'vs/base/common/event'; import { Iterable } from 'vs/base/common/iterator'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation } from 'vs/platform/editor/common/editor'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { GroupIdentifier } from 'vs/workbench/common/editor'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IWebviewService, WebviewContentOptions, WebviewExtensionDescription, WebviewOptions, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewIconManager, WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -69,6 +71,8 @@ export interface IWebviewWorkbenchService { resolveWebview( webview: WebviewInput, ): CancelablePromise; + + readonly onDidChangeActiveWebviewEditor: Event; } export interface WebviewResolver { @@ -171,12 +175,48 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc super(); this._iconManager = this._register(this._instantiationService.createInstance(WebviewIconManager)); + + this._register(_editorService.onDidActiveEditorChange(() => { + this.updateActiveWebview(); + })); + + // The user may have switched focus between two sides of a diff editor + this._register(_webviewService.onDidChangeActiveWebview(() => { + this.updateActiveWebview(); + })); + + this.updateActiveWebview(); } get iconManager() { return this._iconManager; } + private _activeWebview: WebviewInput | undefined; + + private readonly _onDidChangeActiveWebviewEditor = this._register(new Emitter()); + public readonly onDidChangeActiveWebviewEditor = this._onDidChangeActiveWebviewEditor.event; + + private updateActiveWebview() { + const activeInput = this._editorService.activeEditor; + + let newActiveWebview: WebviewInput | undefined; + if (activeInput instanceof WebviewInput) { + newActiveWebview = activeInput; + } else if (activeInput instanceof DiffEditorInput) { + if (activeInput.primary instanceof WebviewInput && activeInput.primary.webview === this._webviewService.activeWebview) { + newActiveWebview = activeInput.primary; + } else if (activeInput.secondary instanceof WebviewInput && activeInput.secondary.webview === this._webviewService.activeWebview) { + newActiveWebview = activeInput.secondary; + } + } + + if (newActiveWebview !== this._activeWebview) { + this._activeWebview = newActiveWebview; + this._onDidChangeActiveWebviewEditor.fire(newActiveWebview); + } + } + public createWebview( id: string, viewType: string, diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index b05f27ecb11..77c3629b13f 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -279,6 +279,7 @@ class SimpleWebviewService implements IWebviewService { declare readonly _serviceBrand: undefined; readonly activeWebview = undefined; + readonly onDidChangeActiveWebview = Event.None; createWebviewElement(id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined): WebviewElement { throw new Error('Method not implemented.'); } createWebviewOverlay(id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined): WebviewOverlay { throw new Error('Method not implemented.'); } diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index e54d141f447..f7769371de5 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -6,7 +6,7 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; export const FOLDER_CONFIG_FOLDER_NAME = '.vscode'; export const FOLDER_SETTINGS_NAME = 'settings'; @@ -45,7 +45,7 @@ export interface IConfigurationCache { } -export const IWorkbenchConfigurationService = createDecorator('configurationService'); +export const IWorkbenchConfigurationService = refineServiceDecorator(IConfigurationService); export interface IWorkbenchConfigurationService extends IConfigurationService { /** * A promise that resolves when the remote configuration is loaded in a remote window. diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index 1f77581456a..bc564af8e2e 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -31,6 +31,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR getExecPath: () => string | undefined }, envVariables: IProcessEnvironment, + envVariablesPromise: Promise, editorService: IEditorService, private readonly configurationService: IConfigurationService, private readonly commandService: ICommandService, @@ -101,7 +102,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR } return undefined; } - }, labelService, envVariables); + }, labelService, envVariables, envVariablesPromise); } public async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, target?: ConfigurationTarget): Promise { @@ -367,8 +368,10 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi @ICommandService commandService: ICommandService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @IQuickInputService quickInputService: IQuickInputService, - @ILabelService labelService: ILabelService + @ILabelService labelService: ILabelService, ) { - super({ getAppRoot: () => undefined, getExecPath: () => undefined }, Object.create(null), editorService, configurationService, commandService, workspaceContextService, quickInputService, labelService); + super({ getAppRoot: () => undefined, getExecPath: () => undefined }, Object.create(null), + Promise.resolve(Object.create(null)), editorService, configurationService, + commandService, workspaceContextService, quickInputService, labelService); } } diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 87fdc54c0c8..0af35a2f429 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -40,10 +40,10 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe private _envVariables?: IProcessEnvironment; protected _contributedVariables: Map Promise> = new Map(); - - constructor(_context: IVariableResolveContext, _labelService?: ILabelService, _envVariables?: IProcessEnvironment) { + constructor(_context: IVariableResolveContext, _labelService?: ILabelService, _envVariables?: IProcessEnvironment, _envVariablesPromise?: Promise) { this._context = _context; this._labelService = _labelService; + // TODO: delete _envVariables in favor of _envVariablesPromise https://github.com/microsoft/vscode/issues/108804 if (_envVariables) { if (isWindows) { // windows env variables are case insensitive @@ -65,6 +65,9 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.recursiveResolve(root ? root.uri : undefined, value); } + /** + * @deprecated Use the async version of `resolve` instead. + */ public resolve(root: IWorkspaceFolder | undefined, value: string): string; public resolve(root: IWorkspaceFolder | undefined, value: string[]): string[]; public resolve(root: IWorkspaceFolder | undefined, value: IStringDictionary): IStringDictionary; @@ -72,6 +75,9 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.recursiveResolve(root ? root.uri : undefined, value); } + /** + * @deprecated Use the async version of `resolve` instead. + */ public resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { const result = objects.deepClone(config) as any; diff --git a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts index 5ff57578034..d1e0231b9c6 100644 --- a/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts @@ -14,6 +14,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { env } from 'vs/base/common/process'; import { ILabelService } from 'vs/platform/label/common/label'; +import { IShellEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService'; export class ConfigurationResolverService extends BaseConfigurationResolverService { @@ -24,7 +25,8 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi @ICommandService commandService: ICommandService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @IQuickInputService quickInputService: IQuickInputService, - @ILabelService labelService: ILabelService + @ILabelService labelService: ILabelService, + @IShellEnvironmentService shellEnvironmentService: IShellEnvironmentService ) { super({ getAppRoot: (): string | undefined => { @@ -33,7 +35,7 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi getExecPath: (): string | undefined => { return environmentService.execPath; } - }, env, editorService, configurationService, commandService, workspaceContextService, quickInputService, labelService); + }, env, shellEnvironmentService.getShellEnv(), editorService, configurationService, commandService, workspaceContextService, quickInputService, labelService); } } diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 6c697e59aa4..9ee824edc66 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -75,7 +75,7 @@ suite('Configuration Resolver Service', () => { labelService = new MockLabelService(); containingWorkspace = testWorkspace(uri.parse('file:///VSCode/workspaceLocation')); workspace = containingWorkspace.folders[0]; - configurationResolverService = new TestConfigurationResolverService(nullContext, environmentService.userEnv, editorService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(containingWorkspace), quickInputService, labelService); + configurationResolverService = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), editorService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(containingWorkspace), quickInputService, labelService); }); teardown(() => { @@ -214,7 +214,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); }); @@ -225,7 +225,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.strictEqual(service.resolve(undefined, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); }); @@ -242,7 +242,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz'); }); @@ -259,7 +259,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for key1 xyz'); } else { @@ -280,7 +280,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2'); } else { @@ -314,7 +314,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz'); }); @@ -324,7 +324,7 @@ suite('Configuration Resolver Service', () => { editor: {} }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.strictEqual(service.resolve(workspace, 'abc ${unknownVariable} xyz'), 'abc ${unknownVariable} xyz'); assert.strictEqual(service.resolve(workspace, 'abc ${env:unknownVariable} xyz'), 'abc xyz'); }); @@ -337,7 +337,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); + let service = new TestConfigurationResolverService(nullContext, environmentService.userEnv, Promise.resolve(environmentService.userEnv), new TestEditorServiceWithActiveEditor(), configurationService, mockCommandService, new TestContextService(), quickInputService, labelService); assert.throws(() => service.resolve(workspace, 'abc ${env} xyz')); assert.throws(() => service.resolve(workspace, 'abc ${env:} xyz')); diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index d6191e89c6e..90c0b952fa8 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -25,7 +25,7 @@ import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecyc import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; -import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; +import { IWorkspaceTrustService, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust'; import { Promises } from 'vs/base/common/async'; const SOURCE = 'IWorkbenchExtensionEnablementService'; @@ -64,18 +64,13 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench this._register(this.globalExtensionEnablementService.onDidChangeEnablement(({ extensions, source }) => this.onDidChangeExtensions(extensions, source))); this._register(extensionManagementService.onDidInstallExtension(this._onDidInstallExtension, this)); this._register(extensionManagementService.onDidUninstallExtension(this._onDidUninstallExtension, this)); + this._register(this.workspaceTrustService.onDidChangeTrustState(this._onDidChangeTrustState, this)); // Trusted extensions notification // TODO: Confirm that this is the right lifecycle phase this.lifecycleService.when(LifecyclePhase.Eventually).then(() => { if (this.extensionsDisabledByTrustRequirement.length > 0) { - this.workspaceTrustService.requireWorkspaceTrust({ modal: false }) - .then(trustState => { - if (trustState === WorkspaceTrustState.Trusted) { - this._onEnablementChanged.fire(this.extensionsDisabledByTrustRequirement); - this.extensionsDisabledByTrustRequirement = []; - } - }); + this.workspaceTrustService.requestWorkspaceTrust({ modal: false }); } }); @@ -174,7 +169,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench const result = await Promises.settled(extensions.map(e => { if (this._isDisabledByTrustRequirement(e)) { - return this.workspaceTrustService.requireWorkspaceTrust() + return this.workspaceTrustService.requestWorkspaceTrust() .then(trustState => { if (trustState === WorkspaceTrustState.Trusted) { return this._setEnablement(e, newState); @@ -447,7 +442,8 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench private _onDidInstallExtension({ local, error }: DidInstallExtensionEvent): void { if (local && !error && this._isDisabledByTrustRequirement(local)) { - this.workspaceTrustService.requireWorkspaceTrust(); + this.workspaceTrustService.requestWorkspaceTrust({ modal: false }); + this._onEnablementChanged.fire([local]); } } @@ -457,6 +453,13 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } } + private _onDidChangeTrustState({ currentTrustState }: WorkspaceTrustStateChangeEvent): void { + if (currentTrustState === WorkspaceTrustState.Trusted && this.extensionsDisabledByTrustRequirement.length > 0) { + this._onEnablementChanged.fire(this.extensionsDisabledByTrustRequirement); + this.extensionsDisabledByTrustRequirement = []; + } + } + private _reset(extension: IExtensionIdentifier) { this._removeFromWorkspaceDisabledExtensions(extension); this._removeFromWorkspaceEnabledExtensions(extension); diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index 5cd77eb233d..e523f5b46a4 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtension, IScannedExtension, ExtensionType, ITranslatedScannedExtension, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { IExtensionManagementService, IGalleryExtension, IExtensionIdentifier, ILocalExtension, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; @@ -24,7 +24,7 @@ export interface IExtensionManagementServerService { getExtensionManagementServer(extension: IExtension): IExtensionManagementServer | null; } -export const IWorkbenchExtensionManagementService = createDecorator('extensionManagementService'); +export const IWorkbenchExtensionManagementService = refineServiceDecorator(IExtensionManagementService); export interface IWorkbenchExtensionManagementService extends IExtensionManagementService { readonly _serviceBrand: undefined; installExtensions(extensions: IGalleryExtension[], installOptions?: InstallOptions): Promise; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 91eea651c1c..2d989d36f3e 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -25,7 +25,7 @@ import Severity from 'vs/base/common/severity'; import { canceled } from 'vs/base/common/errors'; import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; import { Promises } from 'vs/base/common/async'; -import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; +import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; export class ExtensionManagementService extends Disposable implements IWorkbenchExtensionManagementService { @@ -362,9 +362,21 @@ export class ExtensionManagementService extends Disposable implements IWorkbench protected async checkForWorkspaceTrust(manifest: IExtensionManifest): Promise { if (getExtensionWorkspaceTrustRequirement(manifest) === 'onStart') { - const trustState = await this.workspaceTrustService.requireWorkspaceTrust(); - return trustState === WorkspaceTrustState.Trusted ? Promise.resolve() : Promise.reject(canceled()); + const trustState = await this.workspaceTrustService.requestWorkspaceTrust({ + modal: true, + message: localize('extensionInstallWorkspaceTrustMessage', "Enabling this extension requires a trusted workspace."), + buttons: [ + { label: localize('extensionInstallWorkspaceTrustButton', "Trust Workspace & Install"), type: 'ContinueWithTrust' }, + { label: localize('extensionInstallWorkspaceTrustContinueButton', "Install"), type: 'ContinueWithoutTrust' }, + { label: localize('extensionInstallWorkspaceTrustManageButton', "Learn More"), type: 'Manage' } + ] + }); + + if (!trustState) { + Promise.reject(canceled()); + } } + return Promise.resolve(); } } diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 8cee0b8399b..9c748ad3e0b 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -15,7 +15,6 @@ import { IWorkspaceTrustModel, WorkspaceTrustRequestOptions, IWorkspaceTrustRequ import { EditorModel } from 'vs/workbench/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { dirname, resolve } from 'vs/base/common/path'; -import { canceled } from 'vs/base/common/errors'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; @@ -220,11 +219,10 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust readonly onDidChangeTrustState = this._onDidChangeTrustState.event; private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown; - private _trustRequestPromise?: Promise; - private _inFlightResolver?: (trustState: WorkspaceTrustState) => void; - private _modalTrustRequestPromise?: Promise; - private _modalTrustRequestResolver?: (trustState: WorkspaceTrustState) => void; - private _modalTrustRequestRejecter?: (error: Error) => void; + private _trustRequestPromise?: Promise; + private _inFlightResolver?: (trustState?: WorkspaceTrustState) => void; + private _modalTrustRequestPromise?: Promise; + private _modalTrustRequestResolver?: (trustState?: WorkspaceTrustState) => void; private _workspace: IWorkspace; private readonly _ctxWorkspaceTrustState: IContextKey; @@ -393,7 +391,6 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust this._modalTrustRequestResolver(trustState === undefined ? this.currentTrustState : trustState); this._modalTrustRequestResolver = undefined; - this._modalTrustRequestRejecter = undefined; this._modalTrustRequestPromise = undefined; } if (this._inFlightResolver) { @@ -415,11 +412,10 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust } private onTrustRequestCancelled(): void { - if (this._modalTrustRequestRejecter) { - this._modalTrustRequestRejecter(canceled()); + if (this._modalTrustRequestResolver) { + this._modalTrustRequestResolver(undefined); this._modalTrustRequestResolver = undefined; - this._modalTrustRequestRejecter = undefined; this._modalTrustRequestPromise = undefined; } } @@ -436,7 +432,7 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust return this.configurationService.getValue(WORKSPACE_TRUST_ENABLED) ?? false; } - async requireWorkspaceTrust(options: WorkspaceTrustRequestOptions = { modal: true }): Promise { + async requestWorkspaceTrust(options: WorkspaceTrustRequestOptions = { modal: true }): Promise { // Trusted workspace if (this.currentTrustState === WorkspaceTrustState.Trusted) { return this.currentTrustState; @@ -450,21 +446,22 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust // Modal request if (!this._modalTrustRequestPromise) { // Create promise - this._modalTrustRequestPromise = new Promise((resolve, reject) => { + this._modalTrustRequestPromise = new Promise(resolve => { this._modalTrustRequestResolver = resolve; - this._modalTrustRequestRejecter = reject; }); } else { - // Return existing promises + // Return existing promise return this._modalTrustRequestPromise; } } else { // Soft request if (!this._trustRequestPromise) { + // Create promise this._trustRequestPromise = new Promise(resolve => { this._inFlightResolver = resolve; }); } else { + // Return existing promise return this._trustRequestPromise; } } diff --git a/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts b/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts index 2953fcb2328..9e713061352 100644 --- a/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts +++ b/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts @@ -22,7 +22,7 @@ export class TestWorkspaceTrustService implements IWorkspaceTrustService { return true; } - requireWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise { + requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise { return Promise.resolve(WorkspaceTrustState.Trusted); } } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 7dea1df11ce..63edbb2dc52 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1507,6 +1507,7 @@ export class TestTerminalInstanceService implements ITerminalInstanceService { } export class TestLocalTerminalService implements ILocalTerminalService { + declare readonly _serviceBrand: undefined; onPtyHostExit = Event.None; @@ -1518,9 +1519,11 @@ export class TestLocalTerminalService implements ILocalTerminalService { return new TestTerminalChildProcess(shouldPersist); } async attachToProcess(id: number): Promise { throw new Error('Method not implemented.'); } - async listProcesses(reduceGraceTime: boolean): Promise { throw new Error('Method not implemented.'); } + async listProcesses(): Promise { throw new Error('Method not implemented.'); } async setTerminalLayoutInfo(argsOrLayout?: ISetTerminalLayoutInfoArgs | ITerminalsLayoutInfoById) { throw new Error('Method not implemented.'); } async getTerminalLayoutInfo(): Promise { throw new Error('Method not implemented.'); } + reduceConnectionGraceTime(): void { throw new Error('Method not implemented.'); } + processBinary(id: number, data: string): void { throw new Error('Method not implemented.'); } } class TestTerminalChildProcess implements ITerminalChildProcess { @@ -1544,6 +1547,9 @@ class TestTerminalChildProcess implements ITerminalChildProcess { async getInitialCwd(): Promise { return ''; } async getCwd(): Promise { return ''; } async getLatency(): Promise { return 0; } + processBinary(data: string): void { + throw new Error('not implemented'); + } } export class TestQuickInputService implements IQuickInputService { diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 7d3a06dd857..735967e619f 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -16,7 +16,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IProductConfiguration } from 'vs/platform/product/common/productService'; +import { IProductConfiguration } from 'vs/base/common/product'; import { mark } from 'vs/base/common/performance'; import { ICredentialsProvider } from 'vs/workbench/services/credentials/common/credentials'; import { TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel'; diff --git a/test/unit/electron/index.js b/test/unit/electron/index.js index 4c9bcdc05e3..738a2165203 100644 --- a/test/unit/electron/index.js +++ b/test/unit/electron/index.js @@ -130,12 +130,15 @@ app.on('ready', () => { } }); + ipcMain.handle('vscode:test-vscode-window-config', async () => Object.create(null)); + const win = new BrowserWindow({ height: 600, width: 800, show: false, webPreferences: { preload: path.join(__dirname, '..', '..', '..', 'src', 'vs', 'base', 'parts', 'sandbox', 'electron-browser', 'preload.js'), // ensure similar environment as VSCode as tests may depend on this + additionalArguments: [`--vscode-window-config=vscode:test-vscode-window-config`], nodeIntegration: true, enableWebSQL: false, enableRemoteModule: false, diff --git a/yarn.lock b/yarn.lock index 6150dae52c5..ae2e8d4123a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -352,11 +352,6 @@ dependencies: defer-to-connect "^1.0.1" -"@tootallnate/once@1", "@tootallnate/once@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@ts-morph/common@~0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.9.0.tgz#a306355bad82cff22a1881f7f2f2c710bbb4d69d" @@ -894,12 +889,12 @@ agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== +agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: - debug "4" + es6-promisify "^5.0.0" aggregate-error@^3.0.0: version "3.1.0" @@ -2653,11 +2648,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== - debounce@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.1.0.tgz#6a1a4ee2a9dc4b7c24bb012558dbcdb05b37f408" @@ -2714,7 +2704,7 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -3773,11 +3763,6 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -file-uri-to-path@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" - integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -4101,14 +4086,6 @@ fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -ftp@^0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4171,18 +4148,6 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-uri@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" - integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== - dependencies: - "@tootallnate/once" "1" - data-uri-to-buffer "3" - debug "4" - file-uri-to-path "2" - fs-extra "^8.1.0" - ftp "^0.3.10" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -4887,15 +4852,6 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -8075,16 +8031,6 @@ read-pkg@^3.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - "readable-stream@2 || 3": version "3.1.1" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" @@ -8734,10 +8680,10 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== snapdragon-node@^2.0.1: version "2.1.1" @@ -8769,22 +8715,21 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== +socks-proxy-agent@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" + agent-base "~4.2.1" + socks "~2.3.2" -socks@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2" - integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw== +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== dependencies: ip "^1.1.5" - smart-buffer "^4.1.0" + smart-buffer "4.0.2" source-list-map@^2.0.0: version "2.0.1" @@ -10118,18 +10063,15 @@ vscode-oniguruma@1.3.1: resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f" integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ== -vscode-proxy-agent@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.9.0.tgz#da6501b0bb9a6c8cc2fe0e31756c91eb4d5d900b" - integrity sha512-DvLLaYNy8MBlm7O2CBUpmSpQCnNH88f95yXT1l9ovKO7GmTKkbbEJ6ZtzatUezqOlUuOFI0CwenhGGPYAlJ37A== +vscode-proxy-agent@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.8.2.tgz#5125e7f1efedd84e0114abe9f38cef3f7b33eb50" + integrity sha512-pRNhgAqrgMB4k1rZTHthCLVH+CtJ3TFlKKhFlt4IMxDRZnMEAbPiAGthvEt/Ku6qS4Vuca8b2PqT+rJlbmnznQ== dependencies: - "@tootallnate/once" "^1.1.2" - agent-base "^6.0.2" - debug "^4.3.1" - get-uri "^3.0.2" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - socks-proxy-agent "^5.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + socks-proxy-agent "^4.0.1" vscode-regexpp@^3.1.0: version "3.1.0" @@ -10481,11 +10423,6 @@ xmldom@0.1.x: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= - "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"