diff --git a/.github/workflows/pr-chat.yml b/.github/workflows/pr-chat.yml index 0c8d6bab793..13803fda778 100644 --- a/.github/workflows/pr-chat.yml +++ b/.github/workflows/pr-chat.yml @@ -6,6 +6,7 @@ on: jobs: main: runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} steps: - name: Checkout Actions uses: actions/checkout@v2 diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index 221e5ba7516..2671a5a3a6c 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -97,7 +97,7 @@ function writeControlFile(control) { fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2)); } function getBuiltInExtensions() { - log('Syncronizing built-in extensions...'); + log('Synchronizing built-in extensions...'); log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`); const control = readControlFile(); const streams = []; diff --git a/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts index f5a03d1304e..1abc85b3b09 100644 --- a/build/lib/builtInExtensions.ts +++ b/build/lib/builtInExtensions.ts @@ -136,7 +136,7 @@ function writeControlFile(control: IControlFile): void { } export function getBuiltInExtensions(): Promise { - log('Syncronizing built-in extensions...'); + log('Synchronizing built-in extensions...'); log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`); const control = readControlFile(); diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 06bfbb2b506..7c99da42ae7 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -119,7 +119,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/localizations", + "name": "vs/workbench/contrib/localization", "project": "vscode-workbench" }, { diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index a3199cffc3a..6852639fcda 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -416,6 +416,7 @@ export class CommandCenter { if (!url) { /* __GDPR__ "clone" : { + "owner": "lszomoru", "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -441,6 +442,7 @@ export class CommandCenter { if (!uris || uris.length === 0) { /* __GDPR__ "clone" : { + "owner": "lszomoru", "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -499,6 +501,7 @@ export class CommandCenter { /* __GDPR__ "clone" : { + "owner": "lszomoru", "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } } @@ -518,6 +521,7 @@ export class CommandCenter { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { /* __GDPR__ "clone" : { + "owner": "lszomoru", "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -527,6 +531,7 @@ export class CommandCenter { } else { /* __GDPR__ "clone" : { + "owner": "lszomoru", "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -2920,6 +2925,7 @@ export class CommandCenter { /* __GDPR__ "git.command" : { + "owner": "lszomoru", "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 0327aae4868..ee60d2cb1b1 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -192,7 +192,9 @@ export async function _activate(context: ExtensionContext): Promise 0) { diff --git a/extensions/html-language-features/server/src/modes/javascriptLibs.ts b/extensions/html-language-features/server/src/modes/javascriptLibs.ts index bdca89be362..7abf94edf22 100644 --- a/extensions/html-language-features/server/src/modes/javascriptLibs.ts +++ b/extensions/html-language-features/server/src/modes/javascriptLibs.ts @@ -24,7 +24,7 @@ export function loadLibrary(name: string) { try { content = readFileSync(libPath).toString(); } catch (e) { - console.log(`Unable to load library ${name} at ${libPath}: ${e.message}`); + console.log(`Unable to load library ${name} at ${libPath}`); content = ''; } contents[name] = content; diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index 7f9e3f1d85a..a119a9248ae 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -19,7 +19,7 @@ import { getSemanticTokens, getSemanticTokenLegend } from './javascriptSemanticT const JS_WORD_REGEX = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g; function getLanguageServiceHost(scriptKind: ts.ScriptKind) { - const compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false }; + const compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es2020.full.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false }; let currentTextDocument = TextDocument.create('init', 'javascript', 1, ''); const jsLanguageService = import(/* webpackChunkName: "javascriptLibs" */ './javascriptLibs').then(libs => { @@ -52,7 +52,7 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) { }; }, getCurrentDirectory: () => '', - getDefaultLibFileName: (_options: ts.CompilerOptions) => 'es6', + getDefaultLibFileName: (_options: ts.CompilerOptions) => 'es2020.full', readFile: (path: string, _encoding?: string | undefined): string | undefined => { if (path === currentTextDocument.uri) { return currentTextDocument.getText(); @@ -66,6 +66,15 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) { } else { return !!libs.loadLibrary(path); } + }, + directoryExists: (path: string): boolean => { + // typescript tries to first find libraries in node_modules/@types and node_modules/@typescript + // there's no node_modules in our setup + if (path.startsWith('node_modules')) { + return false; + } + return true; + } }; return ts.createLanguageService(host); diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 4ef07a0dd65..f2ad883243f 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -16,7 +16,8 @@ "Programming Languages" ], "enabledApiProposals": [ - "textEditorDrop" + "textEditorDrop", + "documentPaste" ], "activationEvents": [ "onLanguage:markdown", @@ -414,6 +415,12 @@ "markdownDescription": "%configuration.markdown.editor.drop.enabled%", "scope": "resource" }, + "markdown.experimental.editor.pasteLinks.enabled": { + "type": "boolean", + "default": false, + "markdownDescription": "%configuration.markdown.editor.pasteLinks.enabled%", + "scope": "resource" + }, "markdown.experimental.validate.enabled": { "type": "boolean", "scope": "resource", diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 2c8977cf2e0..1f3598e3fd8 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -28,7 +28,8 @@ "configuration.markdown.links.openLocation.currentGroup": "Open links in the active editor group.", "configuration.markdown.links.openLocation.beside": "Open links beside the active editor.", "configuration.markdown.suggest.paths.enabled.description": "Enable/disable path suggestions for markdown links", - "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbench.experimental.editor.dropIntoEditor.enabled#`.", + "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbenck.experimental.editor.dropIntoEditor.enabled#`.", + "configuration.markdown.editor.pasteLinks.enabled": "Enable/disable pasting files into a Markdown editor inserts Markdown links.", "configuration.markdown.experimental.validate.enabled.description": "Enable/disable all error reporting in Markdown files.", "configuration.markdown.experimental.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.", "configuration.markdown.experimental.validate.headerLinks.enabled.description": "Validate links to headers in Markdown files, e.g. `[link](#header)`. Requires enabling `#markdown.experimental.validate.enabled#`.", diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index f088f91391a..0f2399692e9 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -6,8 +6,9 @@ import * as vscode from 'vscode'; import { CommandManager } from './commandManager'; import * as commands from './commands/index'; -import { register as registerDiagnostics } from './languageFeatures/diagnostics'; +import { registerPasteProvider } from './languageFeatures/copyPaste'; import { MdDefinitionProvider } from './languageFeatures/definitionProvider'; +import { register as registerDiagnostics } from './languageFeatures/diagnostics'; import { MdLinkProvider } from './languageFeatures/documentLinkProvider'; import { MdDocumentSymbolProvider } from './languageFeatures/documentSymbolProvider'; import { registerDropIntoEditor } from './languageFeatures/dropIntoEditor'; @@ -78,6 +79,7 @@ function registerMarkdownLanguageFeatures( MdPathCompletionProvider.register(selector, engine, linkProvider), registerDiagnostics(selector, engine, workspaceContents, linkProvider, commandManager), registerDropIntoEditor(selector), + registerPasteProvider(selector), registerFindFileReferences(commandManager, referencesProvider), ); } diff --git a/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts b/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts new file mode 100644 index 00000000000..d9e939b463c --- /dev/null +++ b/extensions/markdown-language-features/src/languageFeatures/copyPaste.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { tryInsertUriList } from './dropIntoEditor'; + +export function registerPasteProvider(selector: vscode.DocumentSelector) { + return vscode.languages.registerDocumentPasteEditProvider(selector, new class implements vscode.DocumentPasteEditProvider { + + async provideDocumentPasteEdits( + document: vscode.TextDocument, + range: vscode.Range, + dataTransfer: vscode.DataTransfer, + token: vscode.CancellationToken, + ): Promise { + const enabled = vscode.workspace.getConfiguration('markdown', document).get('experimental.editor.pasteLinks.enabled', false); + if (!enabled) { + return; + } + + return tryInsertUriList(document, range, dataTransfer, token); + } + }); +} diff --git a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts index d5d7c4d9d29..2ad71ec0516 100644 --- a/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts +++ b/extensions/markdown-language-features/src/languageFeatures/dropIntoEditor.ts @@ -32,45 +32,45 @@ export function registerDropIntoEditor(selector: vscode.DocumentSelector) { } const replacementRange = new vscode.Range(position, position); - return this.tryInsertUriList(document, replacementRange, dataTransfer, token); - } - - private async tryInsertUriList(document: vscode.TextDocument, replacementRange: vscode.Range, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise { - const urlList = await dataTransfer.get('text/uri-list')?.asString(); - if (!urlList || token.isCancellationRequested) { - return undefined; - } - - const uris: vscode.Uri[] = []; - for (const resource of urlList.split('\n')) { - try { - uris.push(vscode.Uri.parse(resource)); - } catch { - // noop - } - } - - if (!uris.length) { - return; - } - - const snippet = new vscode.SnippetString(); - uris.forEach((uri, i) => { - const mdPath = document.uri.scheme === uri.scheme - ? encodeURI(path.relative(URI.Utils.dirname(document.uri).fsPath, uri.fsPath).replace(/\\/g, '/')) - : uri.toString(false); - - const ext = URI.Utils.extname(uri).toLowerCase(); - snippet.appendText(imageFileExtensions.has(ext) ? '![' : '['); - snippet.appendTabstop(); - snippet.appendText(`](${mdPath})`); - - if (i <= uris.length - 1 && uris.length > 1) { - snippet.appendText(' '); - } - }); - - return new vscode.SnippetTextEdit(replacementRange, snippet); + return tryInsertUriList(document, replacementRange, dataTransfer, token); } }); } + +export async function tryInsertUriList(document: vscode.TextDocument, replacementRange: vscode.Range, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise { + const urlList = await dataTransfer.get('text/uri-list')?.asString(); + if (!urlList || token.isCancellationRequested) { + return undefined; + } + + const uris: vscode.Uri[] = []; + for (const resource of urlList.split('\n')) { + try { + uris.push(vscode.Uri.parse(resource)); + } catch { + // noop + } + } + + if (!uris.length) { + return; + } + + const snippet = new vscode.SnippetString(); + uris.forEach((uri, i) => { + const mdPath = document.uri.scheme === uri.scheme + ? encodeURI(path.relative(URI.Utils.dirname(document.uri).fsPath, uri.fsPath).replace(/\\/g, '/')) + : uri.toString(false); + + const ext = URI.Utils.extname(uri).toLowerCase(); + snippet.appendText(imageFileExtensions.has(ext) ? '![' : '['); + snippet.appendTabstop(); + snippet.appendText(`](${mdPath})`); + + if (i <= uris.length - 1 && uris.length > 1) { + snippet.appendText(' '); + } + }); + + return new vscode.SnippetTextEdit(replacementRange, snippet); +} diff --git a/extensions/markdown-language-features/tsconfig.json b/extensions/markdown-language-features/tsconfig.json index 775eaa7c0a8..7c1d4a7fca8 100644 --- a/extensions/markdown-language-features/tsconfig.json +++ b/extensions/markdown-language-features/tsconfig.json @@ -7,6 +7,7 @@ "src/**/*", "../../src/vscode-dts/vscode.d.ts", "../../src/vscode-dts/vscode.proposed.textEditorDrop.d.ts", - "../../src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts" + "../../src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts", + "../../src/vscode-dts/vscode.proposed.documentPaste.d.ts" ] } diff --git a/extensions/package.json b/extensions/package.json index b6d00d2faaf..3d89442d04f 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "4.7.1-rc" + "typescript": "4.7" }, "scripts": { "postinstall": "node ./postinstall.mjs" diff --git a/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts index 46a32ec68f6..a7b1e6c061c 100644 --- a/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -554,6 +554,7 @@ class CompletionAcceptedCommand implements Command { if (item instanceof MyCompletionItem) { /* __GDPR__ "completions.accept" : { + "owner": "mjbvz", "isPackageJsonImport" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "isImportStatementCompletion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "${include}": [ @@ -820,6 +821,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< ) { /* __GDPR__ "completions.execute" : { + "owner": "mjbvz", "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, diff --git a/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts b/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts index 1cf85deb467..cd1aeffa823 100644 --- a/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts +++ b/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts @@ -32,6 +32,7 @@ class OrganizeImportsCommand implements Command { public async execute(file: string, sortOnly = false): Promise { /* __GDPR__ "organizeImports.execute" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}" ] diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 977bc20dc61..9ea0780a446 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -37,6 +37,7 @@ class ApplyCodeActionCommand implements Command { ): Promise { /* __GDPR__ "quickFix.execute" : { + "owner": "mjbvz", "fixName" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "${include}": [ "${TypeScriptCommonProperties}" @@ -67,6 +68,7 @@ class ApplyFixAllCodeAction implements Command { public async execute(args: ApplyFixAllCodeAction_args): Promise { /* __GDPR__ "quickFixAll.execute" : { + "owner": "mjbvz", "fixName" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "${include}": [ "${TypeScriptCommonProperties}" diff --git a/extensions/typescript-language-features/src/languageFeatures/refactor.ts b/extensions/typescript-language-features/src/languageFeatures/refactor.ts index 392cc5a3e18..d5d1723533c 100644 --- a/extensions/typescript-language-features/src/languageFeatures/refactor.ts +++ b/extensions/typescript-language-features/src/languageFeatures/refactor.ts @@ -36,6 +36,7 @@ class DidApplyRefactoringCommand implements Command { public async execute(args: DidApplyRefactoringCommand_Args): Promise { /* __GDPR__ "refactor.execute" : { + "owner": "mjbvz", "action" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "${include}": [ "${TypeScriptCommonProperties}" diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index 12e6f70d91b..a035fbc9fdb 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -230,6 +230,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe if (!executeInfo.token || !executeInfo.token.isCancellationRequested) { /* __GDPR__ "languageServiceErrorResponse" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}", "${TypeScriptRequestErrorProperties}" diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 306dd8570eb..0fdecc5c952 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -388,6 +388,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType /* __GDPR__ "tsserver.spawned" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}" ], @@ -418,6 +419,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType /* __GDPR__ "tsserver.error" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}" ] @@ -443,6 +445,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.error(`TSServer exited with code: ${code}. Signal: ${signal}`); /* __GDPR__ "tsserver.exitWithCode" : { + "owner": "mjbvz", "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "${include}": [ @@ -601,6 +604,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType /* __GDPR__ "serviceExited" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}" ] @@ -846,6 +850,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType private fatalError(command: string, error: unknown): void { /* __GDPR__ "fatalError" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}", "${TypeScriptRequestErrorProperties}" @@ -977,6 +982,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType /* __GDPR__ "typingsInstalled" : { + "owner": "mjbvz", "installedPackages" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "installSuccess": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "typingsInstallerVersion": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, diff --git a/extensions/typescript-language-features/src/utils/largeProjectStatus.ts b/extensions/typescript-language-features/src/utils/largeProjectStatus.ts index 346f95c6979..f6bdbf3721c 100644 --- a/extensions/typescript-language-features/src/utils/largeProjectStatus.ts +++ b/extensions/typescript-language-features/src/utils/largeProjectStatus.ts @@ -49,6 +49,7 @@ class ExcludeHintItem { this._item.show(); /* __GDPR__ "js.hintProjectExcludes" : { + "owner": "mjbvz", "${include}": [ "${TypeScriptCommonProperties}" ] diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 1c746b8d2d0..4ab30e237c6 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -42,10 +42,10 @@ node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== -typescript@4.7.1-rc: - version "4.7.1-rc" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.1-rc.tgz#23a0517d36c56de887b4457f29e2d265647bbd7c" - integrity sha512-EQd2NVelDe6ZVc2sO1CSpuSs+RHzY8c2n/kTNQAHw4um/eAXY+ZY4IKoUpNK0wO6C5hN+XcUXR7yqT8VbwwNIQ== +typescript@4.7: + version "4.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4" + integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A== vscode-grammar-updater@^1.1.0: version "1.1.0" diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index 06a95927644..c035cb6f262 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -37,6 +37,11 @@ if (process.env['VSCODE_PARENT_PID']) { terminateWhenParentTerminates(); } +// Listen for message ports +if (process.env['VSCODE_WILL_SEND_MESSAGE_PORT']) { + listenForMessagePort(); +} + // Load AMD entry point require('./bootstrap-amd').load(process.env['VSCODE_AMD_ENTRYPOINT']); @@ -264,4 +269,17 @@ function terminateWhenParentTerminates() { } } +function listenForMessagePort() { + // We need to listen for the 'port' event as soon as possible, + // otherwise we might miss the event. But we should also be + // prepared in case the event arrives late. + process.on('port', (e) => { + if (global.vscodePortsCallback) { + global.vscodePortsCallback(e.ports); + } else { + global.vscodePorts = e.ports; + } + }); +} + //#endregion diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index 2fe5d37c03f..f9729a18770 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -14,6 +14,7 @@ export interface ITelemetryData { } export type WorkbenchActionExecutedClassification = { + owner: 'bpasero'; id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; from: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/base/common/dataTransfer.ts b/src/vs/base/common/dataTransfer.ts index 1f56e79f751..d5d99bd283b 100644 --- a/src/vs/base/common/dataTransfer.ts +++ b/src/vs/base/common/dataTransfer.ts @@ -37,6 +37,10 @@ export class VSDataTransfer { this._data.set(mimeType, value); } + public delete(mimeType: string) { + this._data.delete(mimeType); + } + public setString(mimeType: string, stringOrPromise: string | Promise) { this.set(mimeType, { asString: async () => stringOrPromise, diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts b/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts index 6c9bfa8125a..68085dcefcc 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; +import { LanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; export class LocalizationsUpdater extends Disposable { constructor( - @ILocalizationsService private readonly localizationsService: LocalizationsService + @ILanguagePackService private readonly localizationsService: LanguagePackService ) { super(); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 243729c4e37..fb6cac109a9 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -46,8 +46,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { MessagePortMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; +import { LanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; import { ConsoleLogger, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; import { FollowerLogService, LoggerChannelClient, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; @@ -311,7 +311,7 @@ class SharedProcessMain extends Disposable { services.set(IExtensionTipsService, new SyncDescriptor(ExtensionTipsService)); // Localizations - services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + services.set(ILanguagePackService, new SyncDescriptor(LanguagePackService)); // Diagnostics services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); @@ -360,9 +360,9 @@ class SharedProcessMain extends Disposable { const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null); this.server.registerChannel('extensions', channel); - // Localizations - const localizationsChannel = ProxyChannel.fromService(accessor.get(ILocalizationsService)); - this.server.registerChannel('localizations', localizationsChannel); + // Language Packs + const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService)); + this.server.registerChannel('languagePacks', languagePacksChannel); // Diagnostics const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService)); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 2d7e71bef34..eb752810e1c 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -1105,7 +1105,7 @@ export class CodeApplication extends Disposable { code: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'The type of shared process crash to understand the nature of the crash better.' }; visible: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Whether shared process window was visible or not.' }; shuttingdown: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true; comment: 'Whether the application is shutting down when the crash happens.' }; - owner: 'bpaser'; + owner: 'bpasero'; comment: 'Event which fires whenever an error occurs in the shared process'; }; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 6c197b17661..88f9dc88a7a 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -36,8 +36,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; +import { LanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; import { ConsoleLogger, getLogLevel, ILogger, ILogService, LogLevel, MultiplexLogService } from 'vs/platform/log/common/log'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; import { FilePolicyService } from 'vs/platform/policy/common/filePolicyService'; @@ -161,7 +161,7 @@ class CliMain extends Disposable { services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); // Localizations - services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + services.set(ILanguagePackService, new SyncDescriptor(LanguagePackService)); // Telemetry const appenders: AppInsightsAppender[] = []; diff --git a/src/vs/editor/browser/dnd.ts b/src/vs/editor/browser/dnd.ts new file mode 100644 index 00000000000..08a3f558786 --- /dev/null +++ b/src/vs/editor/browser/dnd.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { VSDataTransfer } from 'vs/base/common/dataTransfer'; +import { URI } from 'vs/base/common/uri'; + + +export function toVSDataTransfer(dataTransfer: DataTransfer) { + const vsDataTransfer = new VSDataTransfer(); + for (const item of dataTransfer.items) { + const type = item.type; + if (item.kind === 'string') { + const asStringValue = new Promise(resolve => item.getAsString(resolve)); + vsDataTransfer.setString(type, asStringValue); + } else if (item.kind === 'file') { + const file = item.getAsFile() as null | (File & { path?: string }); + if (file) { + const uri = file.path ? URI.parse(file.path) : undefined; + vsDataTransfer.setFile(type, file.name, uri, async () => { + return new Uint8Array(await file.arrayBuffer()); + }); + } + } + } + return vsDataTransfer; +} diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 50766a815c2..93b20f1d2ed 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -338,6 +338,7 @@ export abstract class EditorAction extends EditorCommand { protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { type EditorActionInvokedClassification = { + owner: 'alexdima'; name: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index 647dc1fa131..6ad570fcd54 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -721,6 +721,15 @@ export interface CodeActionProvider { _getAdditionalMenuItems?(context: CodeActionContext, actions: readonly CodeAction[]): Command[]; } +/** + * @internal + */ +export interface DocumentPasteEditProvider { + prepareDocumentPaste?(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise; + + provideDocumentPasteEdits(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise; +} + /** * Represents a parameter of a callable-signature. A parameter can * have a label and a doc-comment. diff --git a/src/vs/editor/common/services/languageFeatures.ts b/src/vs/editor/common/services/languageFeatures.ts index e0ba2416582..2c80887df1a 100644 --- a/src/vs/editor/common/services/languageFeatures.ts +++ b/src/vs/editor/common/services/languageFeatures.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { LanguageFeatureRegistry, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry'; -import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; +import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentPasteEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const ILanguageFeaturesService = createDecorator('ILanguageFeaturesService'); @@ -25,6 +25,8 @@ export interface ILanguageFeaturesService { readonly codeActionProvider: LanguageFeatureRegistry; + readonly documentPasteEditProvider: LanguageFeatureRegistry; + readonly renameProvider: LanguageFeatureRegistry; readonly documentFormattingEditProvider: LanguageFeatureRegistry; diff --git a/src/vs/editor/common/services/languageFeaturesService.ts b/src/vs/editor/common/services/languageFeaturesService.ts index 2ed7cebcf62..4059a90b370 100644 --- a/src/vs/editor/common/services/languageFeaturesService.ts +++ b/src/vs/editor/common/services/languageFeaturesService.ts @@ -5,7 +5,7 @@ import { URI } from 'vs/base/common/uri'; import { LanguageFeatureRegistry, NotebookInfo, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry'; -import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; +import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DocumentPasteEditProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentOnDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from 'vs/editor/common/languages'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -41,6 +41,7 @@ export class LanguageFeaturesService implements ILanguageFeaturesService { readonly documentRangeSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this)); readonly documentSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this)); readonly documentOnDropEditProvider = new LanguageFeatureRegistry(this._score.bind(this)); + readonly documentPasteEditProvider = new LanguageFeatureRegistry(this._score.bind(this)); private _notebookTypeResolver?: NotebookInfoResolver; diff --git a/src/vs/editor/contrib/copyPaste/browser/copyPasteContribution.ts b/src/vs/editor/contrib/copyPaste/browser/copyPasteContribution.ts new file mode 100644 index 00000000000..55c120d060f --- /dev/null +++ b/src/vs/editor/contrib/copyPaste/browser/copyPasteContribution.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/editorConfigurationSchema'; +import { CopyPasteController } from 'vs/editor/contrib/copyPaste/browser/copyPasteController'; +import * as nls from 'vs/nls'; +import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; + +registerEditorContribution(CopyPasteController.ID, CopyPasteController); + +Registry.as(Extensions.Configuration).registerConfiguration({ + ...editorConfigurationBaseNode, + properties: { + 'editor.experimental.pasteActions.enabled': { + type: 'boolean', + scope: ConfigurationScope.LANGUAGE_OVERRIDABLE, + description: nls.localize('pasteActions', "Enable/disable running edits from extensions on paste."), + default: false, + }, + } +}); diff --git a/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts new file mode 100644 index 00000000000..6c203af56cd --- /dev/null +++ b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts @@ -0,0 +1,195 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { addDisposableListener } from 'vs/base/browser/dom'; +import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { VSDataTransfer } from 'vs/base/common/dataTransfer'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Mimes } from 'vs/base/common/mime'; +import { generateUuid } from 'vs/base/common/uuid'; +import { toVSDataTransfer } from 'vs/editor/browser/dnd'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IBulkEditService, ResourceEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; +import { Selection } from 'vs/editor/common/core/selection'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { DocumentPasteEditProvider, SnippetTextEdit, WorkspaceEdit } from 'vs/editor/common/languages'; +import { ITextModel } from 'vs/editor/common/model'; +import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState'; +import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +const vscodeClipboardMime = 'application/vnd.code.copyId'; + +class DefaultPasteEditProvider implements DocumentPasteEditProvider { + + async provideDocumentPasteEdits(model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise { + const textDataTransfer = dataTransfer.get(Mimes.text) ?? dataTransfer.get('text'); + if (textDataTransfer) { + const text = await textDataTransfer.asString(); + return { + edits: [new ResourceTextEdit(model.uri, { range: selection, text })] + }; + } + + return undefined; + } +} + +export class CopyPasteController extends Disposable implements IEditorContribution { + + public static readonly ID = 'editor.contrib.copyPasteActionController'; + + public static get(editor: ICodeEditor): CopyPasteController { + return editor.getContribution(CopyPasteController.ID)!; + } + + private readonly _editor: ICodeEditor; + + private _currentClipboardItem: undefined | { + readonly handle: string; + readonly dataTransferPromise: CancelablePromise; + }; + + constructor( + editor: ICodeEditor, + @IBulkEditService private readonly _bulkEditService: IBulkEditService, + @IClipboardService private readonly _clipboardService: IClipboardService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService, + ) { + super(); + + this._editor = editor; + + this._languageFeaturesService.documentPasteEditProvider.register('*', new DefaultPasteEditProvider()); + + const container = editor.getContainerDomNode(); + + this._register(addDisposableListener(container, 'copy', (e: ClipboardEvent) => { + if (!e.clipboardData) { + return; + } + + const model = editor.getModel(); + const selection = this._editor.getSelection(); + if (!model || !selection) { + return; + } + + if (!this.arePasteActionsEnabled(model)) { + return; + } + + const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model).filter(x => !!x.prepareDocumentPaste); + if (!providers.length) { + return; + } + + const dataTransfer = toVSDataTransfer(e.clipboardData); + + // Save off a handle pointing to data that VS Code maintains. + const handle = generateUuid(); + e.clipboardData.setData(vscodeClipboardMime, handle); + + const promise = createCancelablePromise(async token => { + const results = await Promise.all(providers.map(provider => { + return provider.prepareDocumentPaste!(model, selection, dataTransfer, token); + })); + + for (const result of results) { + result?.forEach((value, key) => { + dataTransfer.set(key, value); + }); + } + + return dataTransfer; + }); + + this._currentClipboardItem?.dataTransferPromise.cancel(); + this._currentClipboardItem = { handle: handle, dataTransferPromise: promise }; + })); + + this._register(addDisposableListener(container, 'paste', async (e: ClipboardEvent) => { + const selection = this._editor.getSelection(); + if (!e.clipboardData || !selection || !editor.hasModel()) { + return; + } + + const model = editor.getModel(); + if (!this.arePasteActionsEnabled(model)) { + return; + } + + const originalDocVersion = model.getVersionId(); + + const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model); + if (!providers.length) { + return; + } + + const handle = e.clipboardData?.getData(vscodeClipboardMime); + if (typeof handle !== 'string') { + return; + } + + e.preventDefault(); + e.stopImmediatePropagation(); + + const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection); + + try { + const dataTransfer = toVSDataTransfer(e.clipboardData); + + if (handle && this._currentClipboardItem?.handle === handle) { + const toMergeDataTransfer = await this._currentClipboardItem.dataTransferPromise; + toMergeDataTransfer.forEach((value, key) => { + dataTransfer.set(key, value); + }); + } + + if (!dataTransfer.has(Mimes.uriList)) { + const resources = await this._clipboardService.readResources(); + if (resources.length) { + const value = resources.join('\n'); + dataTransfer.set(Mimes.uriList, { + value, + asString: async () => value, + asFile: () => undefined, + }); + } + } + + dataTransfer.delete(vscodeClipboardMime); + + for (const provider of providers) { + const edit = await provider.provideDocumentPasteEdits(model, selection, dataTransfer, tokenSource.token); + if (originalDocVersion !== model.getVersionId()) { + return; + } + + if (edit) { + if ((edit as WorkspaceEdit).edits) { + await this._bulkEditService.apply(ResourceEdit.convert(edit as WorkspaceEdit), { editor }); + } else { + performSnippetEdit(editor, edit as SnippetTextEdit); + } + return; + } + } + } finally { + tokenSource.dispose(); + } + }, true)); + } + + public arePasteActionsEnabled(model: ITextModel): boolean { + return this._configurationService.getValue('editor.experimental.pasteActions.enabled', { + resource: model.uri + }); + } +} diff --git a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts index edbc29db56e..b713b71a7dd 100644 --- a/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts +++ b/src/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution.ts @@ -121,10 +121,8 @@ export class DropIntoEditorController extends Disposable implements IEditorContr .map(input => input.resource!.toString()); if (editorData.length) { - const added = new VSDataTransfer(); const str = distinct(editorData).join('\n'); - added.setString(Mimes.uriList.toLowerCase(), str); - return added; + textEditorDataTransfer.setString(Mimes.uriList.toLowerCase(), str); } } @@ -188,3 +186,4 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider { registerEditorContribution(DropIntoEditorController.ID, DropIntoEditorController); + diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 6c66d2a31ea..56a882e650c 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -451,11 +451,11 @@ export class SuggestController implements IEditorContribution { type AcceptedSuggestionClassification = { owner: 'jrieken'; comment: 'Information accepting completion items'; - providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comments: 'Provider of the completions item' }; - basenameHash: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comments: 'Hash of the basename of the file into which the completion was inserted' }; - fileExtension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comments: 'File extension of the file into which the completion was inserted' }; - languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comments: 'Language type of the file into which the completion was inserted' }; - kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comments: 'The completion item kind' }; + providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Provider of the completions item' }; + basenameHash: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Hash of the basename of the file into which the completion was inserted' }; + fileExtension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'File extension of the file into which the completion was inserted' }; + languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Language type of the file into which the completion was inserted' }; + kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The completion item kind' }; }; // _debugDisplayName looks like `vscode.css-language-features(/-:)`, where the last bit is the trigger chars // normalize it to just the extension ID and lowercase diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index aba1e89aa1d..1168ef7bb16 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -15,6 +15,7 @@ import 'vs/editor/contrib/clipboard/browser/clipboard'; import 'vs/editor/contrib/codeAction/browser/codeActionContributions'; import 'vs/editor/contrib/codelens/browser/codelensController'; import 'vs/editor/contrib/colorPicker/browser/colorContributions'; +import 'vs/editor/contrib/copyPaste/browser/copyPasteContribution'; import 'vs/editor/contrib/comment/browser/comment'; import 'vs/editor/contrib/contextmenu/browser/contextmenu'; import 'vs/editor/contrib/cursorUndo/browser/cursorUndo'; diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts index 19dd0e65b2a..7a7a3ec76ba 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -536,8 +536,10 @@ export class DiagnosticsService implements IDiagnosticsService { try { const stats = await collectWorkspaceStats(folder, ['node_modules', '.git']); type WorkspaceStatsClassification = { - 'workspace.id': { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; - rendererSessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + owner: 'lramos15'; + comment: 'Metadata related to the workspace'; + 'workspace.id': { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A UUID given to a workspace to identify it.' }; + rendererSessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The ID of the session' }; }; type WorkspaceStatsEvent = { 'workspace.id': string | undefined; @@ -548,9 +550,11 @@ export class DiagnosticsService implements IDiagnosticsService { rendererSessionId: workspace.rendererSessionId }); type WorkspaceStatsFileClassification = { - rendererSessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; - type: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; - count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; + owner: 'lramos15'; + comment: 'Helps us gain insights into what type of files are being used in a workspace'; + rendererSessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The ID of the session.' }; + type: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The type of file' }; + count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'How many types of that file are present' }; }; type WorkspaceStatsFileEvent = { rendererSessionId: string; diff --git a/src/vs/platform/driver/browser/driver.ts b/src/vs/platform/driver/browser/driver.ts index c16032c953f..ce2167ba328 100644 --- a/src/vs/platform/driver/browser/driver.ts +++ b/src/vs/platform/driver/browser/driver.ts @@ -7,7 +7,7 @@ import { getClientArea, getTopLeftOffset } from 'vs/base/browser/dom'; import { coalesce } from 'vs/base/common/arrays'; import { language, locale } from 'vs/base/common/platform'; import { IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver'; -import localizedStrings from 'vs/platform/localizations/common/localizedStrings'; +import localizedStrings from 'vs/platform/languagePacks/common/localizedStrings'; export class BrowserWindowDriver implements IWindowDriver { diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts index 9279c520625..a2ff49e9bfd 100644 --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -616,6 +616,7 @@ export function reportTelemetry(telemetryService: ITelemetryService, eventName: const errorcode = error ? error instanceof ExtensionManagementError ? error.code : ExtensionManagementErrorCode.Internal : undefined; /* __GDPR__ "extensionGallery:install" : { + "owner": "sandy081", "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "durationSinceUpdate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, @@ -628,6 +629,7 @@ export function reportTelemetry(telemetryService: ITelemetryService, eventName: */ /* __GDPR__ "extensionGallery:uninstall" : { + "owner": "sandy081", "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "errorcode": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, @@ -638,6 +640,7 @@ export function reportTelemetry(telemetryService: ITelemetryService, eventName: */ /* __GDPR__ "extensionGallery:update" : { + "owner": "sandy081", "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "errorcode": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 3f563b19e40..443107d84b9 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -235,6 +235,7 @@ const DefaultQueryState: IQueryState = { }; type GalleryServiceQueryClassification = { + owner: 'sandy081'; readonly filterTypes: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; readonly flags: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; readonly sortBy: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; @@ -272,6 +273,7 @@ type GalleryServiceQueryEvent = QueryTelemetryData & { }; type GalleryServiceAdditionalQueryClassification = { + owner: 'sandy081'; readonly duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; 'isMeasurement': true }; readonly count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; @@ -992,6 +994,7 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const startTime = new Date().getTime(); /* __GDPR__ "galleryService:downloadVSIX" : { + "owner": "sandy081", "duration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "${include}": [ "${GalleryExtensionTelemetryData}" @@ -1124,6 +1127,7 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const message = getErrorMessage(err); type GalleryServiceCDNFallbackClassification = { + owner: 'sandy081'; url: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; message: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts index f0a14198878..91cda7e7d16 100644 --- a/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts +++ b/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts @@ -27,6 +27,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; type ExeExtensionRecommendationsClassification = { + owner: 'sandy081'; extensionId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; exeName: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/platform/extensions/common/extensionHostStarter.ts b/src/vs/platform/extensions/common/extensionHostStarter.ts index d4fc6b48112..5d2a9e3a83a 100644 --- a/src/vs/platform/extensions/common/extensionHostStarter.ts +++ b/src/vs/platform/extensions/common/extensionHostStarter.ts @@ -12,6 +12,9 @@ export const IExtensionHostStarter = createDecorator('ext export const ipcExtensionHostStarterChannelName = 'extensionHostStarter'; export interface IExtensionHostProcessOptions { + responseWindowId: number; + responseChannel: string; + responseNonce: string; env: { [key: string]: string | undefined }; detached: boolean; execArgv: string[] | undefined; @@ -27,8 +30,9 @@ export interface IExtensionHostStarter { onDynamicError(id: string): Event<{ error: SerializedError }>; onDynamicExit(id: string): Event<{ code: number; signal: string }>; - createExtensionHost(): Promise<{ id: string }>; - start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number }>; + canUseUtilityProcess(): Promise; + createExtensionHost(useUtilityProcess: boolean): Promise<{ id: string }>; + start(id: string, opts: IExtensionHostProcessOptions): Promise; enableInspectPort(id: string): Promise; kill(id: string): Promise; diff --git a/src/vs/platform/extensions/electron-main/extensionHostStarter.ts b/src/vs/platform/extensions/electron-main/extensionHostStarter.ts index 493168507e8..1647d46f55b 100644 --- a/src/vs/platform/extensions/electron-main/extensionHostStarter.ts +++ b/src/vs/platform/extensions/electron-main/extensionHostStarter.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { canceled, SerializedError, transformErrorForSerialization } from 'vs/base/common/errors'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform/extensions/common/extensionHostStarter'; import { Emitter, Event } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; @@ -17,20 +17,40 @@ import { FileAccess } from 'vs/base/common/network'; import { mixin } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { cwd } from 'vs/base/common/process'; +import type { EventEmitter } from 'events'; +import * as electron from 'electron'; + +declare namespace UtilityProcessProposedApi { + interface UtilityProcessOptions { + serviceName?: string | undefined; + execArgv?: string[] | undefined; + env?: NodeJS.ProcessEnv | undefined; + } + export class UtilityProcess extends EventEmitter { + readonly pid?: number | undefined; + constructor(modulePath: string, args?: string[] | undefined, options?: UtilityProcessOptions); + postMessage(channel: string, message: any, transfer?: Electron.MessagePortMain[]): void; + kill(signal?: number | string): boolean; + on(event: 'exit', listener: (code: number) => void): this; + on(event: 'spawn', listener: () => void): this; + } +} +const UtilityProcess = ((electron as any).UtilityProcess); +const canUseUtilityProcess = (typeof UtilityProcess !== 'undefined'); export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter { _serviceBrand: undefined; private static _lastId: number = 0; - protected readonly _extHosts: Map; + protected readonly _extHosts: Map; private _shutdown = false; constructor( @ILogService private readonly _logService: ILogService, @ILifecycleMainService lifecycleMainService: ILifecycleMainService ) { - this._extHosts = new Map(); + this._extHosts = new Map(); // On shutdown: gracefully await extension host shutdowns lifecycleMainService.onWillShutdown((e) => { @@ -43,7 +63,7 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter // Intentionally not killing the extension host processes } - private _getExtHost(id: string): ExtensionHostProcess { + private _getExtHost(id: string): ExtensionHostProcess | UtilityExtensionHostProcess { const extHostProcess = this._extHosts.get(id); if (!extHostProcess) { throw new Error(`Unknown extension host!`); @@ -71,12 +91,24 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter return this._getExtHost(id).onExit; } - async createExtensionHost(): Promise<{ id: string }> { + async canUseUtilityProcess(): Promise { + return canUseUtilityProcess; + } + + async createExtensionHost(useUtilityProcess: boolean): Promise<{ id: string }> { if (this._shutdown) { throw canceled(); } const id = String(++ExtensionHostStarter._lastId); - const extHost = new ExtensionHostProcess(id, this._logService); + let extHost: UtilityExtensionHostProcess | ExtensionHostProcess; + if (useUtilityProcess) { + if (!canUseUtilityProcess) { + throw new Error(`Cannot use UtilityProcess!`); + } + extHost = new UtilityExtensionHostProcess(id, this._logService); + } else { + extHost = new ExtensionHostProcess(id, this._logService); + } this._extHosts.set(id, extHost); extHost.onExit(({ pid, code, signal }) => { this._logService.info(`Extension host with pid ${pid} exited with code: ${code}, signal: ${signal}.`); @@ -88,7 +120,7 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter return { id }; } - async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number }> { + async start(id: string, opts: IExtensionHostProcessOptions): Promise { if (this._shutdown) { throw canceled(); } @@ -160,7 +192,7 @@ class ExtensionHostProcess extends Disposable { super(); } - start(opts: IExtensionHostProcessOptions): { pid: number } { + start(opts: IExtensionHostProcessOptions): void { if (platform.isCI) { this._logService.info(`Calling fork to start extension host...`); } @@ -199,8 +231,130 @@ class ExtensionHostProcess extends Disposable { this._hasExited = true; this._onExit.fire({ pid, code, signal }); }); - - return { pid }; + } + + enableInspectPort(): boolean { + if (!this._process) { + return false; + } + + this._logService.info(`Enabling inspect port on extension host with pid ${this._process.pid}.`); + + interface ProcessExt { + _debugProcess?(n: number): any; + } + + if (typeof (process)._debugProcess === 'function') { + // use (undocumented) _debugProcess feature of node + (process)._debugProcess!(this._process.pid!); + return true; + } else if (!platform.isWindows) { + // use KILL USR1 on non-windows platforms (fallback) + this._process.kill('SIGUSR1'); + return true; + } else { + // not supported... + return false; + } + } + + kill(): void { + if (!this._process) { + return; + } + this._logService.info(`Killing extension host with pid ${this._process.pid}.`); + this._process.kill(); + } + + async waitForExit(maxWaitTimeMs: number): Promise { + if (!this._process) { + return; + } + const pid = this._process.pid; + this._logService.info(`Waiting for extension host with pid ${pid} to exit.`); + await Promise.race([Event.toPromise(this.onExit), timeout(maxWaitTimeMs)]); + + if (!this._hasExited) { + // looks like we timed out + this._logService.info(`Extension host with pid ${pid} did not exit within ${maxWaitTimeMs}ms.`); + this._process.kill(); + } + } +} + +class UtilityExtensionHostProcess extends Disposable { + + readonly onStdout = Event.None; + readonly onStderr = Event.None; + readonly onError = Event.None; + + readonly _onMessage = this._register(new Emitter()); + readonly onMessage = this._onMessage.event; + + readonly _onExit = this._register(new Emitter<{ pid: number; code: number; signal: string }>()); + readonly onExit = this._onExit.event; + + private _process: UtilityProcessProposedApi.UtilityProcess | null = null; + private _hasExited: boolean = false; + + constructor( + public readonly id: string, + @ILogService private readonly _logService: ILogService, + ) { + super(); + } + + start(opts: IExtensionHostProcessOptions): void { + const responseWindow = electron.BrowserWindow.fromId(opts.responseWindowId); + if (!responseWindow || responseWindow.isDestroyed() || responseWindow.webContents.isDestroyed()) { + this._logService.info(`Refusing to create new Extension Host UtilityProcess because requesting window cannot be found...`); + return; + } + + const serviceName = `extensionHost${this.id}`; + const modulePath = FileAccess.asFileUri('bootstrap-fork.js', require).fsPath; + const args: string[] = ['--type=extensionHost', '--skipWorkspaceStorageLock']; + const execArgv: string[] = opts.execArgv || []; + const env: { [key: string]: any } = { ...opts.env }; + + // Make sure all values are strings, otherwise the process will not start + for (const key of Object.keys(env)) { + env[key] = String(env[key]); + } + + this._logService.info(`Creating new UtilityProcess to start extension host...`); + + this._process = new UtilityProcess(modulePath, args, { serviceName, env, execArgv }); + + this._process.on('spawn', () => { + this._logService.info(`Utility process emits spawn!`); + }); + this._process.on('exit', (code: number) => { + this._logService.info(`Utility process emits exit!`); + this._hasExited = true; + this._onExit.fire({ pid: this._process!.pid!, code, signal: '' }); + }); + const listener = (event: electron.Event, details: electron.Details) => { + if (details.type !== 'Utility') { + return; + } + // Despite the fact that we pass the argument `seviceName`, + // the details have a field called `name` where this value appears + if (details.name === serviceName) { + this._logService.info(`Utility process emits exit!`); + this._hasExited = true; + this._onExit.fire({ pid: this._process!.pid!, code: details.exitCode, signal: '' }); + } + }; + electron.app.on('child-process-gone', listener); + this._register(toDisposable(() => { + electron.app.off('child-process-gone', listener); + })); + + const { port1, port2 } = new electron.MessageChannelMain(); + + this._process.postMessage('port', null, [port2]); + responseWindow.webContents.postMessage(opts.responseChannel, opts.responseNonce, [port1]); } enableInspectPort(): boolean { diff --git a/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts b/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts index ee053cda77a..6436f0a4d4b 100644 --- a/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts +++ b/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts @@ -16,6 +16,7 @@ import { createFileSystemProviderError, FileChangeType, IFileDeleteOptions, IFil import { DBClosedError, IndexedDB } from 'vs/base/browser/indexedDB'; export type IndexedDBFileSystemProviderErrorDataClassification = { + owner: 'sandy081'; readonly scheme: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; readonly operation: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; readonly code: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; diff --git a/src/vs/platform/languagePacks/common/languagePacks.ts b/src/vs/platform/languagePacks/common/languagePacks.ts new file mode 100644 index 00000000000..473e358148a --- /dev/null +++ b/src/vs/platform/languagePacks/common/languagePacks.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const ILanguagePackService = createDecorator('languagePackService'); +export interface ILanguagePackService { + readonly _serviceBrand: undefined; + getInstalledLanguages(): Promise; +} diff --git a/src/vs/platform/localizations/common/localizedStrings.ts b/src/vs/platform/languagePacks/common/localizedStrings.ts similarity index 100% rename from src/vs/platform/localizations/common/localizedStrings.ts rename to src/vs/platform/languagePacks/common/localizedStrings.ts diff --git a/src/vs/platform/localizations/node/localizations.ts b/src/vs/platform/languagePacks/node/languagePacks.ts similarity index 88% rename from src/vs/platform/localizations/node/localizations.ts rename to src/vs/platform/languagePacks/node/languagePacks.ts index 9d8bd79ac7d..009c936bdb0 100644 --- a/src/vs/platform/localizations/node/localizations.ts +++ b/src/vs/platform/languagePacks/node/languagePacks.ts @@ -13,7 +13,8 @@ import { Promises } from 'vs/base/node/pfs'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { IExtensionIdentifier, IExtensionManagementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ILocalizationsService, isValidLocalization } from 'vs/platform/localizations/common/localizations'; +import { ILocalizationContribution } from 'vs/platform/extensions/common/extensions'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { ILogService } from 'vs/platform/log/common/log'; interface ILanguagePack { @@ -25,7 +26,7 @@ interface ILanguagePack { translations: { [id: string]: string }; } -export class LocalizationsService extends Disposable implements ILocalizationsService { +export class LanguagePackService extends Disposable implements ILanguagePackService { declare readonly _serviceBrand: undefined; @@ -48,7 +49,7 @@ export class LocalizationsService extends Disposable implements ILocalizationsSe }); } - async getLanguageIds(): Promise { + async getInstalledLanguages(): Promise { const languagePacks = await this.cache.getLanguagePacks(); // Contributed languages are those installed via extension packs, so does not include English const languages = ['en', ...Object.keys(languagePacks)]; @@ -174,3 +175,27 @@ class LanguagePacksCache extends Disposable { }); } } + +function isValidLocalization(localization: ILocalizationContribution): boolean { + if (typeof localization.languageId !== 'string') { + return false; + } + if (!Array.isArray(localization.translations) || localization.translations.length === 0) { + return false; + } + for (const translation of localization.translations) { + if (typeof translation.id !== 'string') { + return false; + } + if (typeof translation.path !== 'string') { + return false; + } + } + if (localization.languageName && typeof localization.languageName !== 'string') { + return false; + } + if (localization.localizedLanguageName && typeof localization.localizedLanguageName !== 'string') { + return false; + } + return true; +} diff --git a/src/vs/platform/localizations/common/localizations.ts b/src/vs/platform/localizations/common/localizations.ts deleted file mode 100644 index 6792440125c..00000000000 --- a/src/vs/platform/localizations/common/localizations.ts +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ILocalizationContribution } from 'vs/platform/extensions/common/extensions'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const ILocalizationsService = createDecorator('localizationsService'); -export interface ILocalizationsService { - readonly _serviceBrand: undefined; - getLanguageIds(): Promise; -} - -export function isValidLocalization(localization: ILocalizationContribution): boolean { - if (typeof localization.languageId !== 'string') { - return false; - } - if (!Array.isArray(localization.translations) || localization.translations.length === 0) { - return false; - } - for (const translation of localization.translations) { - if (typeof translation.id !== 'string') { - return false; - } - if (typeof translation.path !== 'string') { - return false; - } - } - if (localization.languageName && typeof localization.languageName !== 'string') { - return false; - } - if (localization.localizedLanguageName && typeof localization.localizedLanguageName !== 'string') { - return false; - } - return true; -} diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 5a30a5743de..859af104212 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -84,8 +84,10 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf return configurationService.onDidChangeConfiguration(event => { if (event.source !== ConfigurationTarget.DEFAULT) { type UpdateConfigurationClassification = { - configurationSource: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; - configurationKeys: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + owner: 'lramos15, sbatten'; + comment: 'Event which fires when user updates telemetry configuration'; + configurationSource: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration file was updated i.e user or workspace' }; + configurationKeys: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration keys were updated' }; }; type UpdateConfigurationEvent = { configurationSource: string; diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index df36e27041d..2e456109e9e 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -144,7 +144,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati private _handleVSCodeSequence(data: string): boolean { const didHandle = this._doHandleVSCodeSequence(data); if (!this._hasUpdatedTelemetry && didHandle) { - this._telemetryService?.publicLog2<{ classification: 'SystemMetaData'; purpose: 'FeatureInsight' }>('terminal/shellIntegrationActivationSucceeded'); + this._telemetryService?.publicLog2<{}, { owner: 'meganrogge'; comment: 'Indicates shell integration was activated' }>('terminal/shellIntegrationActivationSucceeded'); this._hasUpdatedTelemetry = true; if (this._activationTimeout !== undefined) { clearTimeout(this._activationTimeout); @@ -232,7 +232,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati private async _ensureCapabilitiesOrAddFailureTelemetry(): Promise { this._activationTimeout = setTimeout(() => { if (!this.capabilities.get(TerminalCapability.CommandDetection) && !this.capabilities.get(TerminalCapability.CwdDetection)) { - this._telemetryService?.publicLog2<{ classification: 'SystemMetaData'; purpose: 'FeatureInsight' }>('terminal/shellIntegrationActivationTimeout'); + this._telemetryService?.publicLog2<{}, { owner: 'meganrogge'; comment: 'Indicates shell integration activation did not occur within 10 seconds' }>('terminal/shellIntegrationActivationTimeout'); this._logService.warn('Shell integration failed to add capabilities within 10 seconds'); } this._hasUpdatedTelemetry = true; diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index 42b9e8cee7a..8d777b69a7e 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -19,6 +19,7 @@ export function createUpdateURL(platform: string, quality: string, productServic } export type UpdateNotAvailableClassification = { + owner: 'joaomoreno'; explicit: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index 0c008ea8504..df08a4b7966 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -92,6 +92,7 @@ export class DarwinUpdateService extends AbstractUpdateService { } type UpdateDownloadedClassification = { + owner: 'joaomoreno'; version: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this.telemetryService.publicLog2<{ version: String }, UpdateDownloadedClassification>('update:downloaded', { version: update.version }); diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 932841567c6..74d549a5bee 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -29,6 +29,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { Change, getLastSyncResourceUri, IRemoteUserData, IResourcePreview as IBaseResourcePreview, ISyncData, ISyncResourceHandle, ISyncResourcePreview as IBaseSyncResourcePreview, IUserData, IUserDataInitializer, IUserDataManifest, IUserDataSyncBackupStoreService, IUserDataSyncConfiguration, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, IUserDataSyncUtilService, MergeState, PREVIEW_DIR_NAME, SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_CONFIGURATION_SCOPE, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; type SyncSourceClassification = { + owner: 'sandy081'; source?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index bea7313f0b3..108017e834b 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -22,10 +22,12 @@ import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/use import { IUserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; type AutoSyncClassification = { + owner: 'sandy081'; sources: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; type AutoSyncErrorClassification = { + owner: 'sandy081'; code: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; service: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; @@ -194,7 +196,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto // Reset if (everywhere) { - this.telemetryService.publicLog2('sync/turnOffEveryWhere'); + this.telemetryService.publicLog2<{}, { owner: 'sandy081' }>('sync/turnOffEveryWhere'); await this.userDataSyncService.reset(); } else { await this.userDataSyncService.resetLocal(); diff --git a/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts b/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts index 8e237a29063..9538b66d373 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts @@ -12,6 +12,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ALL_SYNC_RESOURCES, getEnablementKey, IUserDataSyncEnablementService, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; type SyncEnablementClassification = { + owner: 'sandy081'; enabled?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index f3dc3c82982..ff26c4d2b88 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -28,6 +28,7 @@ import { TasksSynchroniser } from 'vs/platform/userDataSync/common/tasksSync'; import { ALL_SYNC_RESOURCES, Change, createSyncHeaders, IManualSyncTask, IResourcePreview, ISyncResourceHandle, ISyncResourcePreview, ISyncTask, IUserDataManifest, IUserDataSyncConfiguration, IUserDataSyncEnablementService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, MergeState, SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, UserDataSyncStoreError, USER_DATA_SYNC_CONFIGURATION_SCOPE } from 'vs/platform/userDataSync/common/userDataSync'; type SyncErrorClassification = { + owner: 'sandy081'; code: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; service: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; serverCode?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts index 36c01538db4..2d8bde94e63 100644 --- a/src/vs/server/node/remoteExtensionHostAgentCli.ts +++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts @@ -28,8 +28,8 @@ import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IServerEnvironmentService, ServerEnvironmentService, ServerParsedArgs } from 'vs/server/node/serverEnvironmentService'; import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; +import { LanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; import { getErrorMessage } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; import { isAbsolute, join } from 'vs/base/common/path'; @@ -104,7 +104,7 @@ class CliMain extends Disposable { services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); - services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + services.set(ILanguagePackService, new SyncDescriptor(LanguagePackService)); return new InstantiationService(services); } diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index 3ae68711aa1..09aafc649a7 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -757,10 +757,10 @@ export async function createServer(address: string | net.AddressInfo | null, arg type ServerStartClassification = { owner: 'alexdima'; comment: 'The server has started up'; - startTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; - startedTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; - codeLoadedTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; - readyTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; + startTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time the server started at.' }; + startedTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time the server began listening for connections.' }; + codeLoadedTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time which the code loaded on the server' }; + readyTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The time when the server was completely ready' }; }; type ServerStartEvent = { startTime: number; diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 9885e9a1982..9a4bdee0c1a 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -35,8 +35,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; +import { LanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILogService, LogLevel, LogService, MultiplexLogService } from 'vs/platform/log/common/log'; import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; @@ -159,7 +159,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); const instantiationService: IInstantiationService = new InstantiationService(services); - services.set(ILocalizationsService, instantiationService.createInstance(LocalizationsService)); + services.set(ILanguagePackService, instantiationService.createInstance(LanguagePackService)); const extensionManagementCLIService = instantiationService.createInstance(ExtensionManagementCLIService); services.set(IExtensionManagementCLIService, extensionManagementCLIService); diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index ff3bd15f82a..f89e0698b9d 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -5,6 +5,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { VSDataTransfer } from 'vs/base/common/dataTransfer'; import { CancellationError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { combinedDisposable, Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -23,14 +24,13 @@ import { ITextModel } from 'vs/editor/common/model'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; import { DataTransferCache } from 'vs/workbench/api/common/shared/dataTransferCache'; import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import * as search from 'vs/workbench/contrib/search/common/search'; import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; -import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol'; -import { VSDataTransfer } from 'vs/base/common/dataTransfer'; -import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; +import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceEditDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol'; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape { @@ -366,6 +366,47 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread this._registrations.set(handle, this._languageFeaturesService.codeActionProvider.register(selector, provider)); } + // --- copy paste action provider + + $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void { + const provider: languages.DocumentPasteEditProvider = { + prepareDocumentPaste: supportsCopy + ? async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise => { + const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer); + if (token.isCancellationRequested) { + return undefined; + } + + const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selection, dataTransferDto, token); + if (!result) { + return undefined; + } + + + const dataTransferOut = new VSDataTransfer(); + result.items.forEach(([type, item]) => { + dataTransferOut.setString(type, item.asString); + }); + return dataTransferOut; + } + : undefined, + + provideDocumentPasteEdits: async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken) => { + const d = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer); + const result = await this._proxy.$providePasteEdits(handle, model.uri, selection, d, token); + if (!result) { + return; + } else if ((result as IWorkspaceEditDto).edits) { + return reviveWorkspaceEditDto(result as IWorkspaceEditDto); + } else { + return result as languages.SnippetTextEdit; + } + } + }; + + this._registrations.set(handle, this._languageFeaturesService.documentPasteEditProvider.register(selector, provider)); + } + // --- formatting $registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void { diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 3cb6a499c8c..5ac8c935667 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -421,6 +421,16 @@ export class MainThreadSCM implements MainThreadSCMShape { repository.input.placeholder = placeholder; } + $setInputBoxEnablement(sourceControlHandle: number, enabled: boolean): void { + const repository = this._repositories.get(sourceControlHandle); + + if (!repository) { + return; + } + + repository.input.enabled = enabled; + } + $setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void { const repository = this._repositories.get(sourceControlHandle); diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index f0923d95701..56133dc4b20 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -37,14 +37,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } - async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise { + async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean; hasHandleDrop: boolean; supportsFileDataTransfers: boolean }): Promise { this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService); this._dataProviders.set(treeViewId, dataProvider); const dndController = (options.hasHandleDrag || options.hasHandleDrop) - ? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, this._proxy) : undefined; + ? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, options.supportsFileDataTransfers, this._proxy) : undefined; const viewer = this.getTreeView(treeViewId); if (viewer) { // Order is important here. The internal tree isn't created until the dataProvider is set. @@ -201,6 +201,7 @@ class TreeViewDragAndDropController implements ITreeViewDragAndDropController { readonly dropMimeTypes: string[], readonly dragMimeTypes: string[], readonly hasWillDrop: boolean, + readonly supportsFileDataTransfers: boolean, private readonly _proxy: ExtHostTreeViewsShape) { } async handleDrop(dataTransfer: VSDataTransfer, targetTreeItem: ITreeItem | undefined, token: CancellationToken, diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 1cac3df2253..9c1a1e66eed 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -457,6 +457,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable { return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata); }, + registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable { + checkProposedApiEnabled(extension, 'documentPaste'); + return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider); + }, registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable { return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider); }, @@ -524,7 +528,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostLanguageFeatures.registerCompletionItemProvider(extension, checkSelector(selector), provider, triggerCharacters); }, registerInlineCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider): vscode.Disposable { - checkProposedApiEnabled(extension, 'inlineCompletions'); if (provider.handleDidShowCompletionItem) { checkProposedApiEnabled(extension, 'inlineCompletionsAdditions'); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 33fcc3fb351..3b29ae91432 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -258,7 +258,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { } export interface MainThreadTreeViewsShape extends IDisposable { - $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean }): Promise; + $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean; supportsFileDataTransfers: boolean }): Promise; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise; $reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise; $setMessage(treeViewId: string, message: string): void; @@ -372,6 +372,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void; + $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void; $registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void; $registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void; $registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void; @@ -1187,6 +1188,7 @@ export interface MainThreadSCMShape extends IDisposable { $setInputBoxValue(sourceControlHandle: number, value: string): void; $setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void; + $setInputBoxEnablement(sourceControlHandle: number, enabled: boolean): void; $setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void; $showValidationMessage(sourceControlHandle: number, message: string | IMarkdownString, type: InputValidationType): void; $setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void; @@ -1729,6 +1731,8 @@ export interface ExtHostLanguageFeaturesShape { $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise; $resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise; $releaseCodeActions(handle: number, cacheId: number): void; + $prepareDocumentPaste(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise; + $providePasteEdits(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise | undefined>; $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise; $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise; $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 49eaa65d462..d23efb3a111 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -424,6 +424,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) { const event = getTelemetryActivationEvent(extensionDescription, reason); type ExtensionActivationTimesClassification = { + owner: 'jrieken'; outcome: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; } & TelemetryActivationEventFragment & ExtensionActivationTimesFragment; @@ -447,7 +448,9 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise { const event = getTelemetryActivationEvent(extensionDescription, reason); - type ActivatePluginClassification = {} & TelemetryActivationEventFragment; + type ActivatePluginClassification = { + owner: 'jrieken'; + } & TelemetryActivationEventFragment; this._mainThreadTelemetryProxy.$publicLog2('activatePlugin', event); const entryPoint = this._getEntryPoint(extensionDescription); if (!entryPoint) { diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 53f5ad08081..4f06e60d82c 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { mixin } from 'vs/base/common/objects'; import type * as vscode from 'vscode'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; -import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind } from 'vs/workbench/api/common/extHostTypes'; +import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind, WorkspaceEdit } from 'vs/workbench/api/common/extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; import * as languages from 'vs/editor/common/languages'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; @@ -31,7 +31,7 @@ import { IdGenerator } from 'vs/base/common/idGenerator'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; import { Cache } from './cache'; import { StopWatch } from 'vs/base/common/stopwatch'; -import { isCancellationError } from 'vs/base/common/errors'; +import { isCancellationError, NotImplementedError } from 'vs/base/common/errors'; import { raceCancellationError } from 'vs/base/common/async'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier'; @@ -485,6 +485,52 @@ class CodeActionAdapter { } } +class DocumentPasteEditProvider { + + constructor( + private readonly _proxy: extHostProtocol.MainThreadLanguageFeaturesShape, + private readonly _documents: ExtHostDocuments, + private readonly _provider: vscode.DocumentPasteEditProvider, + private readonly _handle: number, + ) { } + + async prepareDocumentPaste(resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise { + if (!this._provider.prepareDocumentPaste) { + return undefined; + } + + const doc = this._documents.getDocument(resource); + const vscodeRange = typeConvert.Range.to(range); + + const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, () => { + throw new NotImplementedError(); + }); + await this._provider.prepareDocumentPaste(doc, vscodeRange, dataTransfer, token); + + return typeConvert.DataTransfer.toDataTransferDTO(dataTransfer); + } + + async providePasteEdits(requestId: number, resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise> { + const doc = this._documents.getDocument(resource); + const vscodeRange = typeConvert.Range.to(range); + + const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => { + return (await this._proxy.$resolveDocumentOnDropFileData(this._handle, requestId, index)).buffer; + }); + + const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRange, dataTransfer, token); + if (!edit) { + return; + } + + if (edit instanceof WorkspaceEdit) { + return typeConvert.WorkspaceEdit.from(edit); + } else { + return typeConvert.SnippetTextEdit.from(edit as vscode.SnippetTextEdit); + } + } +} + class DocumentFormattingAdapter { constructor( @@ -1769,7 +1815,7 @@ class DocumentOnDropEditAdapter { } type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter - | DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter + | DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentPasteEditProvider | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | CompletionsAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter @@ -2413,6 +2459,23 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF Promise.resolve(adapter.provideDocumentOnDropEdits(requestId, URI.revive(resource), position, dataTransferDto, token)), undefined, undefined); } + // --- copy/paste actions + + registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable { + const handle = this._nextHandle(); + this._adapter.set(handle, new AdapterData(new DocumentPasteEditProvider(this._proxy, this._documents, provider, handle), extension)); + this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste); + return this._createDisposable(handle); + } + + $prepareDocumentPaste(handle: number, resource: UriComponents, range: IRange, dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise { + return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), range, dataTransfer, token), undefined, token); + } + + $providePasteEdits(handle: number, resource: UriComponents, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise | undefined> { + return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), range, dataTransferDto, token), undefined, token); + } + // --- configuration private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto { diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 4a072952392..4ae49cc2a8b 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -249,6 +249,7 @@ class KeytarNodeModuleFactory implements INodeModuleFactory { public load(_request: string, parent: URI): any { const ext = this._extensionPaths.findSubstr(parent); type ShimmingKeytarClassification = { + owner: 'jrieken'; extension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this._mainThreadTelemetry.$publicLog2<{ extension: string }, ShimmingKeytarClassification>('shimming.keytar', { extension: ext?.identifier.value ?? 'unknown_extension' }); @@ -346,6 +347,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { return; } type ShimmingOpenClassification = { + owner: 'jrieken'; extension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this._mainThreadTelemetry.$publicLog2<{ extension: string }, ShimmingOpenClassification>('shimming.open', { extension: this._extensionId }); @@ -356,6 +358,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { return; } type ShimmingOpenCallNoForwardClassification = { + owner: 'jrieken'; extension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this._mainThreadTelemetry.$publicLog2<{ extension: string }, ShimmingOpenCallNoForwardClassification>('shimming.open.call.noForward', { extension: this._extensionId }); diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 49a54bc71fe..db595e3c9a5 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -249,6 +249,25 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox { this.#proxy.$setValidationProviderIsEnabled(this._sourceControlHandle, !!fn); } + private _enabled: boolean = true; + + get enabled(): boolean { + checkProposedApiEnabled(this._extension, 'scmInput'); + return this._enabled; + } + + set enabled(enabled: boolean) { + checkProposedApiEnabled(this._extension, 'scmInput'); + enabled = !!enabled; + + if (this._enabled === enabled) { + return; + } + + this._enabled = enabled; + this.#proxy.$setInputBoxEnablement(this._sourceControlHandle, enabled); + } + private _visible: boolean = true; get visible(): boolean { @@ -722,7 +741,10 @@ export class ExtHostSCM implements ExtHostSCMShape { this.logService.trace('ExtHostSCM#createSourceControl', extension.identifier.value, id, label, rootUri); type TEvent = { extensionId: string }; - type TMeta = { extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' } }; + type TMeta = { + owner: 'joaomoreno'; + extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; + }; this._telemetry.$publicLog2('api/scm/createSourceControl', { extensionId: extension.identifier.value, }); diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 00d03d0b6ee..c05d65eee9e 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -24,7 +24,7 @@ import { Schemas } from 'vs/base/common/network'; import * as Platform from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; -import { USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/taskService'; +import { USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/tasks'; import { NotSupportedError } from 'vs/base/common/errors'; export interface IExtHostTask extends ExtHostTaskShape { diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index fdbb535e422..8bdd508109c 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -24,7 +24,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { Command } from 'vs/editor/common/languages'; import { ITreeViewsService, TreeviewsService } from 'vs/workbench/services/views/common/treeViewsService'; -import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; type TreeItemHandle = string; @@ -92,7 +92,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { const dragMimeTypes = options.dragAndDropController?.dragMimeTypes ?? []; const hasHandleDrag = !!options.dragAndDropController?.handleDrag; const hasHandleDrop = !!options.dragAndDropController?.handleDrop; - const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag, hasHandleDrop }); + const supportsFileDataTransfers = isProposedApiEnabled(extension, 'dataTransferFiles'); + const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag, hasHandleDrop, supportsFileDataTransfers }); const treeView = this.createExtHostTreeView(viewId, options, extension); return { get onDidCollapseElement() { return treeView.onDidCollapseElement; }, diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 2707ecf73d3..101afcd8e76 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -23,6 +23,7 @@ import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; import { ProcessTimeRunOnceScheduler } from 'vs/base/common/async'; import { boolean } from 'vs/editor/common/config/editorOptions'; import { createURITransformer } from 'vs/workbench/api/node/uriTransformer'; +import { MessagePortMain } from 'electron'; import 'vs/workbench/api/common/extHost.common.services'; import 'vs/workbench/api/node/extHost.node.services'; @@ -102,8 +103,37 @@ let onTerminate = function (reason: string) { nativeExit(); }; -function _createExtHostProtocol(): Promise { - if (process.env.VSCODE_EXTHOST_WILL_SEND_SOCKET) { +function _createExtHostProtocol(): Promise { + if (process.env.VSCODE_WILL_SEND_MESSAGE_PORT) { + + return new Promise((resolve, reject) => { + + const withPorts = (ports: MessagePortMain[]) => { + const port = ports[0]; + const onMessage = new BufferedEmitter(); + port.on('message', (e) => onMessage.fire(VSBuffer.wrap(e.data))); + port.on('close', () => { + onTerminate('renderer closed the MessagePort'); + }); + port.start(); + + resolve({ + onMessage: onMessage.event, + send: message => port.postMessage(message.buffer) + }); + }; + + if ((global).vscodePorts) { + const ports = (global).vscodePorts; + delete (global).vscodePorts; + withPorts(ports); + } else { + (global).vscodePortsCallback = withPorts; + } + + }); + + } else if (process.env.VSCODE_EXTHOST_WILL_SEND_SOCKET) { return new Promise((resolve, reject) => { @@ -220,8 +250,10 @@ async function createExtHostProtocol(): Promise { } } - drain(): Promise { - return protocol.drain(); + async drain(): Promise { + if (protocol.drain) { + return protocol.drain(); + } } }; } diff --git a/src/vs/workbench/api/test/browser/mainThreadTreeViews.test.ts b/src/vs/workbench/api/test/browser/mainThreadTreeViews.test.ts index 1386a01b234..4afba6e05e6 100644 --- a/src/vs/workbench/api/test/browser/mainThreadTreeViews.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadTreeViews.test.ts @@ -75,7 +75,7 @@ suite('MainThreadHostTreeView', function () { } drain(): any { return null; } }, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService()); - mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, dropMimeTypes: [], dragMimeTypes: [], hasHandleDrag: false, hasHandleDrop: false }); + mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, dropMimeTypes: [], dragMimeTypes: [], hasHandleDrag: false, hasHandleDrop: false, supportsFileDataTransfers: false }); await testExtensionService.whenInstalledExtensionsRegistered(); }); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 36647e6dcfe..307fd9e9fec 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -102,6 +102,7 @@ export class ViewContainerActivityAction extends ActivityAction { private logAction(action: string) { type ActivityBarActionClassification = { + owner: 'sbatten'; viewletId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 3624936e41f..a07f202b076 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -968,6 +968,7 @@ function registerCloseEditorCommands() { ]); type WorkbenchEditorReopenClassification = { + owner: 'rebornix'; scheme: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; ext: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; from: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 7ea0ca109d4..21b5d732107 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -575,6 +575,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { /* __GDPR__ "editorOpened" : { + "owner": "bpasero", "${include}": [ "${EditorTelemetryDescriptor}" ] @@ -611,6 +612,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { /* __GDPR__ "editorClosed" : { + "owner": "bpasero", "${include}": [ "${EditorTelemetryDescriptor}" ] diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 50da8ebb647..051926ebcb4 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -66,7 +66,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; import { ThemeSettings } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ITreeViewsService } from 'vs/workbench/services/views/browser/treeViewsService'; -import { CodeDataTransfers } from 'vs/platform/dnd/browser/dnd'; +import { CodeDataTransfers, FileAdditionalNativeProperties } from 'vs/platform/dnd/browser/dnd'; export class TreeViewPane extends ViewPane { @@ -1503,40 +1503,21 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { } const treeDataTransfer = new VSDataTransfer(); const uris: URI[] = []; - let itemsCount = Array.from(originalEvent.dataTransfer.items).reduce((previous, current) => { - if ((current.kind === 'string') || (current.kind === 'file')) { - return previous + 1; - } - return previous; - }, 0); let treeSourceInfo: TreeDragSourceInfo | undefined; let willDropUuid: string | undefined; if (this.treeItemsTransfer.hasData(DraggedTreeItemsIdentifier.prototype)) { willDropUuid = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype)![0].identifier; } - await new Promise(resolve => { - function decrementStringCount() { - itemsCount--; - if (itemsCount === 0) { - // Check if there are uris to add and add them - if (uris.length) { - treeDataTransfer.setString(Mimes.uriList, uris.map(uri => uri.toString()).join('\n')); - } - resolve(); - } - } - if (!originalEvent.dataTransfer) { - return; - } - for (const dataItem of originalEvent.dataTransfer.items) { - const type = dataItem.type; - const kind = dataItem.kind; - const convertedType = this.convertKnownMimes(type, kind).type; - if ((INTERNAL_MIME_TYPES.indexOf(convertedType) < 0) - && (convertedType === this.treeMimeType) || (dndController.dropMimeTypes.indexOf(convertedType) >= 0)) { - if (dataItem.kind === 'string') { + await Promise.all([...originalEvent.dataTransfer.items].map(async dataItem => { + const type = dataItem.type; + const kind = dataItem.kind; + const convertedType = this.convertKnownMimes(type, kind).type; + if ((INTERNAL_MIME_TYPES.indexOf(convertedType) < 0) + && (convertedType === this.treeMimeType) || (dndController.dropMimeTypes.indexOf(convertedType) >= 0)) { + if (dataItem.kind === 'string') { + await new Promise(resolve => dataItem.getAsString(dataValue => { if (convertedType === this.treeMimeType) { treeSourceInfo = JSON.parse(dataValue); @@ -1545,20 +1526,27 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { const converted = this.convertKnownMimes(type, kind, dataValue); treeDataTransfer.setString(converted.type, converted.value + ''); } - decrementStringCount(); - }); - } else if (dataItem.kind === 'file') { - const dataValue = dataItem.getAsFile(); - if (dataValue) { - uris.push(URI.file(dataValue.path)); + resolve(); + })); + } else if (dataItem.kind === 'file') { + const file = dataItem.getAsFile(); + if (file) { + uris.push(URI.file(file.path)); + const uri = (file as FileAdditionalNativeProperties).path ? URI.parse((file as FileAdditionalNativeProperties).path!) : undefined; + if (dndController.supportsFileDataTransfers) { + treeDataTransfer.setFile(type, file.name, uri, async () => { + return new Uint8Array(await file.arrayBuffer()); + }); } - decrementStringCount(); } - } else if (dataItem.kind === 'string' || dataItem.kind === 'file') { - decrementStringCount(); } } - }); + })); + + // Check if there are uris to add and add them + if (uris.length) { + treeDataTransfer.setString(Mimes.uriList, uris.map(uri => uri.toString()).join('\n')); + } const additionalWillDropPromise = this.treeViewsDragAndDropService.removeDragOperationTransfer(willDropUuid); if (!additionalWillDropPromise) { diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index 80be8b96724..20f83615cab 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -51,6 +51,7 @@ export interface IViewPaneOptions extends IPaneOptions { } type WelcomeActionClassification = { + owner: 'sandy081'; viewId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; uri: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index be75bf31cd1..0ff11494826 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -821,6 +821,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { if (this.viewContainerModel.activeViewDescriptors.some(viewDescriptor => viewDescriptor.id === viewId)) { const visible = !this.viewContainerModel.isVisible(viewId); type ViewsToggleVisibilityClassification = { + owner: 'sandy081'; viewId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; visible: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index ac9b39c0c21..a255a45c0e2 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -831,6 +831,7 @@ export interface ITreeViewDataProvider { export interface ITreeViewDragAndDropController { readonly dropMimeTypes: string[]; readonly dragMimeTypes: string[]; + readonly supportsFileDataTransfers: boolean; handleDrag(sourceTreeItemHandles: string[], operationUuid: string, token: CancellationToken): Promise; handleDrop(elements: VSDataTransfer, target: ITreeItem | undefined, token: CancellationToken, operationUuid?: string, sourceTreeId?: string, sourceTreeItemHandles?: string[]): Promise; } diff --git a/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts b/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts index 4667fc38a3e..8f4255fb1d2 100644 --- a/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts +++ b/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import severity from 'vs/base/common/severity'; import { Event } from 'vs/base/common/event'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; +import { Markers } from 'vs/workbench/contrib/markers/common/markers'; import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; @@ -76,7 +76,7 @@ export class DebugTaskRunner { return TaskRunResult.Success; } if (onTaskErrors === 'showErrors') { - await this.viewsService.openView(Constants.MARKERS_VIEW_ID, true); + await this.viewsService.openView(Markers.MARKERS_VIEW_ID, true); return Promise.resolve(TaskRunResult.Failure); } if (onTaskErrors === 'abort') { @@ -113,7 +113,7 @@ export class DebugTaskRunner { return TaskRunResult.Success; } - await this.viewsService.openView(Constants.MARKERS_VIEW_ID, true); + await this.viewsService.openView(Markers.MARKERS_VIEW_ID, true); return Promise.resolve(TaskRunResult.Failure); } catch (err) { const taskConfigureAction = this.taskService.configureAction(); diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index 677b8c86440..01aac2fa0b6 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -541,6 +541,7 @@ CommandsRegistry.registerCommand({ if (ext || await tryInstallHexEditor(notifications, progressService, extensionService, commandService)) { /* __GDPR__ "debug/didViewMemory" : { + "owner": "connor4312", "debugType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ diff --git a/src/vs/workbench/contrib/debug/common/debugTelemetry.ts b/src/vs/workbench/contrib/debug/common/debugTelemetry.ts index a68ce7e798e..a39c0651c55 100644 --- a/src/vs/workbench/contrib/debug/common/debugTelemetry.ts +++ b/src/vs/workbench/contrib/debug/common/debugTelemetry.ts @@ -18,6 +18,7 @@ export class DebugTelemetry { const extension = dbgr.getMainExtensionDescriptor(); /* __GDPR__ "debugSessionStart" : { + "owner": "connor4312", "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "breakpointCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "exceptionBreakpoints": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -44,6 +45,7 @@ export class DebugTelemetry { /* __GDPR__ "debugSessionStop" : { + "owner": "connor4312", "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "success": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "sessionLengthInSeconds": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 0770dbb143e..07741ba7717 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -306,6 +306,7 @@ export class ExperimentService extends Disposable implements IExperimentService const promises = rawExperiments.map(experiment => this.evaluateExperiment(experiment)); return Promise.all(promises).then(() => { type ExperimentsClassification = { + owner: 'sbatten'; experiments: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this.telemetryService.publicLog2<{ experiments: string[] }, ExperimentsClassification>('experiments', { experiments: this._experiments.map(e => e.id) }); diff --git a/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts index f287d1ebe38..28a22fa7191 100644 --- a/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts +++ b/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts @@ -16,6 +16,7 @@ import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionRe import { localize } from 'vs/nls'; type DynamicWorkspaceRecommendationsClassification = { + owner: 'sandy081'; count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; cache: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index eb5589276f2..c0c3e368540 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -562,6 +562,7 @@ export class ExtensionEditor extends EditorPane { } /* __GDPR__ "extensionGallery:openExtension" : { + "owner": "sandy081", "recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "${include}": [ "${GalleryExtensionTelemetryData}" @@ -644,6 +645,7 @@ export class ExtensionEditor extends EditorPane { private setRecommendationText(extension: IExtension, template: IExtensionEditorTemplate): void { const updateRecommendationText = (layout: boolean) => { + reset(template.recommendation); const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason(); if (extRecommendations[extension.identifier.id.toLowerCase()]) { const reasonText = extRecommendations[extension.identifier.id.toLowerCase()].reasonText; @@ -658,8 +660,8 @@ export class ExtensionEditor extends EditorPane { this.layout(this.dimension); } }; - reset(template.recommendation); if (extension.deprecationInfo || extension.state === ExtensionState.Installed) { + reset(template.recommendation); return; } updateRecommendationText(false); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts index 4e95edf7f9e..dc5bbff9180 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts @@ -27,12 +27,14 @@ import { EnablementState, IWorkbenchExtensionManagementService, IWorkbenchExtens import { IExtensionIgnoredRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; type ExtensionRecommendationsNotificationClassification = { + owner: 'sandy081'; userReaction: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; extensionId?: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; type ExtensionWorkspaceRecommendationsNotificationClassification = { + owner: 'sandy081'; userReaction: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts index 26e23dad630..de0d081513a 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts @@ -29,6 +29,7 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/com import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; type IgnoreRecommendationClassification = { + owner: 'sandy081'; recommendationReason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; extensionId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; }; @@ -233,6 +234,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte if (recommendationReason) { /* __GDPR__ "extensionGallery:install:recommendations" : { + "owner": "sandy081", "recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "${include}": [ "${GalleryExtensionTelemetryData}" diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 9b5c1397ee4..d61e4518b9b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { Event } from 'vs/base/common/event'; import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtension } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions'; @@ -118,6 +118,7 @@ export class Renderer implements IPagedRenderer { const reloadAction = this.instantiationService.createInstance(ReloadAction); const actions = [ this.instantiationService.createInstance(ExtensionStatusLabelAction), + this.instantiationService.createInstance(MigrateDeprecatedExtension, true), this.instantiationService.createInstance(UpdateAction), reloadAction, this.instantiationService.createInstance(InstallDropdownAction), diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index de628c54a8d..31424b2285a 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -61,6 +61,7 @@ import { isOfflineError } from 'vs/base/parts/request/common/request'; const FORCE_FEATURE_EXTENSIONS = ['vscode.git', 'vscode.git-base', 'vscode.search-result']; type WorkspaceRecommendationsClassification = { + owner: 'sandy081'; count: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; 'isMeasurement': true }; }; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index ece35b058d1..0bc773af868 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -57,6 +57,7 @@ interface InstalledExtensionsEvent { readonly count: number; } interface ExtensionsLoadClassification extends GDPRClassification { + owner: 'digitarald'; readonly extensionIds: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; readonly count: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; } @@ -1454,6 +1455,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (changed[i]) { /* __GDPR__ "extension:enable" : { + "owner": "sandy081", "${include}": [ "${GalleryExtensionTelemetryData}" ] @@ -1461,6 +1463,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension */ /* __GDPR__ "extension:disable" : { + "owner": "sandy081", "${include}": [ "${GalleryExtensionTelemetryData}" ] diff --git a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts index b81342b1bb9..26527cd7d68 100644 --- a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts +++ b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts @@ -37,6 +37,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; type FileExtensionSuggestionClassification = { + owner: 'sandy081'; userReaction: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; fileExtension: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts similarity index 55% rename from src/vs/workbench/contrib/localizations/browser/localizationsActions.ts rename to src/vs/workbench/contrib/localization/browser/localizationsActions.ts index 5384fc3e0b0..afebaf8f1e1 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts +++ b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Action } from 'vs/base/common/actions'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { IHostService } from 'vs/workbench/services/host/browser/host'; @@ -17,27 +16,22 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IProductService } from 'vs/platform/product/common/productService'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { ViewContainerLocation } from 'vs/workbench/common/views'; +import { Action2, MenuId } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -export class ConfigureLocaleAction extends Action { - public static readonly ID = 'workbench.action.configureLocale'; - public static readonly LABEL = localize('configureLocale', "Configure Display Language"); - - constructor(id: string, label: string, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILocalizationsService private readonly localizationService: ILocalizationsService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, - @IHostService private readonly hostService: IHostService, - @INotificationService private readonly notificationService: INotificationService, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, - @IDialogService private readonly dialogService: IDialogService, - @IProductService private readonly productService: IProductService - ) { - super(id, label); +export class ConfigureLocaleAction extends Action2 { + constructor() { + super({ + id: 'workbench.action.configureLocale', + title: { original: 'Configure Display Language', value: localize('configureLocale', "Configure Display Language") }, + menu: { + id: MenuId.CommandPalette + } + }); } - private async getLanguageOptions(): Promise { - const availableLanguages = await this.localizationService.getLanguageIds(); + private async getLanguageOptions(localizationService: ILanguagePackService): Promise { + const availableLanguages = await localizationService.getInstalledLanguages(); availableLanguages.sort(); return availableLanguages @@ -45,12 +39,22 @@ export class ConfigureLocaleAction extends Action { .concat({ label: localize('installAdditionalLanguages', "Install Additional Languages...") }); } - public override async run(): Promise { - const languageOptions = await this.getLanguageOptions(); + public override async run(accessor: ServicesAccessor): Promise { + const environmentService: IEnvironmentService = accessor.get(IEnvironmentService); + const languagePackService: ILanguagePackService = accessor.get(ILanguagePackService); + const quickInputService: IQuickInputService = accessor.get(IQuickInputService); + const jsonEditingService: IJSONEditingService = accessor.get(IJSONEditingService); + const hostService: IHostService = accessor.get(IHostService); + const notificationService: INotificationService = accessor.get(INotificationService); + const paneCompositeService: IPaneCompositePartService = accessor.get(IPaneCompositePartService); + const dialogService: IDialogService = accessor.get(IDialogService); + const productService: IProductService = accessor.get(IProductService); + + const languageOptions = await this.getLanguageOptions(languagePackService); const currentLanguageIndex = languageOptions.findIndex(l => l.label === language); try { - const selectedLanguage = await this.quickInputService.pick(languageOptions, + const selectedLanguage = await quickInputService.pick(languageOptions, { canPickMany: false, placeHolder: localize('chooseDisplayLanguage', "Select Display Language"), @@ -58,7 +62,7 @@ export class ConfigureLocaleAction extends Action { }); if (selectedLanguage === languageOptions[languageOptions.length - 1]) { - return this.paneCompositeService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar, true) + return paneCompositeService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar, true) .then(viewlet => viewlet?.getViewPaneContainer()) .then(viewlet => { const extensionsViewlet = viewlet as IExtensionsViewPaneContainer; @@ -68,20 +72,20 @@ export class ConfigureLocaleAction extends Action { } if (selectedLanguage) { - await this.jsonEditingService.write(this.environmentService.argvResource, [{ path: ['locale'], value: selectedLanguage.label }], true); - const restart = await this.dialogService.confirm({ + await jsonEditingService.write(environmentService.argvResource, [{ path: ['locale'], value: selectedLanguage.label }], true); + const restart = await dialogService.confirm({ type: 'info', message: localize('relaunchDisplayLanguageMessage', "A restart is required for the change in display language to take effect."), - detail: localize('relaunchDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", this.productService.nameLong), + detail: localize('relaunchDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", productService.nameLong), primaryButton: localize('restart', "&&Restart") }); if (restart.confirmed) { - this.hostService.restart(); + hostService.restart(); } } } catch (e) { - this.notificationService.error(e); + notificationService.error(e); } } } diff --git a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts similarity index 96% rename from src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts rename to src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts index 92c5e9c0348..c725565a55d 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localization/electron-sandbox/localization.contribution.ts @@ -6,10 +6,7 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ConfigureLocaleAction } from 'vs/workbench/contrib/localizations/browser/localizationsActions'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import * as platform from 'vs/base/common/platform'; @@ -21,15 +18,16 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { VIEWLET_ID as EXTENSIONS_VIEWLET_ID, IExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/common/extensions'; -import { minimumTranslatedStrings } from 'vs/workbench/contrib/localizations/browser/minimalTranslations'; +import { minimumTranslatedStrings } from 'vs/workbench/contrib/localization/electron-sandbox/minimalTranslations'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { ViewContainerLocation } from 'vs/workbench/common/views'; +import { registerAction2 } from 'vs/platform/actions/common/actions'; +import { ConfigureLocaleAction } from 'vs/workbench/contrib/localization/browser/localizationsActions'; // Register action to configure locale and related settings -const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ConfigureLocaleAction), 'Configure Display Language'); +registerAction2(ConfigureLocaleAction); const LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY = 'extensionsAssistant/languagePackSuggestionIgnore'; @@ -119,7 +117,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo const loc = manifest && manifest.contributes && manifest.contributes.localizations && manifest.contributes.localizations.filter(x => x.languageId.toLowerCase() === locale)[0]; const languageName = loc ? (loc.languageName || locale) : locale; const languageDisplayName = loc ? (loc.localizedLanguageName || loc.languageName || locale) : locale; - const translationsFromPack: any = translation && translation.contents ? translation.contents['vs/workbench/contrib/localizations/browser/minimalTranslations'] : {}; + const translationsFromPack: any = translation && translation.contents ? translation.contents['vs/workbench/contrib/localization/electron-sandbox/minimalTranslations'] : {}; const promptMessageKey = extensionToInstall ? 'installAndRestartMessage' : 'showLanguagePackExtensions'; const useEnglish = !translationsFromPack[promptMessageKey]; @@ -135,6 +133,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo const logUserReaction = (userReaction: string) => { /* __GDPR__ "languagePackSuggestion:popup" : { + "owner": "TylerLeonhardt", "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "language": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } diff --git a/src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts b/src/vs/workbench/contrib/localization/electron-sandbox/minimalTranslations.ts similarity index 100% rename from src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts rename to src/vs/workbench/contrib/localization/electron-sandbox/minimalTranslations.ts diff --git a/src/vs/workbench/contrib/markers/browser/constants.ts b/src/vs/workbench/contrib/markers/browser/constants.ts deleted file mode 100644 index a883b3bf148..00000000000 --- a/src/vs/workbench/contrib/markers/browser/constants.ts +++ /dev/null @@ -1,33 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { MarkersViewMode } from 'vs/workbench/contrib/markers/browser/markersView'; - -export default { - MARKERS_CONTAINER_ID: 'workbench.panel.markers', - MARKERS_VIEW_ID: 'workbench.panel.markers.view', - MARKERS_VIEW_STORAGE_ID: 'workbench.panel.markers', - MARKER_COPY_ACTION_ID: 'problems.action.copy', - MARKER_COPY_MESSAGE_ACTION_ID: 'problems.action.copyMessage', - RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID: 'problems.action.copyRelatedInformationMessage', - FOCUS_PROBLEMS_FROM_FILTER: 'problems.action.focusProblemsFromFilter', - MARKERS_VIEW_FOCUS_FILTER: 'problems.action.focusFilter', - MARKERS_VIEW_CLEAR_FILTER_TEXT: 'problems.action.clearFilterText', - MARKERS_VIEW_SHOW_MULTILINE_MESSAGE: 'problems.action.showMultilineMessage', - MARKERS_VIEW_SHOW_SINGLELINE_MESSAGE: 'problems.action.showSinglelineMessage', - MARKER_OPEN_ACTION_ID: 'problems.action.open', - MARKER_OPEN_SIDE_ACTION_ID: 'problems.action.openToSide', - MARKER_SHOW_PANEL_ID: 'workbench.action.showErrorsWarnings', - MARKER_SHOW_QUICK_FIX: 'problems.action.showQuickFixes', - TOGGLE_MARKERS_VIEW_ACTION_ID: 'workbench.actions.view.toggleProblems', - - MarkersViewModeContextKey: new RawContextKey('problemsViewMode', MarkersViewMode.Tree), - MarkersViewSmallLayoutContextKey: new RawContextKey(`problemsView.smallLayout`, false), - MarkersTreeVisibilityContextKey: new RawContextKey('problemsVisibility', false), - MarkerFocusContextKey: new RawContextKey('problemFocus', false), - MarkerViewFilterFocusContextKey: new RawContextKey('problemsFilterFocus', false), - RelatedInformationFocusContextKey: new RawContextKey('relatedInformationFocus', false) -}; diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index ffd15324657..66e8b574bc6 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -11,16 +11,16 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { localize } from 'vs/nls'; import { Marker, RelatedInformation, ResourceMarkers } from 'vs/workbench/contrib/markers/browser/markersModel'; -import { MarkersView, MarkersViewMode } from 'vs/workbench/contrib/markers/browser/markersView'; +import { MarkersView } from 'vs/workbench/contrib/markers/browser/markersView'; import { MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; +import { MarkersViewMode, Markers, MarkersContextKeys } from 'vs/workbench/contrib/markers/common/markers'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { ActivityUpdater, IMarkersView } from 'vs/workbench/contrib/markers/browser/markers'; +import { IMarkersView } from 'vs/workbench/contrib/markers/browser/markers'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/browser/statusbar'; import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewsRegistry, IViewsService } from 'vs/workbench/common/views'; @@ -31,53 +31,54 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: Constants.MARKER_OPEN_ACTION_ID, + id: Markers.MARKER_OPEN_ACTION_ID, weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(Constants.MarkerFocusContextKey), + when: ContextKeyExpr.and(MarkersContextKeys.MarkerFocusContextKey), primary: KeyCode.Enter, mac: { primary: KeyCode.Enter, secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow] }, handler: (accessor, args: any) => { - const markersView = accessor.get(IViewsService).getActiveViewWithId(Constants.MARKERS_VIEW_ID)!; + const markersView = accessor.get(IViewsService).getActiveViewWithId(Markers.MARKERS_VIEW_ID)!; markersView.openFileAtElement(markersView.getFocusElement(), false, false, true); } }); KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: Constants.MARKER_OPEN_SIDE_ACTION_ID, + id: Markers.MARKER_OPEN_SIDE_ACTION_ID, weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(Constants.MarkerFocusContextKey), + when: ContextKeyExpr.and(MarkersContextKeys.MarkerFocusContextKey), primary: KeyMod.CtrlCmd | KeyCode.Enter, mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, handler: (accessor, args: any) => { - const markersView = accessor.get(IViewsService).getActiveViewWithId(Constants.MARKERS_VIEW_ID)!; + const markersView = accessor.get(IViewsService).getActiveViewWithId(Markers.MARKERS_VIEW_ID)!; markersView.openFileAtElement(markersView.getFocusElement(), false, true, true); } }); KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: Constants.MARKER_SHOW_PANEL_ID, + id: Markers.MARKER_SHOW_PANEL_ID, weight: KeybindingWeight.WorkbenchContrib, when: undefined, primary: undefined, handler: async (accessor, args: any) => { - await accessor.get(IViewsService).openView(Constants.MARKERS_VIEW_ID); + await accessor.get(IViewsService).openView(Markers.MARKERS_VIEW_ID); } }); KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: Constants.MARKER_SHOW_QUICK_FIX, + id: Markers.MARKER_SHOW_QUICK_FIX, weight: KeybindingWeight.WorkbenchContrib, - when: Constants.MarkerFocusContextKey, + when: MarkersContextKeys.MarkerFocusContextKey, primary: KeyMod.CtrlCmd | KeyCode.Period, handler: (accessor, args: any) => { - const markersView = accessor.get(IViewsService).getActiveViewWithId(Constants.MARKERS_VIEW_ID)!; + const markersView = accessor.get(IViewsService).getActiveViewWithId(Markers.MARKERS_VIEW_ID)!; const focusedElement = markersView.getFocusElement(); if (focusedElement instanceof Marker) { markersView.showQuickFixes(focusedElement); @@ -125,17 +126,17 @@ const markersViewIcon = registerIcon('markers-view-icon', Codicon.warning, local // markers view container const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ - id: Constants.MARKERS_CONTAINER_ID, + id: Markers.MARKERS_CONTAINER_ID, title: Messages.MARKERS_PANEL_TITLE_PROBLEMS, icon: markersViewIcon, hideIfEmpty: true, order: 0, - ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [Constants.MARKERS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), - storageId: Constants.MARKERS_VIEW_STORAGE_ID, + ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [Markers.MARKERS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]), + storageId: Markers.MARKERS_VIEW_STORAGE_ID, }, ViewContainerLocation.Panel, { donotRegisterOpenCommand: true }); Registry.as(ViewContainerExtensions.ViewsRegistry).registerViews([{ - id: Constants.MARKERS_VIEW_ID, + id: Markers.MARKERS_VIEW_ID, containerIcon: markersViewIcon, name: Messages.MARKERS_PANEL_TITLE_PROBLEMS, canToggleVisibility: false, @@ -151,22 +152,21 @@ Registry.as(ViewContainerExtensions.ViewsRegistry).registerViews // workbench const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ActivityUpdater, LifecyclePhase.Restored); // actions registerAction2(class extends ViewAction { constructor() { super({ - id: `workbench.actions.table.${Constants.MARKERS_VIEW_ID}.viewAsTree`, + id: `workbench.actions.table.${Markers.MARKERS_VIEW_ID}.viewAsTree`, title: localize('viewAsTree', "View as Tree"), menu: { id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Constants.MARKERS_VIEW_ID), Constants.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Table)), + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Table)), group: 'navigation', order: 3 }, icon: Codicon.listTree, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } @@ -178,16 +178,16 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: `workbench.actions.table.${Constants.MARKERS_VIEW_ID}.viewAsTable`, + id: `workbench.actions.table.${Markers.MARKERS_VIEW_ID}.viewAsTable`, title: localize('viewAsTable', "View as Table"), menu: { id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Constants.MARKERS_VIEW_ID), Constants.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Tree)), + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Tree)), group: 'navigation', order: 3 }, icon: Codicon.listFlat, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } @@ -206,15 +206,15 @@ registerAction2(class extends Action2 { }); } async run(accessor: ServicesAccessor): Promise { - accessor.get(IViewsService).openView(Constants.MARKERS_VIEW_ID, true); + accessor.get(IViewsService).openView(Markers.MARKERS_VIEW_ID, true); } }); registerAction2(class extends ViewAction { constructor() { - const when = ContextKeyExpr.and(FocusedViewContext.isEqualTo(Constants.MARKERS_VIEW_ID), Constants.MarkersTreeVisibilityContextKey, Constants.RelatedInformationFocusContextKey.toNegated()); + const when = ContextKeyExpr.and(FocusedViewContext.isEqualTo(Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersTreeVisibilityContextKey, MarkersContextKeys.RelatedInformationFocusContextKey.toNegated()); super({ - id: Constants.MARKER_COPY_ACTION_ID, + id: Markers.MARKER_COPY_ACTION_ID, title: { value: localize('copyMarker', "Copy"), original: 'Copy' }, menu: { id: MenuId.ProblemsPanelContext, @@ -226,7 +226,7 @@ registerAction2(class extends ViewAction { primary: KeyMod.CtrlCmd | KeyCode.KeyC, when }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -254,14 +254,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.MARKER_COPY_MESSAGE_ACTION_ID, + id: Markers.MARKER_COPY_MESSAGE_ACTION_ID, title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, menu: { id: MenuId.ProblemsPanelContext, - when: Constants.MarkerFocusContextKey, + when: MarkersContextKeys.MarkerFocusContextKey, group: 'navigation' }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -276,14 +276,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID, + id: Markers.RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID, title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, menu: { id: MenuId.ProblemsPanelContext, - when: Constants.RelatedInformationFocusContextKey, + when: MarkersContextKeys.RelatedInformationFocusContextKey, group: 'navigation' }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -298,14 +298,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.FOCUS_PROBLEMS_FROM_FILTER, + id: Markers.FOCUS_PROBLEMS_FROM_FILTER, title: localize('focusProblemsList', "Focus problems view"), keybinding: { - when: Constants.MarkerViewFilterFocusContextKey, + when: MarkersContextKeys.MarkerViewFilterFocusContextKey, weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.CtrlCmd | KeyCode.DownArrow }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -316,14 +316,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.MARKERS_VIEW_FOCUS_FILTER, + id: Markers.MARKERS_VIEW_FOCUS_FILTER, title: localize('focusProblemsFilter', "Focus problems filter"), keybinding: { - when: FocusedViewContext.isEqualTo(Constants.MARKERS_VIEW_ID), + when: FocusedViewContext.isEqualTo(Markers.MARKERS_VIEW_ID), weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.CtrlCmd | KeyCode.KeyF }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -334,14 +334,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.MARKERS_VIEW_SHOW_MULTILINE_MESSAGE, + id: Markers.MARKERS_VIEW_SHOW_MULTILINE_MESSAGE, title: { value: localize('show multiline', "Show message in multiple lines"), original: 'Problems: Show message in multiple lines' }, category: localize('problems', "Problems"), menu: { id: MenuId.CommandPalette, - when: ContextKeyExpr.has(getVisbileViewContextKey(Constants.MARKERS_VIEW_ID)) + when: ContextKeyExpr.has(getVisbileViewContextKey(Markers.MARKERS_VIEW_ID)) }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -352,14 +352,14 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.MARKERS_VIEW_SHOW_SINGLELINE_MESSAGE, + id: Markers.MARKERS_VIEW_SHOW_SINGLELINE_MESSAGE, title: { value: localize('show singleline', "Show message in single line"), original: 'Problems: Show message in single line' }, category: localize('problems', "Problems"), menu: { id: MenuId.CommandPalette, - when: ContextKeyExpr.has(getVisbileViewContextKey(Constants.MARKERS_VIEW_ID)) + when: ContextKeyExpr.has(getVisbileViewContextKey(Markers.MARKERS_VIEW_ID)) }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -370,15 +370,15 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: Constants.MARKERS_VIEW_CLEAR_FILTER_TEXT, + id: Markers.MARKERS_VIEW_CLEAR_FILTER_TEXT, title: localize('clearFiltersText', "Clear filters text"), category: localize('problems', "Problems"), keybinding: { - when: Constants.MarkerViewFilterFocusContextKey, + when: MarkersContextKeys.MarkerViewFilterFocusContextKey, weight: KeybindingWeight.WorkbenchContrib, primary: KeyCode.Escape }, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, markersView: IMarkersView): Promise { @@ -389,16 +389,16 @@ registerAction2(class extends ViewAction { registerAction2(class extends ViewAction { constructor() { super({ - id: `workbench.actions.treeView.${Constants.MARKERS_VIEW_ID}.collapseAll`, + id: `workbench.actions.treeView.${Markers.MARKERS_VIEW_ID}.collapseAll`, title: localize('collapseAll', "Collapse All"), menu: { id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Constants.MARKERS_VIEW_ID), Constants.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Tree)), + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersViewModeContextKey.isEqualTo(MarkersViewMode.Tree)), group: 'navigation', order: 2, }, icon: Codicon.collapseAll, - viewId: Constants.MARKERS_VIEW_ID + viewId: Markers.MARKERS_VIEW_ID }); } async runInView(serviceAccessor: ServicesAccessor, view: IMarkersView): Promise { @@ -409,11 +409,11 @@ registerAction2(class extends ViewAction { registerAction2(class extends Action2 { constructor() { super({ - id: `workbench.actions.treeView.${Constants.MARKERS_VIEW_ID}.filter`, + id: `workbench.actions.treeView.${Markers.MARKERS_VIEW_ID}.filter`, title: localize('filter', "Filter"), menu: { id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Constants.MARKERS_VIEW_ID), Constants.MarkersViewSmallLayoutContextKey.negate()), + when: ContextKeyExpr.and(ContextKeyExpr.equals('view', Markers.MARKERS_VIEW_ID), MarkersContextKeys.MarkersViewSmallLayoutContextKey.negate()), group: 'navigation', order: 1, }, @@ -425,16 +425,16 @@ registerAction2(class extends Action2 { registerAction2(class extends Action2 { constructor() { super({ - id: Constants.TOGGLE_MARKERS_VIEW_ACTION_ID, + id: Markers.TOGGLE_MARKERS_VIEW_ACTION_ID, title: Messages.MARKERS_PANEL_TOGGLE_LABEL, }); } async run(accessor: ServicesAccessor): Promise { const viewsService = accessor.get(IViewsService); - if (viewsService.isViewVisible(Constants.MARKERS_VIEW_ID)) { - viewsService.closeView(Constants.MARKERS_VIEW_ID); + if (viewsService.isViewVisible(Markers.MARKERS_VIEW_ID)) { + viewsService.closeView(Markers.MARKERS_VIEW_ID); } else { - viewsService.openView(Constants.MARKERS_VIEW_ID, true); + viewsService.openView(Markers.MARKERS_VIEW_ID, true); } } }); @@ -514,3 +514,26 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont } workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); + +class ActivityUpdater extends Disposable implements IWorkbenchContribution { + + private readonly activity = this._register(new MutableDisposable()); + + constructor( + @IActivityService private readonly activityService: IActivityService, + @IMarkerService private readonly markerService: IMarkerService + ) { + super(); + this._register(this.markerService.onMarkerChanged(() => this.updateBadge())); + this.updateBadge(); + } + + private updateBadge(): void { + const { errors, warnings, infos } = this.markerService.getStatistics(); + const total = errors + warnings + infos; + const message = localize('totalProblems', 'Total {0} Problems', total); + this.activity.value = this.activityService.showViewActivity(Markers.MARKERS_VIEW_ID, { badge: new NumberBadge(total, () => message) }); + } +} + +workbenchRegistry.registerWorkbenchContribution(ActivityUpdater, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts index c65df45418a..0969177554d 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.ts @@ -3,17 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, MutableDisposable, IDisposable } from 'vs/base/common/lifecycle'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { localize } from 'vs/nls'; -import Constants from './constants'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { MarkersFilters } from 'vs/workbench/contrib/markers/browser/markersViewActions'; import { Event } from 'vs/base/common/event'; import { IView } from 'vs/workbench/common/views'; import { MarkerElement, ResourceMarkers } from 'vs/workbench/contrib/markers/browser/markersModel'; -import { MarkersViewMode } from 'vs/workbench/contrib/markers/browser/markersView'; +import { MarkersViewMode } from 'vs/workbench/contrib/markers/common/markers'; export interface IMarkersView extends IView { @@ -33,24 +27,3 @@ export interface IMarkersView extends IView { setMultiline(multiline: boolean): void; setViewMode(viewMode: MarkersViewMode): void; } - -export class ActivityUpdater extends Disposable implements IWorkbenchContribution { - - private readonly activity = this._register(new MutableDisposable()); - - constructor( - @IActivityService private readonly activityService: IActivityService, - @IMarkerService private readonly markerService: IMarkerService - ) { - super(); - this._register(this.markerService.onMarkerChanged(() => this.updateBadge())); - this.updateBadge(); - } - - private updateBadge(): void { - const { errors, warnings, infos } = this.markerService.getStatistics(); - const total = errors + warnings + infos; - const message = localize('totalProblems', 'Total {0} Problems', total); - this.activity.value = this.activityService.showViewActivity(Constants.MARKERS_VIEW_ID, { badge: new NumberBadge(total, () => message) }); - } -} diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index f6e04799b34..92a2abd857b 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -48,9 +48,8 @@ import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Link } from 'vs/platform/opener/browser/link'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; -import { MarkersViewMode } from 'vs/workbench/contrib/markers/browser/markersView'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; +import { MarkersContextKeys, MarkersViewMode } from 'vs/workbench/contrib/markers/common/markers'; interface IResourceMarkersTemplateData { resourceLabel: IResourceLabel; @@ -718,7 +717,7 @@ export class MarkersViewModel extends Disposable { this._multiline = multiline; this._viewMode = viewMode; - this.viewModeContextKey = Constants.MarkersViewModeContextKey.bindTo(this.contextKeyService); + this.viewModeContextKey = MarkersContextKeys.MarkersViewModeContextKey.bindTo(this.contextKeyService); this.viewModeContextKey.set(viewMode); } diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index b20df6c492a..b3cdba4c228 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -10,7 +10,6 @@ import * as dom from 'vs/base/browser/dom'; import { IAction, Action, Separator } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { Marker, ResourceMarkers, RelatedInformation, MarkerChangesEvent, MarkersModel, compareMarkersByUri, MarkerElement, MarkerTableItem } from 'vs/workbench/contrib/markers/browser/markersModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MarkersFilterActionViewItem, MarkersFilters, IMarkersFiltersChangeEvent } from 'vs/workbench/contrib/markers/browser/markersViewActions'; @@ -59,6 +58,7 @@ import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/m import { ResourceListDnDHandler } from 'vs/workbench/browser/dnd'; import { ITableContextMenuEvent, ITableEvent } from 'vs/base/browser/ui/table/table'; import { MarkersTable } from 'vs/workbench/contrib/markers/browser/markersTable'; +import { Markers, MarkersContextKeys, MarkersViewMode } from 'vs/workbench/contrib/markers/common/markers'; function createResourceMarkersIterator(resourceMarkers: ResourceMarkers): Iterable> { return Iterable.map(resourceMarkers.markers, m => { @@ -69,11 +69,6 @@ function createResourceMarkersIterator(resourceMarkers: ResourceMarkers): Iterab }); } -export const enum MarkersViewMode { - Table = 'table', - Tree = 'tree' -} - export interface IProblemsWidget { get contextKeyService(): IContextKeyService; @@ -162,8 +157,8 @@ export class MarkersView extends ViewPane implements IMarkersView { @IThemeService themeService: IThemeService, ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); - this.smallLayoutContextKey = Constants.MarkersViewSmallLayoutContextKey.bindTo(this.contextKeyService); - this.panelState = new Memento(Constants.MARKERS_VIEW_STORAGE_ID, storageService).getMemento(StorageScope.WORKSPACE, StorageTarget.USER); + this.smallLayoutContextKey = MarkersContextKeys.MarkersViewSmallLayoutContextKey.bindTo(this.contextKeyService); + this.panelState = new Memento(Markers.MARKERS_VIEW_STORAGE_ID, storageService).getMemento(StorageScope.WORKSPACE, StorageTarget.USER); this.markersModel = this._register(instantiationService.createInstance(MarkersModel)); this.markersViewModel = this._register(instantiationService.createInstance(MarkersViewModel, this.panelState['multiline'], this.panelState['viewMode'] ?? this.getDefaultViewMode())); @@ -419,8 +414,8 @@ export class MarkersView extends ViewPane implements IMarkersView { this.widget = this.markersViewModel.viewMode === MarkersViewMode.Table ? this.createTable(parent) : this.createTree(parent); this.widgetDisposables.add(this.widget); - const markerFocusContextKey = Constants.MarkerFocusContextKey.bindTo(this.widget.contextKeyService); - const relatedInformationFocusContextKey = Constants.RelatedInformationFocusContextKey.bindTo(this.widget.contextKeyService); + const markerFocusContextKey = MarkersContextKeys.MarkerFocusContextKey.bindTo(this.widget.contextKeyService); + const relatedInformationFocusContextKey = MarkersContextKeys.RelatedInformationFocusContextKey.bindTo(this.widget.contextKeyService); this.widgetDisposables.add(this.widget.onDidChangeFocus(focus => { markerFocusContextKey.set(focus.elements.some(e => e instanceof Marker)); relatedInformationFocusContextKey.set(focus.elements.some(e => e instanceof RelatedInformation)); @@ -915,7 +910,7 @@ class MarkersTree extends WorkbenchObjectTree impleme @IAccessibilityService accessibilityService: IAccessibilityService ) { super(user, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService, accessibilityService); - this.visibilityContextKey = Constants.MarkersTreeVisibilityContextKey.bindTo(contextKeyService); + this.visibilityContextKey = MarkersContextKeys.MarkersTreeVisibilityContextKey.bindTo(contextKeyService); } collapseMarkers(): void { diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index 63dc3458879..a8857968647 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -11,7 +11,6 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { IThemeService, registerThemingParticipant, ICssStyleCollector, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { toDisposable, Disposable } from 'vs/base/common/lifecycle'; @@ -31,6 +30,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { IMarkersView } from 'vs/workbench/contrib/markers/browser/markers'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; +import { MarkersContextKeys } from 'vs/workbench/contrib/markers/common/markers'; export interface IMarkersFiltersChangeEvent { filterText?: boolean; @@ -260,7 +260,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { ) { super(null, action); this.keybindingService = keybindingService; - this.focusContextKey = Constants.MarkerViewFilterFocusContextKey.bindTo(contextKeyService); + this.focusContextKey = MarkersContextKeys.MarkerViewFilterFocusContextKey.bindTo(contextKeyService); this.delayedFilterUpdate = new Delayer(400); this._register(toDisposable(() => this.delayedFilterUpdate.cancel())); this._register(markersView.onDidFocusFilter(() => this.focus())); diff --git a/src/vs/workbench/contrib/markers/common/markers.ts b/src/vs/workbench/contrib/markers/common/markers.ts new file mode 100644 index 00000000000..6f3efbbeec6 --- /dev/null +++ b/src/vs/workbench/contrib/markers/common/markers.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; + +export const enum MarkersViewMode { + Table = 'table', + Tree = 'tree' +} + +export namespace Markers { + export const MARKERS_CONTAINER_ID = 'workbench.panel.markers'; + export const MARKERS_VIEW_ID = 'workbench.panel.markers.view'; + export const MARKERS_VIEW_STORAGE_ID = 'workbench.panel.markers'; + export const MARKER_COPY_ACTION_ID = 'problems.action.copy'; + export const MARKER_COPY_MESSAGE_ACTION_ID = 'problems.action.copyMessage'; + export const RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID = 'problems.action.copyRelatedInformationMessage'; + export const FOCUS_PROBLEMS_FROM_FILTER = 'problems.action.focusProblemsFromFilter'; + export const MARKERS_VIEW_FOCUS_FILTER = 'problems.action.focusFilter'; + export const MARKERS_VIEW_CLEAR_FILTER_TEXT = 'problems.action.clearFilterText'; + export const MARKERS_VIEW_SHOW_MULTILINE_MESSAGE = 'problems.action.showMultilineMessage'; + export const MARKERS_VIEW_SHOW_SINGLELINE_MESSAGE = 'problems.action.showSinglelineMessage'; + export const MARKER_OPEN_ACTION_ID = 'problems.action.open'; + export const MARKER_OPEN_SIDE_ACTION_ID = 'problems.action.openToSide'; + export const MARKER_SHOW_PANEL_ID = 'workbench.action.showErrorsWarnings'; + export const MARKER_SHOW_QUICK_FIX = 'problems.action.showQuickFixes'; + export const TOGGLE_MARKERS_VIEW_ACTION_ID = 'workbench.actions.view.toggleProblems'; +} + +export namespace MarkersContextKeys { + export const MarkersViewModeContextKey = new RawContextKey('problemsViewMode', MarkersViewMode.Tree); + export const MarkersViewSmallLayoutContextKey = new RawContextKey(`problemsView.smallLayout`, false); + export const MarkersTreeVisibilityContextKey = new RawContextKey('problemsVisibility', false); + export const MarkerFocusContextKey = new RawContextKey('problemFocus', false); + export const MarkerViewFilterFocusContextKey = new RawContextKey('problemsFilterFocus', false); + export const RelatedInformationFocusContextKey = new RawContextKey('relatedInformationFocus', false); +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index c6b4e71bb47..1ae1e7ea6bf 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -245,6 +245,7 @@ export class NotebookEditor extends EditorPane implements IEditorPaneWithSelecti mark(input.resource, 'editorLoaded'); type WorkbenchNotebookOpenClassification = { + owner: 'rebornix'; scheme: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; ext: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; viewType: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 8567bdded40..aabbb8f23de 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1130,6 +1130,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD }); } type WorkbenchNotebookOpenClassification = { + owner: 'rebornix'; scheme: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; ext: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; viewType: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 018b31c5768..c7c5e722f4f 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -51,6 +51,7 @@ import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; type KeybindingEditorActionClassification = { + owner: 'sandy081'; action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; command: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts index 2f5cfdd2caa..7f5d1e698ed 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts @@ -122,7 +122,7 @@ export class SettingsTreeIndicatorsLabel { updateDefaultOverrideIndicator(element: SettingsTreeSettingElement) { this.defaultOverrideIndicatorElement.style.display = 'none'; - const defaultValueSource = element.setting.defaultValueSource; + const defaultValueSource = element.defaultValueSource; if (defaultValueSource) { this.defaultOverrideIndicatorElement.style.display = 'inline'; if (typeof defaultValueSource !== 'string' && defaultValueSource.id !== element.setting.extensionInfo?.id) { @@ -157,8 +157,8 @@ export function getIndicatorsLabelAriaLabel(element: SettingsTreeSettingElement, } // Add default override indicator text - if (element.setting.defaultValueSource) { - const defaultValueSource = element.setting.defaultValueSource; + if (element.defaultValueSource) { + const defaultValueSource = element.defaultValueSource; if (typeof defaultValueSource !== 'string' && defaultValueSource.id !== element.setting.extensionInfo?.id) { const extensionSource = defaultValueSource.displayName ?? defaultValueSource.id; ariaLabelSections.push(localize('defaultOverriddenDetails', "Default setting value overridden by {0}", extensionSource)); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 5a9aa77dcf2..b65d169f75c 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1115,7 +1115,7 @@ export class SettingComplexRenderer extends AbstractSettingRenderer implements I template.elementDisposables.add(template.button.onDidClick(() => { if (isLanguageTagSetting) { - this._onApplyFilter.fire(`@${LANGUAGE_SETTING_TAG}:${plainKey}`); + this._onApplyFilter.fire(`@${LANGUAGE_SETTING_TAG}${plainKey}`); } else { this._onDidOpenSettings.fire(dataElement.setting.key); } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index b16ea3ac942..aa4cce1ae2b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -18,7 +18,7 @@ import { FOLDER_SCOPES, WORKSPACE_SCOPES, REMOTE_MACHINE_SCOPES, LOCAL_MACHINE_S import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; -import { ConfigurationScope, EditPresentationTypes, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, EditPresentationTypes, Extensions, IConfigurationRegistry, IExtensionInfo } from 'vs/platform/configuration/common/configurationRegistry'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -129,6 +129,12 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { */ defaultValue?: any; + /** + * The source of the default value to display. + * This value also accounts for extension-contributed language-specific default value overrides. + */ + defaultValueSource: string | IExtensionInfo | undefined; + /** * Whether the setting is configured in the selected scope. */ @@ -146,7 +152,12 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { tags?: Set; overriddenScopeList: string[] = []; + + /** + * For each language that contributes setting values or default overrides, we can see those values here. + */ languageOverrideValues: Map> = new Map>(); + description!: string; valueType!: SettingValueType; @@ -219,6 +230,10 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { } } + // The user might have added, removed, or modified a language filter, + // so we reset the default value source to the non-language-specific default value source for now. + this.defaultValueSource = this.setting.nonLanguageSpecificDefaultValueSource; + if (inspected.policyValue) { this.hasPolicyValue = true; isConfigured = false; // The user did not manually configure the setting themselves. @@ -236,7 +251,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { const registryValues = Registry.as(Extensions.Configuration).getConfigurationDefaultsOverrides(); const overrideValueSource = registryValues.get(`[${languageSelector}]`)?.valuesSources?.get(this.setting.key); if (overrideValueSource) { - this.setting.defaultValueSource = overrideValueSource; + this.defaultValueSource = overrideValueSource; } } else { this.scopeValue = isConfigured && inspected[targetSelector]; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index a3059234eb1..a738e3d7a21 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -1862,6 +1862,13 @@ class SCMInputWidget extends Disposable { this.repositoryDisposables.add(input.repository.provider.onDidChangeCommitTemplate(updateTemplate, this)); updateTemplate(); + // Update input enablement + const updateEnablement = (enabled: boolean) => { + this.inputEditor.updateOptions({ readOnly: !enabled }); + }; + this.repositoryDisposables.add(input.onDidChangeEnablement(enabled => updateEnablement(enabled))); + updateEnablement(input.enabled); + // Save model this.model = { input, textModel }; } diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index e180e8e9d3c..9d18d25a131 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -121,6 +121,9 @@ export interface ISCMInput { validateInput: IInputValidator; readonly onDidChangeValidateInput: Event; + enabled: boolean; + readonly onDidChangeEnablement: Event; + visible: boolean; readonly onDidChangeVisibility: Event; diff --git a/src/vs/workbench/contrib/scm/common/scmService.ts b/src/vs/workbench/contrib/scm/common/scmService.ts index 7877ba1d34e..73da6c00923 100644 --- a/src/vs/workbench/contrib/scm/common/scmService.ts +++ b/src/vs/workbench/contrib/scm/common/scmService.ts @@ -38,6 +38,20 @@ class SCMInput implements ISCMInput { private readonly _onDidChangePlaceholder = new Emitter(); readonly onDidChangePlaceholder: Event = this._onDidChangePlaceholder.event; + private _enabled = true; + + get enabled(): boolean { + return this._enabled; + } + + set enabled(enabled: boolean) { + this._enabled = enabled; + this._onDidChangeEnablement.fire(enabled); + } + + private readonly _onDidChangeEnablement = new Emitter(); + readonly onDidChangeEnablement: Event = this._onDidChangeEnablement.event; + private _visible = true; get visible(): boolean { diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 578221a80ef..b10af56a625 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -1076,6 +1076,7 @@ export class SearchModel extends Disposable { Promise.race([currentRequest, Event.toPromise(progressEmitter.event)]).finally(() => { /* __GDPR__ "searchResultsFirstRender" : { + "owner": "roblourens", "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } } */ @@ -1091,6 +1092,7 @@ export class SearchModel extends Disposable { } finally { /* __GDPR__ "searchResultsFinished" : { + "owner": "roblourens", "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } } */ @@ -1119,6 +1121,7 @@ export class SearchModel extends Disposable { /* __GDPR__ "searchResultsShown" : { + owner": "roblourens", "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "fileCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "options": { "${inline}": [ "${IPatternInfo}" ] }, diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts index 28e8b4fd1e5..8878b684466 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts @@ -139,7 +139,7 @@ export const openNewSearchEditor = } } - telemetryService.publicLog2('searchEditor/openNewSearchEditor'); + telemetryService.publicLog2<{}, { owner: 'roblourens' }>('searchEditor/openNewSearchEditor'); const seedSearchStringFromSelection = _args.location === 'new' || configurationService.getValue('editor').find!.seedSearchStringFromSelection; const args: OpenSearchEditorArgs = { query: seedSearchStringFromSelection ? selected : undefined }; @@ -189,7 +189,7 @@ export const createEditorFromSearchResult = const sortOrder = configurationService.getValue('search').sortOrder; - telemetryService.publicLog2('searchEditor/createEditorFromSearchResult'); + telemetryService.publicLog2<{}, { owner: 'roblourens' }>('searchEditor/createEditorFromSearchResult'); const labelFormatter = (uri: URI): string => labelService.getUriLabel(uri, { relative: true }); diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts index dfd56c33267..56f822657f5 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts @@ -184,7 +184,7 @@ export class SearchEditorInput extends EditorInput { override async saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { const path = await this.fileDialogService.pickFileToSave(await this.suggestFileName(), options?.availableFileSystems); if (path) { - this.telemetryService.publicLog2('searchEditor/saveSearchResults'); + this.telemetryService.publicLog2<{}, { owner: 'roblourens' }>('searchEditor/saveSearchResults'); const toWrite = await this.serializeForDisk(); if (await this.textFileService.create([{ resource: path, value: toWrite, options: { overwrite: true } }])) { this.setDirty(false); diff --git a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts index 6c2dab81268..a2c5a2beaf7 100644 --- a/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/ces.contribution.ts @@ -66,6 +66,7 @@ class CESContribution extends Disposable implements IWorkbenchContribution { const sendTelemetry = (userReaction: 'accept' | 'remindLater' | 'neverShowAgain' | 'cancelled') => { /* __GDPR__ "cesSurvey:popup" : { + "owner": "digitarald", "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -141,7 +142,9 @@ class CESContribution extends Disposable implements IWorkbenchContribution { } } /* __GDPR__ - "cesSurvey:schedule" : { } + "cesSurvey:schedule" : { + "owner": "digitarald" + } */ this.telemetryService.publicLog('cesSurvey:schedule'); diff --git a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts index 8e263a87401..ab86a14c069 100644 --- a/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts +++ b/src/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts @@ -67,7 +67,7 @@ export class WorkspaceTags implements IWorkbenchContribution { value = 'Unknown'; } - this.telemetryService.publicLog2<{ edition: string }, { edition: { classification: 'SystemMetaData'; purpose: 'BusinessInsight' } }>('windowsEdition', { edition: value }); + this.telemetryService.publicLog2<{ edition: string }, { owner: 'sbatten'; edition: { classification: 'SystemMetaData'; purpose: 'BusinessInsight' } }>('windowsEdition', { edition: value }); } private async getWorkspaceInformation(): Promise { @@ -89,6 +89,7 @@ export class WorkspaceTags implements IWorkbenchContribution { private reportWorkspaceTags(tags: Tags): void { /* __GDPR__ "workspce.tags" : { + "owner": "lramos15", "${include}": [ "${WorkspaceTags}" ] @@ -116,6 +117,7 @@ export class WorkspaceTags implements IWorkbenchContribution { set.forEach(item => list.push(item)); /* __GDPR__ "workspace.remotes" : { + "owner": "lramos15", "domains" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ @@ -192,6 +194,7 @@ export class WorkspaceTags implements IWorkbenchContribution { if (Object.keys(tags).length) { /* __GDPR__ "workspace.azure" : { + "owner": "lramos15", "${include}": [ "${AzureTags}" ] diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 7e4c505c69c..42f69229199 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -36,7 +36,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IModelService } from 'vs/editor/common/services/model'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; +import { Markers } from 'vs/workbench/contrib/markers/common/markers'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder, IWorkspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -52,9 +52,10 @@ import { Task, CustomTask, ConfiguringTask, ContributedTask, InMemoryTask, TaskEvent, TaskSet, TaskGroup, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskSorter, TaskIdentifier, KeyedTaskIdentifier, TASK_RUNNING_STATE, TaskRunSource, - KeyedTaskIdentifier as NKeyedTaskIdentifier, TaskDefinition, RuntimeType + KeyedTaskIdentifier as NKeyedTaskIdentifier, TaskDefinition, RuntimeType, + USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/tasks'; -import { ITaskService, ITaskProvider, ProblemMatcherRunOptions, CustomizationProperties, TaskFilter, WorkspaceFolderTaskResult, USER_TASKS_GROUP_KEY, CustomExecutionSupportedContext, ShellExecutionSupportedContext, ProcessExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; +import { ITaskService, ITaskProvider, ProblemMatcherRunOptions, CustomizationProperties, TaskFilter, WorkspaceFolderTaskResult, CustomExecutionSupportedContext, ShellExecutionSupportedContext, ProcessExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/common/taskTemplates'; import * as TaskConfig from '../common/taskConfiguration'; @@ -429,7 +430,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } }); - CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => this.commandService.executeCommand(Constants.TOGGLE_MARKERS_VIEW_ACTION_ID)); + CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => this.commandService.executeCommand(Markers.TOGGLE_MARKERS_VIEW_ACTION_ID)); CommandsRegistry.registerCommand('workbench.action.tasks.openUserTasks', async () => { const resource = this.getResourceForKind(TaskSourceKind.User); diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 6cb1d3b7f86..2c06dbc8717 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -22,7 +22,7 @@ import { IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/marke import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IModelService } from 'vs/editor/common/services/model'; import { ProblemMatcher, ProblemMatcherRegistry /*, ProblemPattern, getResource */ } from 'vs/workbench/contrib/tasks/common/problemMatcher'; -import Constants from 'vs/workbench/contrib/markers/browser/constants'; +import { Markers } from 'vs/workbench/contrib/markers/common/markers'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ITerminalProfileResolverService, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -813,7 +813,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let reveal = task.command.presentation!.reveal; let revealProblems = task.command.presentation!.revealProblems; if (revealProblems === RevealProblemKind.OnProblem) { - this.viewsService.openView(Constants.MARKERS_VIEW_ID, true); + this.viewsService.openView(Markers.MARKERS_VIEW_ID, true); } else if (reveal === RevealKind.Silent) { this.terminalService.setActiveInstance(terminal!); this.terminalGroupService.showPanel(false); @@ -956,7 +956,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let revealProblems = task.command.presentation!.revealProblems; let revealProblemPanel = terminal && (revealProblems === RevealProblemKind.OnProblem) && (startStopProblemMatcher.numberOfMatches > 0); if (revealProblemPanel) { - this.viewsService.openView(Constants.MARKERS_VIEW_ID); + this.viewsService.openView(Markers.MARKERS_VIEW_ID); } else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity && (startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { @@ -991,7 +991,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let showProblemPanel = task.command.presentation && (task.command.presentation.revealProblems === RevealProblemKind.Always); if (showProblemPanel) { - this.viewsService.openView(Constants.MARKERS_VIEW_ID); + this.viewsService.openView(Markers.MARKERS_VIEW_ID); } else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) { this.terminalService.setActiveInstance(terminal); this.terminalGroupService.showPanel(task.command.presentation.focus); diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 9c6f0ba9e34..3f567b6320a 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -23,7 +23,7 @@ import * as Tasks from './tasks'; import { TaskDefinitionRegistry } from './taskDefinitionRegistry'; import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { URI } from 'vs/base/common/uri'; -import { USER_TASKS_GROUP_KEY, ShellExecutionSupportedContext, ProcessExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; +import { ShellExecutionSupportedContext, ProcessExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const enum ShellQuoting { @@ -1268,7 +1268,7 @@ export namespace GroupKind { namespace TaskDependency { function uriFromSource(context: ParseContext, source: TaskConfigSource): URI | string { switch (source) { - case TaskConfigSource.User: return USER_TASKS_GROUP_KEY; + case TaskConfigSource.User: return Tasks.USER_TASKS_GROUP_KEY; case TaskConfigSource.TasksJson: return context.workspaceFolder.uri; default: return context.workspace && context.workspace.configuration ? context.workspace.configuration : context.workspaceFolder.uri; } @@ -2146,4 +2146,3 @@ export function parse(workspaceFolder: IWorkspaceFolder, workspace: IWorkspace | export function createCustomTask(contributedTask: Tasks.ContributedTask, configuredProps: Tasks.ConfiguringTask | Tasks.CustomTask): Tasks.CustomTask { return CustomTask.createCustomTask(contributedTask, configuredProps); } - diff --git a/src/vs/workbench/contrib/tasks/common/taskService.ts b/src/vs/workbench/contrib/tasks/common/taskService.ts index 68a2394a880..b75cd445666 100644 --- a/src/vs/workbench/contrib/tasks/common/taskService.ts +++ b/src/vs/workbench/contrib/tasks/common/taskService.ts @@ -55,8 +55,6 @@ export interface WorkspaceFolderTaskResult extends WorkspaceTaskResult { workspaceFolder: IWorkspaceFolder; } -export const USER_TASKS_GROUP_KEY = 'settings'; - export interface ITaskService { readonly _serviceBrand: undefined; onDidStateChange: Event; diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 3cf450aabd0..e26ad2051e5 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -17,9 +17,8 @@ import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDe import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -// TODO@jrieken HACK, HACK -// import { USER_TASKS_GROUP_KEY } from 'vs/workbench/contrib/tasks/common/taskService'; -const USER_TASKS_GROUP_KEY = 'settings'; + +export const USER_TASKS_GROUP_KEY = 'settings'; export const TASK_RUNNING_STATE = new RawContextKey('taskRunning', false, nls.localize('tasks.taskRunningContext', "Whether a task is currently running.")); export const TASKS_CATEGORY = { value: nls.localize('tasksCategory', "Tasks"), original: 'Tasks' }; diff --git a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts index adf6f60619f..2ebf2547eca 100644 --- a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts +++ b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts @@ -72,6 +72,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr }; type WorkspaceLoadClassification = { + owner: 'bpasero'; userAgent: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; emptyWorkbench: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; windowSize: WindowSizeFragment; @@ -134,12 +135,15 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr const settingsType = this.getTypeIfSettings(e.model.resource); if (settingsType) { type SettingsReadClassification = { + owner: 'bpasero'; settingsType: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this.telemetryService.publicLog2<{ settingsType: string }, SettingsReadClassification>('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data } else { - type FileGetClassification = {} & FileTelemetryDataFragment; + type FileGetClassification = { + owner: 'bpasero'; + } & FileTelemetryDataFragment; this.telemetryService.publicLog2('fileGet', this.getTelemetryData(e.model.resource, e.reason)); } @@ -149,11 +153,14 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr const settingsType = this.getTypeIfSettings(e.model.resource); if (settingsType) { type SettingsWrittenClassification = { + owner: 'bpasero'; settingsType: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; this.telemetryService.publicLog2<{ settingsType: string }, SettingsWrittenClassification>('settingsWritten', { settingsType }); // Do not log write to user settings.json and .vscode folder as a filePUT event as it ruins our JSON usage data } else { - type FilePutClassfication = {} & FileTelemetryDataFragment; + type FilePutClassfication = { + owner: 'bpasero'; + } & FileTelemetryDataFragment; this.telemetryService.publicLog2('filePUT', this.getTelemetryData(e.model.resource, e.reason)); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 61c2efbb885..5c841da1021 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1634,7 +1634,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } if (failedShellIntegrationInjection) { - this._telemetryService.publicLog2<{ classification: 'SystemMetaData'; purpose: 'FeatureInsight' }>('terminal/shellIntegrationFailureProcessExit'); + this._telemetryService.publicLog2<{}, { owner: 'meganrogge'; comment: 'Indicates the process exited when created with shell integration args' }>('terminal/shellIntegrationFailureProcessExit'); } // First onExit to consumers, this can happen after the terminal has already been disposed. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 7ae7dc3c4fc..65d72db0196 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -335,7 +335,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce this._hasChildProcesses = value; break; case ProcessPropertyType.FailedShellIntegrationActivation: - this._telemetryService?.publicLog2<{ classification: 'SystemMetaData'; purpose: 'FeatureInsight' }>('terminal/shellIntegrationActivationFailureCustomArgs'); + this._telemetryService?.publicLog2<{}, { owner: 'meganrogge'; comment: 'Indicates shell integration was not activated because of custom args' }>('terminal/shellIntegrationActivationFailureCustomArgs'); break; } this._onDidChangeProperty.fire({ type, value }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts index 168cbe2fbf2..9c53e0d00f6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts @@ -1411,6 +1411,7 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon { private _sendLatencyStats(stats: PredictionStats) { /* __GDPR__ "terminalLatencyStats" : { + "owner": "Tyriar", "min" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "max" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "median" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 4a7fe8b6202..dec9d627cb9 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -66,6 +66,7 @@ const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', type ConfigureSyncQuickPickItem = { id: SyncResource; label: string; description?: string }; type SyncConflictsClassification = { + owner: 'sandy081'; source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; action?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 799c6820bba..cb1fe2362b2 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -181,7 +181,9 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr this.handleEditorPartSize(container, this.editorGroupsService.contentDimension); /* __GDPR__ - "watermark:open" : { } + "watermark:open" : { + "owner": "digitarald" + } */ this.telemetryService.publicLog('watermark:open'); } diff --git a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts index af9a08af7c8..eb818e7fc16 100644 --- a/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts @@ -22,6 +22,7 @@ interface AccessibilityMetrics { enabled: boolean; } type AccessibilityMetricsClassification = { + owner: 'isidorn'; enabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index 19955341627..36560ff0d77 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -254,7 +254,7 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.InlineCompletionsActions, description: localize('inlineCompletions.actions', "The actions shown when hovering on an inline completion"), supportsSubmenus: false, - proposed: 'inlineCompletions' + proposed: 'inlineCompletionsAdditions' }, ]; diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index 5c045163b1b..f2008b07592 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -82,6 +82,7 @@ export interface ExtensionUrlHandlerEvent { } export interface ExtensionUrlHandlerClassification extends GDPRClassification { + owner: 'joaomoreno'; readonly extensionId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; } diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index d5ded005d72..e2f86dc13a9 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -18,6 +18,7 @@ export const allApiProposals = Object.freeze({ dataTransferFiles: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts', diffCommand: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffCommand.d.ts', documentFiltersExclusive: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentFiltersExclusive.d.ts', + documentPaste: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentPaste.d.ts', editorInsets: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editorInsets.d.ts', extensionRuntime: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionRuntime.d.ts', extensionsAny: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionsAny.d.ts', @@ -26,7 +27,6 @@ export const allApiProposals = Object.freeze({ findTextInFiles: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts', fsChunks: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts', idToken: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.idToken.d.ts', - inlineCompletions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletions.d.ts', inlineCompletionsAdditions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts', inlineCompletionsNew: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletionsNew.d.ts', ipc: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.ipc.d.ts', @@ -47,6 +47,7 @@ export const allApiProposals = Object.freeze({ quickPickSortByLabel: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts', resolvers: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.resolvers.d.ts', scmActionButton: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmActionButton.d.ts', + scmInput: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmInput.d.ts', scmSelectedProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts', scmValidation: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmValidation.d.ts', taskPresentationGroup: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts', diff --git a/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts b/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts new file mode 100644 index 00000000000..2e4c745a9f8 --- /dev/null +++ b/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ExtensionHostKind, ExtensionRunningLocation, IExtensionHost, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { NativeLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost'; +import { ElectronExtensionService } from 'vs/workbench/services/extensions/electron-sandbox/electronExtensionService'; + +export class NativeExtensionService extends ElectronExtensionService { + protected override _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null { + if (runningLocation.kind === ExtensionHostKind.LocalProcess) { + return this._instantiationService.createInstance(NativeLocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation)); + } + return super._createExtensionHost(runningLocation, isInitialStart); + } +} + +registerSingleton(IExtensionService, NativeExtensionService); diff --git a/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts new file mode 100644 index 00000000000..d498ddd7960 --- /dev/null +++ b/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createServer, Server } from 'net'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import * as platform from 'vs/base/common/platform'; +import { StopWatch } from 'vs/base/common/stopwatch'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; +import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; +import { createRandomIPCHandle, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; +import { IExtensionHostProcessOptions } from 'vs/platform/extensions/common/extensionHostStarter'; +import { ILogService } from 'vs/platform/log/common/log'; +import { createMessageOfType, MessageType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { ExtensionHostProcess, ExtHostMessagePortCommunication, IExtHostCommunication, SandboxLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost'; + +export class NativeLocalProcessExtensionHost extends SandboxLocalProcessExtensionHost { + protected override async _start(): Promise { + const canUseUtilityProcess = await this._extensionHostStarter.canUseUtilityProcess(); + if (canUseUtilityProcess && process.env['VSCODE_USE_UTILITY_PROCESS']) { + const communication = this._toDispose.add(new ExtHostMessagePortCommunication(this._logService)); + return this._startWithCommunication(communication); + } else { + const communication = this._toDispose.add(new ExtHostNamedPipeCommunication(this._logService)); + return this._startWithCommunication(communication); + } + } +} + +interface INamedPipePreparedData { + pipeName: string; + namedPipeServer: Server; +} + +class ExtHostNamedPipeCommunication extends Disposable implements IExtHostCommunication { + + readonly useUtilityProcess = false; + + constructor( + @ILogService private readonly _logService: ILogService + ) { + super(); + } + + prepare(): Promise { + return new Promise<{ pipeName: string; namedPipeServer: Server }>((resolve, reject) => { + const pipeName = createRandomIPCHandle(); + + const namedPipeServer = createServer(); + namedPipeServer.on('error', reject); + namedPipeServer.listen(pipeName, () => { + if (namedPipeServer) { + namedPipeServer.removeListener('error', reject); + } + resolve({ pipeName, namedPipeServer }); + }); + this._register(toDisposable(() => { + if (namedPipeServer.listening) { + namedPipeServer.close(); + } + })); + }); + } + + establishProtocol(prepared: INamedPipePreparedData, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise { + const { namedPipeServer, pipeName } = prepared; + + opts.env['VSCODE_IPC_HOOK_EXTHOST'] = pipeName; + + return new Promise((resolve, reject) => { + + // Wait for the extension host to connect to our named pipe + // and wrap the socket in the message passing protocol + const handle = setTimeout(() => { + if (namedPipeServer.listening) { + namedPipeServer.close(); + } + reject('The local extension host took longer than 60s to connect.'); + }, 60 * 1000); + + namedPipeServer.on('connection', (socket) => { + + clearTimeout(handle); + if (namedPipeServer.listening) { + namedPipeServer.close(); + } + + const nodeSocket = new NodeSocket(socket, 'renderer-exthost'); + const protocol = new PersistentProtocol(nodeSocket); + + this._register(toDisposable(() => { + // Send the extension host a request to terminate itself + // (graceful termination) + protocol.send(createMessageOfType(MessageType.Terminate)); + protocol.flush(); + + socket.end(); + nodeSocket.dispose(); + protocol.dispose(); + })); + + resolve(protocol); + }); + + // Now that the named pipe listener is installed, start the ext host process + const sw = StopWatch.create(false); + extensionHostProcess.start(opts).then(() => { + const duration = sw.elapsed(); + if (platform.isCI) { + this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`); + } + }, (err) => { + // Starting the ext host process resulted in an error + reject(err); + }); + + }); + } +} diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts similarity index 97% rename from src/vs/workbench/services/extensions/electron-browser/extensionService.ts rename to src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts index 388033c90a1..ea87ef0642a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts @@ -3,10 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILocalProcessExtensionHostDataProvider, ILocalProcessExtensionHostInitData, LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost'; - import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractExtensionService, ExtensionHostCrashTracker, ExtensionRunningPreference, extensionRunningPreferenceToString, filterByRunningLocation } from 'vs/workbench/services/extensions/common/abstractExtensionService'; import * as nls from 'vs/nls'; import { runWhenIdle } from 'vs/base/common/async'; @@ -50,8 +47,9 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import { isCI } from 'vs/base/common/platform'; import { IResolveAuthorityErrorResult } from 'vs/workbench/services/extensions/common/extensionHostProxy'; import { URI } from 'vs/base/common/uri'; +import { ILocalProcessExtensionHostDataProvider, ILocalProcessExtensionHostInitData, SandboxLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost'; -export class ExtensionService extends AbstractExtensionService implements IExtensionService { +export abstract class ElectronExtensionService extends AbstractExtensionService implements IExtensionService { private readonly _enableLocalWebWorker: boolean; private readonly _lazyLocalWebWorker: boolean; @@ -155,7 +153,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten ])); } - private _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation): ILocalProcessExtensionHostDataProvider & IWebWorkerExtensionHostDataProvider { + protected _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation): ILocalProcessExtensionHostDataProvider & IWebWorkerExtensionHostDataProvider { return { getInitData: async (): Promise => { if (isInitialStart) { @@ -193,7 +191,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } protected _pickExtensionHostKind(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionHostKind | null { - const result = ExtensionService.pickExtensionHostKind(extensionKinds, isInstalledLocally, isInstalledRemotely, preference, Boolean(this._environmentService.remoteAuthority), this._enableLocalWebWorker); + const result = ElectronExtensionService.pickExtensionHostKind(extensionKinds, isInstalledLocally, isInstalledRemotely, preference, Boolean(this._environmentService.remoteAuthority), this._enableLocalWebWorker); this._logService.trace(`pickRunningLocation for ${extensionId.value}, extension kinds: [${extensionKinds.join(', ')}], isInstalledLocally: ${isInstalledLocally}, isInstalledRemotely: ${isInstalledRemotely}, preference: ${extensionRunningPreferenceToString(preference)} => ${extensionHostKindToString(result)}`); return result; } @@ -240,7 +238,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten protected _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null { switch (runningLocation.kind) { case ExtensionHostKind.LocalProcess: { - return this._instantiationService.createInstance(LocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation)); + return this._instantiationService.createInstance(SandboxLocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation)); } case ExtensionHostKind.LocalWebWorker: { if (this._enableLocalWebWorker) { @@ -614,6 +612,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const sendTelemetry = (userReaction: 'install' | 'enable' | 'cancel') => { /* __GDPR__ "remoteExtensionRecommendations:popup" : { + "owner": "sandy081", "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } } @@ -676,8 +675,6 @@ function getRemoteAuthorityPrefix(remoteAuthority: string): string { return remoteAuthority.substring(0, plusIndex); } -registerSingleton(IExtensionService, ExtensionService); - class RestartExtensionHostAction extends Action2 { constructor() { diff --git a/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts similarity index 56% rename from src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts rename to src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index 0f7f60bbc7d..cee3a17b7f1 100644 --- a/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -3,21 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Server, Socket, createServer } from 'net'; -import { createRandomIPCHandle, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; - import * as nls from 'vs/nls'; import { timeout } from 'vs/base/common/async'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IRemoteConsoleLog, log } from 'vs/base/common/console'; import { logRemoteEntry, logRemoteEntryIfError } from 'vs/workbench/services/extensions/common/remoteConsoleUtil'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; -import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; +import { BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILifecycleService, WillShutdownEvent } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -27,7 +24,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { isUntitledWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { MessageType, createMessageOfType, isMessageOfType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { MessageType, isMessageOfType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { parseExtensionDevOptions } from '../common/extensionDevOptions'; @@ -44,6 +41,8 @@ import { SerializedError } from 'vs/base/common/errors'; import { removeDangerousEnvVariables } from 'vs/base/common/processes'; import { StopWatch } from 'vs/base/common/stopwatch'; import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; +import { generateUuid } from 'vs/base/common/uuid'; +import { acquirePort } from 'vs/base/parts/ipc/electron-sandbox/ipc.mp'; export interface ILocalProcessExtensionHostInitData { readonly autoStart: boolean; @@ -60,7 +59,7 @@ const enum NativeLogMarkers { End = 'END_NATIVE_LOG', } -class ExtensionHostProcess { +export class ExtensionHostProcess { private readonly _id: string; @@ -91,7 +90,7 @@ class ExtensionHostProcess { this._id = id; } - public start(opts: IExtensionHostProcessOptions): Promise<{ pid: number }> { + public start(opts: IExtensionHostProcessOptions): Promise { return this._extensionHostStarter.start(this._id, opts); } @@ -104,7 +103,7 @@ class ExtensionHostProcess { } } -export class LocalProcessExtensionHost implements IExtensionHost { +export class SandboxLocalProcessExtensionHost implements IExtensionHost { public readonly remoteAuthority = null; public readonly lazyStart = false; @@ -115,7 +114,7 @@ export class LocalProcessExtensionHost implements IExtensionHost { private readonly _onDidSetInspectPort = new Emitter(); - private readonly _toDispose = new DisposableStore(); + protected readonly _toDispose = new DisposableStore(); private readonly _isExtensionDevHost: boolean; private readonly _isExtensionDevDebug: boolean; @@ -127,11 +126,9 @@ export class LocalProcessExtensionHost implements IExtensionHost { private _terminating: boolean; // Resources, in order they get acquired/created when .start() is called: - private _namedPipeServer: Server | null; private _inspectPort: number | null; private _extensionHostProcess: ExtensionHostProcess | null; - private _extensionHostConnection: Socket | null; - private _messageProtocol: Promise | null; + private _messageProtocol: Promise | null; private readonly _extensionHostLogFile: URI; @@ -144,13 +141,13 @@ export class LocalProcessExtensionHost implements IExtensionHost { @ILifecycleService private readonly _lifecycleService: ILifecycleService, @INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, - @ILogService private readonly _logService: ILogService, + @ILogService protected readonly _logService: ILogService, @ILabelService private readonly _labelService: ILabelService, @IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService, @IHostService private readonly _hostService: IHostService, @IProductService private readonly _productService: IProductService, @IShellEnvironmentService private readonly _shellEnvironmentService: IShellEnvironmentService, - @IExtensionHostStarter private readonly _extensionHostStarter: IExtensionHostStarter, + @IExtensionHostStarter protected readonly _extensionHostStarter: IExtensionHostStarter, ) { const devOpts = parseExtensionDevOptions(this._environmentService); this._isExtensionDevHost = devOpts.isExtensionDevHost; @@ -161,17 +158,15 @@ export class LocalProcessExtensionHost implements IExtensionHost { this._lastExtensionHostError = null; this._terminating = false; - this._namedPipeServer = null; this._inspectPort = null; this._extensionHostProcess = null; - this._extensionHostConnection = null; this._messageProtocol = null; this._extensionHostLogFile = joinPath(this._environmentService.extHostLogsPath, `${ExtensionHostLogFileName}.log`); this._toDispose.add(this._onExit); this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); - this._toDispose.add(this._lifecycleService.onDidShutdown(() => this.terminate())); + this._toDispose.add(this._lifecycleService.onDidShutdown(() => this._terminate())); this._toDispose.add(this._extensionHostDebugService.onClose(event => { if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._nativeHostService.closeWindow(); @@ -185,7 +180,16 @@ export class LocalProcessExtensionHost implements IExtensionHost { } public dispose(): void { - this.terminate(); + this._terminate(); + } + + private _terminate(): void { + if (this._terminating) { + return; + } + this._terminating = true; + + this._toDispose.dispose(); } public start(): Promise | null { @@ -195,173 +199,166 @@ export class LocalProcessExtensionHost implements IExtensionHost { } if (!this._messageProtocol) { - this._messageProtocol = Promise.all([ - this._extensionHostStarter.createExtensionHost(), - this._tryListenOnPipe(), - this._tryFindDebugPort(), - this._shellEnvironmentService.getShellEnv(), - ]).then(([extensionHostCreationResult, pipeName, portNumber, processEnv]) => { - - this._extensionHostProcess = new ExtensionHostProcess(extensionHostCreationResult.id, this._extensionHostStarter); - - const env = objects.mixin(processEnv, { - VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', - VSCODE_PIPE_LOGGING: 'true', - VSCODE_VERBOSE_LOGGING: true, - VSCODE_LOG_NATIVE: this._isExtensionDevHost, - VSCODE_IPC_HOOK_EXTHOST: pipeName, - VSCODE_HANDLES_UNCAUGHT_ERRORS: true, - VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || this._productService.quality !== 'stable' || this._environmentService.verbose) - }); - - if (this._environmentService.debugExtensionHost.env) { - objects.mixin(env, this._environmentService.debugExtensionHost.env); - } - - removeDangerousEnvVariables(env); - - if (this._isExtensionDevHost) { - // Unset `VSCODE_CODE_CACHE_PATH` when developing extensions because it might - // be that dependencies, that otherwise would be cached, get modified. - delete env['VSCODE_CODE_CACHE_PATH']; - } - - const opts = { - env, - // We only detach the extension host on windows. Linux and Mac orphan by default - // and detach under Linux and Mac create another process group. - // We detach because we have noticed that when the renderer exits, its child processes - // (i.e. extension host) are taken down in a brutal fashion by the OS - detached: !!platform.isWindows, - execArgv: undefined as string[] | undefined, - silent: true - }; - - if (portNumber !== 0) { - opts.execArgv = [ - '--nolazy', - (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portNumber - ]; - } else { - opts.execArgv = ['--inspect-port=0']; - } - - if (this._environmentService.extensionTestsLocationURI) { - opts.execArgv.unshift('--expose-gc'); - } - - if (this._environmentService.args['prof-v8-extensions']) { - opts.execArgv.unshift('--prof'); - } - - if (this._environmentService.args['max-memory']) { - opts.execArgv.unshift(`--max-old-space-size=${this._environmentService.args['max-memory']}`); - } - - // Catch all output coming from the extension host process - type Output = { data: string; format: string[] }; - const onStdout = this._handleProcessOutputStream(this._extensionHostProcess.onStdout); - const onStderr = this._handleProcessOutputStream(this._extensionHostProcess.onStderr); - const onOutput = Event.any( - Event.map(onStdout.event, o => ({ data: `%c${o}`, format: [''] })), - Event.map(onStderr.event, o => ({ data: `%c${o}`, format: ['color: red'] })) - ); - - // Debounce all output, so we can render it in the Chrome console as a group - const onDebouncedOutput = Event.debounce(onOutput, (r, o) => { - return r - ? { data: r.data + o.data, format: [...r.format, ...o.format] } - : { data: o.data, format: o.format }; - }, 100); - - // Print out extension host output - onDebouncedOutput(output => { - const inspectorUrlMatch = output.data && output.data.match(/ws:\/\/([^\s]+:(\d+)\/[^\s]+)/); - if (inspectorUrlMatch) { - if (!this._environmentService.isBuilt && !this._isExtensionDevTestFromCli) { - console.log(`%c[Extension Host] %cdebugger inspector at chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${inspectorUrlMatch[1]}`, 'color: blue', 'color:'); - } - if (!this._inspectPort) { - this._inspectPort = Number(inspectorUrlMatch[2]); - this._onDidSetInspectPort.fire(); - } - } else { - if (!this._isExtensionDevTestFromCli) { - console.group('Extension Host'); - console.log(output.data, ...output.format); - console.groupEnd(); - } - } - }); - - // Support logging from extension host - this._extensionHostProcess.onMessage(msg => { - if (msg && (msg).type === '__$console') { - this._logExtensionHostMessage(msg); - } - }); - - // Lifecycle - - this._extensionHostProcess.onError((e) => this._onExtHostProcessError(e.error)); - this._extensionHostProcess.onExit(({ code, signal }) => this._onExtHostProcessExit(code, signal)); - - // Notify debugger that we are ready to attach to the process if we run a development extension - if (portNumber) { - if (this._isExtensionDevHost && portNumber && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { - this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portNumber); - } - this._inspectPort = portNumber; - this._onDidSetInspectPort.fire(); - } - - // Help in case we fail to start it - let startupTimeoutHandle: any; - if (!this._environmentService.isBuilt && !this._environmentService.remoteAuthority || this._isExtensionDevHost) { - startupTimeoutHandle = setTimeout(() => { - this._logService.error(`[LocalProcessExtensionHost]: Extension host did not start in 10 seconds (debugBrk: ${this._isExtensionDevDebugBrk})`); - - const msg = this._isExtensionDevDebugBrk - ? nls.localize('extensionHost.startupFailDebug', "Extension host did not start in 10 seconds, it might be stopped on the first line and needs a debugger to continue.") - : nls.localize('extensionHost.startupFail', "Extension host did not start in 10 seconds, that might be a problem."); - - this._notificationService.prompt(Severity.Warning, msg, - [{ - label: nls.localize('reloadWindow', "Reload Window"), - run: () => this._hostService.reload() - }], - { sticky: true } - ); - }, 10000); - } - - // Initialize extension host process with hand shakes - return this._tryExtHostHandshake(opts).then((protocol) => { - clearTimeout(startupTimeoutHandle); - return protocol; - }); - }); + this._messageProtocol = this._start(); } return this._messageProtocol; } - /** - * Start a server (`this._namedPipeServer`) that listens on a named pipe and return the named pipe name. - */ - private _tryListenOnPipe(): Promise { - return new Promise((resolve, reject) => { - const pipeName = createRandomIPCHandle(); + protected async _start(): Promise { + const communication = this._toDispose.add(new ExtHostMessagePortCommunication(this._logService)); + return this._startWithCommunication(communication); + } - this._namedPipeServer = createServer(); - this._namedPipeServer.on('error', reject); - this._namedPipeServer.listen(pipeName, () => { - if (this._namedPipeServer) { - this._namedPipeServer.removeListener('error', reject); - } - resolve(pipeName); - }); + protected async _startWithCommunication(communication: IExtHostCommunication): Promise { + + const [extensionHostCreationResult, communicationPreparedData, portNumber, processEnv] = await Promise.all([ + this._extensionHostStarter.createExtensionHost(communication.useUtilityProcess), + communication.prepare(), + this._tryFindDebugPort(), + this._shellEnvironmentService.getShellEnv(), + ]); + + this._extensionHostProcess = new ExtensionHostProcess(extensionHostCreationResult.id, this._extensionHostStarter); + + const env = objects.mixin(processEnv, { + VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess', + VSCODE_PIPE_LOGGING: 'true', + VSCODE_VERBOSE_LOGGING: true, + VSCODE_LOG_NATIVE: this._isExtensionDevHost, + VSCODE_HANDLES_UNCAUGHT_ERRORS: true, + VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || this._productService.quality !== 'stable' || this._environmentService.verbose) }); + + if (this._environmentService.debugExtensionHost.env) { + objects.mixin(env, this._environmentService.debugExtensionHost.env); + } + + removeDangerousEnvVariables(env); + + if (this._isExtensionDevHost) { + // Unset `VSCODE_CODE_CACHE_PATH` when developing extensions because it might + // be that dependencies, that otherwise would be cached, get modified. + delete env['VSCODE_CODE_CACHE_PATH']; + } + + const opts: IExtensionHostProcessOptions = { + responseWindowId: this._environmentService.window.id, + responseChannel: 'vscode:startExtensionHostMessagePortResult', + responseNonce: generateUuid(), + env, + // We only detach the extension host on windows. Linux and Mac orphan by default + // and detach under Linux and Mac create another process group. + // We detach because we have noticed that when the renderer exits, its child processes + // (i.e. extension host) are taken down in a brutal fashion by the OS + detached: !!platform.isWindows, + execArgv: undefined as string[] | undefined, + silent: true + }; + + if (portNumber !== 0) { + opts.execArgv = [ + '--nolazy', + (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portNumber + ]; + } else { + opts.execArgv = ['--inspect-port=0']; + } + + if (this._environmentService.extensionTestsLocationURI) { + opts.execArgv.unshift('--expose-gc'); + } + + if (this._environmentService.args['prof-v8-extensions']) { + opts.execArgv.unshift('--prof'); + } + + if (this._environmentService.args['max-memory']) { + opts.execArgv.unshift(`--max-old-space-size=${this._environmentService.args['max-memory']}`); + } + + // Catch all output coming from the extension host process + type Output = { data: string; format: string[] }; + const onStdout = this._handleProcessOutputStream(this._extensionHostProcess.onStdout); + const onStderr = this._handleProcessOutputStream(this._extensionHostProcess.onStderr); + const onOutput = Event.any( + Event.map(onStdout.event, o => ({ data: `%c${o}`, format: [''] })), + Event.map(onStderr.event, o => ({ data: `%c${o}`, format: ['color: red'] })) + ); + + // Debounce all output, so we can render it in the Chrome console as a group + const onDebouncedOutput = Event.debounce(onOutput, (r, o) => { + return r + ? { data: r.data + o.data, format: [...r.format, ...o.format] } + : { data: o.data, format: o.format }; + }, 100); + + // Print out extension host output + onDebouncedOutput(output => { + const inspectorUrlMatch = output.data && output.data.match(/ws:\/\/([^\s]+:(\d+)\/[^\s]+)/); + if (inspectorUrlMatch) { + if (!this._environmentService.isBuilt && !this._isExtensionDevTestFromCli) { + console.log(`%c[Extension Host] %cdebugger inspector at chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${inspectorUrlMatch[1]}`, 'color: blue', 'color:'); + } + if (!this._inspectPort) { + this._inspectPort = Number(inspectorUrlMatch[2]); + this._onDidSetInspectPort.fire(); + } + } else { + if (!this._isExtensionDevTestFromCli) { + console.group('Extension Host'); + console.log(output.data, ...output.format); + console.groupEnd(); + } + } + }); + + // Support logging from extension host + this._extensionHostProcess.onMessage(msg => { + if (msg && (msg).type === '__$console') { + this._logExtensionHostMessage(msg); + } + }); + + // Lifecycle + + this._extensionHostProcess.onError((e) => this._onExtHostProcessError(e.error)); + this._extensionHostProcess.onExit(({ code, signal }) => this._onExtHostProcessExit(code, signal)); + + // Notify debugger that we are ready to attach to the process if we run a development extension + if (portNumber) { + if (this._isExtensionDevHost && portNumber && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portNumber); + } + this._inspectPort = portNumber; + this._onDidSetInspectPort.fire(); + } + + // Help in case we fail to start it + let startupTimeoutHandle: any; + if (!this._environmentService.isBuilt && !this._environmentService.remoteAuthority || this._isExtensionDevHost) { + startupTimeoutHandle = setTimeout(() => { + this._logService.error(`[LocalProcessExtensionHost]: Extension host did not start in 10 seconds (debugBrk: ${this._isExtensionDevDebugBrk})`); + + const msg = this._isExtensionDevDebugBrk + ? nls.localize('extensionHost.startupFailDebug', "Extension host did not start in 10 seconds, it might be stopped on the first line and needs a debugger to continue.") + : nls.localize('extensionHost.startupFail', "Extension host did not start in 10 seconds, that might be a problem."); + + this._notificationService.prompt(Severity.Warning, msg, + [{ + label: nls.localize('reloadWindow', "Reload Window"), + run: () => this._hostService.reload() + }], + { sticky: true } + ); + }, 10000); + } + + // Initialize extension host process with hand shakes + const protocol = await communication.establishProtocol(communicationPreparedData, this._extensionHostProcess, opts); + await this._performHandshake(protocol); + clearTimeout(startupTimeoutHandle); + return protocol; } /** @@ -394,102 +391,58 @@ export class LocalProcessExtensionHost implements IExtensionHost { return port || 0; } - private _tryExtHostHandshake(opts: IExtensionHostProcessOptions): Promise { + private _performHandshake(protocol: IMessagePassingProtocol): Promise { + // 1) wait for the incoming `ready` event and send the initialization data. + // 2) wait for the incoming `initialized` event. + return new Promise((resolve, reject) => { - return new Promise((resolve, reject) => { + let timeoutHandle: any; + const installTimeoutCheck = () => { + timeoutHandle = setTimeout(() => { + reject('The local extenion host took longer than 60s to send its ready message.'); + }, 60 * 1000); + }; + const uninstallTimeoutCheck = () => { + clearTimeout(timeoutHandle); + }; - // Wait for the extension host to connect to our named pipe - // and wrap the socket in the message passing protocol - let handle = setTimeout(() => { - if (this._namedPipeServer) { - this._namedPipeServer.close(); - this._namedPipeServer = null; + // Wait 60s for the ready message + installTimeoutCheck(); + + const disposable = protocol.onMessage(msg => { + + if (isMessageOfType(msg, MessageType.Ready)) { + + // 1) Extension Host is ready to receive messages, initialize it + uninstallTimeoutCheck(); + + this._createExtHostInitData().then(data => { + + // Wait 60s for the initialized message + installTimeoutCheck(); + + protocol.send(VSBuffer.fromString(JSON.stringify(data))); + }); + return; } - reject('The local extension host took longer than 60s to connect.'); - }, 60 * 1000); - this._namedPipeServer!.on('connection', socket => { + if (isMessageOfType(msg, MessageType.Initialized)) { - clearTimeout(handle); - if (this._namedPipeServer) { - this._namedPipeServer.close(); - this._namedPipeServer = null; + // 2) Extension Host is initialized + uninstallTimeoutCheck(); + + // stop listening for messages here + disposable.dispose(); + + // Register log channel for exthost log + Registry.as(Extensions.OutputChannels).registerChannel({ id: 'extHostLog', label: nls.localize('extension host Log', "Extension Host"), file: this._extensionHostLogFile, log: true }); + + // release this promise + resolve(); + return; } - this._extensionHostConnection = socket; - - // using a buffered message protocol here because between now - // and the first time a `then` executes some messages might be lost - // unless we immediately register a listener for `onMessage`. - resolve(new PersistentProtocol(new NodeSocket(this._extensionHostConnection, 'renderer-exthost'))); - }); - - // Now that the named pipe listener is installed, start the ext host process - const sw = StopWatch.create(false); - this._extensionHostProcess!.start(opts).then(() => { - const duration = sw.elapsed(); - if (platform.isCI) { - this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`); - } - }, (err) => { - // Starting the ext host process resulted in an error - reject(err); - }); - - }).then((protocol) => { - - // 1) wait for the incoming `ready` event and send the initialization data. - // 2) wait for the incoming `initialized` event. - return new Promise((resolve, reject) => { - - let timeoutHandle: NodeJS.Timer; - const installTimeoutCheck = () => { - timeoutHandle = setTimeout(() => { - reject('The local extenion host took longer than 60s to send its ready message.'); - }, 60 * 1000); - }; - const uninstallTimeoutCheck = () => { - clearTimeout(timeoutHandle); - }; - - // Wait 60s for the ready message - installTimeoutCheck(); - - const disposable = protocol.onMessage(msg => { - - if (isMessageOfType(msg, MessageType.Ready)) { - - // 1) Extension Host is ready to receive messages, initialize it - uninstallTimeoutCheck(); - - this._createExtHostInitData().then(data => { - - // Wait 60s for the initialized message - installTimeoutCheck(); - - protocol.send(VSBuffer.fromString(JSON.stringify(data))); - }); - return; - } - - if (isMessageOfType(msg, MessageType.Initialized)) { - - // 2) Extension Host is initialized - uninstallTimeoutCheck(); - - // stop listening for messages here - disposable.dispose(); - - // Register log channel for exthost log - Registry.as(Extensions.OutputChannels).registerChannel({ id: 'extHostLog', label: nls.localize('extension host Log', "Extension Host"), file: this._extensionHostLogFile, log: true }); - - // release this promise - resolve(protocol); - return; - } - - console.error(`received unexpected message during handshake phase from the extension host: `, msg); - }); + console.error(`received unexpected message during handshake phase from the extension host: `, msg); }); }); @@ -632,58 +585,7 @@ export class LocalProcessExtensionHost implements IExtensionHost { return withNullAsUndefined(this._inspectPort); } - private terminate(): void { - if (this._terminating) { - return; - } - this._terminating = true; - - this._toDispose.dispose(); - - if (!this._messageProtocol) { - // .start() was not called - return; - } - - this._messageProtocol.then((protocol) => { - - // Send the extension host a request to terminate itself - // (graceful termination) - protocol.send(createMessageOfType(MessageType.Terminate)); - - protocol.getSocket().dispose(); - - protocol.dispose(); - - // Give the extension host 10s, after which we will - // try to kill the process and release any resources - setTimeout(() => this._cleanResources(), 10 * 1000); - - }, (err) => { - - // Establishing a protocol with the extension host failed, so - // try to kill the process and release any resources. - this._cleanResources(); - }); - } - - private _cleanResources(): void { - if (this._namedPipeServer) { - this._namedPipeServer.close(); - this._namedPipeServer = null; - } - if (this._extensionHostConnection) { - this._extensionHostConnection.end(); - this._extensionHostConnection = null; - } - if (this._extensionHostProcess) { - this._extensionHostProcess.kill(); - this._extensionHostProcess = null; - } - } - private _onWillShutdown(event: WillShutdownEvent): void { - // If the extension development host was started without debugger attached we need // to communicate this back to the main side to terminate the debug session if (this._isExtensionDevHost && !this._isExtensionDevTestFromCli && !this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { @@ -692,3 +594,63 @@ export class LocalProcessExtensionHost implements IExtensionHost { } } } + +export interface IExtHostCommunication { + readonly useUtilityProcess: boolean; + prepare(): Promise; + establishProtocol(prepared: T, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise; +} + +export class ExtHostMessagePortCommunication extends Disposable implements IExtHostCommunication { + + readonly useUtilityProcess = true; + + constructor( + @ILogService private readonly _logService: ILogService + ) { + super(); + } + + async prepare(): Promise { + } + + establishProtocol(prepared: void, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise { + + opts.env['VSCODE_WILL_SEND_MESSAGE_PORT'] = 'true'; + + // Get ready to acquire the message port from the shared process worker + const portPromise = acquirePort(undefined /* we trigger the request via service call! */, opts.responseChannel, opts.responseNonce); + + return new Promise((resolve, reject) => { + + const handle = setTimeout(() => { + reject('The local extension host took longer than 60s to connect.'); + }, 60 * 1000); + + portPromise.then((port) => { + clearTimeout(handle); + + const onMessage = new BufferedEmitter(); + port.onmessage = ((e) => onMessage.fire(VSBuffer.wrap(e.data))); + port.start(); + + resolve({ + onMessage: onMessage.event, + send: message => port.postMessage(message.buffer), + }); + }); + + // Now that the message port listener is installed, start the ext host process + const sw = StopWatch.create(false); + extensionHostProcess.start(opts).then(() => { + const duration = sw.elapsed(); + if (platform.isCI) { + this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`); + } + }, (err) => { + // Starting the ext host process resulted in an error + reject(err); + }); + }); + } +} diff --git a/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts new file mode 100644 index 00000000000..ea51d7abc8f --- /dev/null +++ b/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ElectronExtensionService } from 'vs/workbench/services/extensions/electron-sandbox/electronExtensionService'; + +export class SandboxExtensionService extends ElectronExtensionService { +} + +registerSingleton(IExtensionService, SandboxExtensionService); diff --git a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts index d3428409896..e70dd761951 100644 --- a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts +++ b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts @@ -203,6 +203,7 @@ export class LanguageDetectionWorkerHost { async sendTelemetryEvent(languages: string[], confidences: number[], timeSpent: number): Promise { type LanguageDetectionStats = { languages: string; confidences: string; timeSpent: number }; type LanguageDetectionStatsClassification = { + owner: 'TylerLeonhardt'; languages: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; confidences: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; timeSpent: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; @@ -337,6 +338,7 @@ export class LanguageDetectionWorkerClient extends EditorWorkerClient { } type LanguageDetectionPerfClassification = { + owner: 'TylerLeonhardt'; timeSpent: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; detection: { classification: 'SystemMetaData'; purpose: 'FeatureInsight' }; }; diff --git a/src/vs/workbench/services/localizations/electron-sandbox/localizationsService.ts b/src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts similarity index 68% rename from src/vs/workbench/services/localizations/electron-sandbox/localizationsService.ts rename to src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts index 5b716004793..b71303b3a90 100644 --- a/src/vs/workbench/services/localizations/electron-sandbox/localizationsService.ts +++ b/src/vs/workbench/services/localization/electron-sandbox/languagePackService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; -registerSharedProcessRemoteService(ILocalizationsService, 'localizations', { supportsDelayedInstantiation: true }); +registerSharedProcessRemoteService(ILanguagePackService, 'languagePacks', { supportsDelayedInstantiation: true }); diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 555a3a7ee20..27785f847cc 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -304,6 +304,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic async openGlobalKeybindingSettings(textual: boolean, options?: IKeybindingsEditorOptions): Promise { type OpenKeybindingsClassification = { + owner: 'sandy081'; textual: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; this.telemetryService.publicLog2<{ textual: boolean }, OpenKeybindingsClassification>('openKeybindings', { textual }); diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 5aaf1198fe4..06b43562999 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -87,7 +87,7 @@ export interface ISetting { enumItemLabels?: string[]; allKeysAreBoolean?: boolean; editPresentation?: EditPresentationTypes; - defaultValueSource?: string | IExtensionInfo; + nonLanguageSpecificDefaultValueSource?: string | IExtensionInfo; isLanguageTagSetting?: boolean; categoryOrder?: number; categoryLabel?: string; diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index d93923deb81..9fb02061b6e 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -751,7 +751,7 @@ export class DefaultSettings extends Disposable { allKeysAreBoolean, editPresentation: prop.editPresentation, order: prop.order, - defaultValueSource, + nonLanguageSpecificDefaultValueSource: defaultValueSource, isLanguageTagSetting, categoryLabel, categoryOrder diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index 282bbfbe40e..cf0aad3563a 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -288,6 +288,7 @@ export class SearchService extends Disposable implements ISearchService { const cacheStats: ICachedSearchStats = fileSearchStats.detailStats as ICachedSearchStats; type CachedSearchCompleteClassifcation = { + owner: 'roblourens'; reason?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; resultCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; workspaceFolderCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; @@ -330,6 +331,7 @@ export class SearchService extends Disposable implements ISearchService { const searchEngineStats: ISearchEngineStats = fileSearchStats.detailStats as ISearchEngineStats; type SearchCompleteClassification = { + owner: 'roblourens'; reason?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; resultCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; workspaceFolderCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; @@ -387,6 +389,7 @@ export class SearchService extends Disposable implements ISearchService { } type TextSearchCompleteClassification = { + owner: 'roblourens'; reason?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth' }; workspaceFolderCount: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; endToEndTime: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; isMeasurement: true }; diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 901f92d9f3e..e2b130592fb 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -579,6 +579,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { const key = themeType + themeData.extensionId; if (!this.themeExtensionsActivated.get(key)) { type ActivatePluginClassification = { + owner: 'aeschli'; id: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; name: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight' }; isBuiltin: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index be619fd1188..08723845be3 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -514,6 +514,7 @@ export abstract class AbstractTimerService implements ITimerService { // report IStartupMetrics as telemetry /* __GDPR__ "startupTimeVaried" : { + "owner": "jrieken", "${include}": [ "${IStartupMetrics}" ] diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 482be496d9b..d90996fd7ab 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -37,11 +37,13 @@ import { ICredentialsService } from 'vs/platform/credentials/common/credentials' import { CancellationError } from 'vs/base/common/errors'; type UserAccountClassification = { + owner: 'sandy081'; id: { classification: 'EndUserPseudonymizedInformation'; purpose: 'BusinessInsight' }; providerId: { classification: 'EndUserPseudonymizedInformation'; purpose: 'BusinessInsight' }; }; type FirstTimeSyncClassification = { + owner: 'sandy081'; action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true }; }; @@ -617,7 +619,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat } private async onDidSuccessiveAuthFailures(): Promise { - this.telemetryService.publicLog2('sync/successiveAuthFailures'); + this.telemetryService.publicLog2<{}, { owner: 'sandy081' }>('sync/successiveAuthFailures'); this.currentSessionId = undefined; await this.update(); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 75b3b27affa..6b7b44d4155 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -37,7 +37,7 @@ import 'vs/workbench/workbench.sandbox.main'; // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -import 'vs/workbench/services/extensions/electron-browser/extensionService'; +import 'vs/workbench/services/extensions/electron-browser/nativeExtensionService'; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // diff --git a/src/vs/workbench/workbench.desktop.sandbox.main.ts b/src/vs/workbench/workbench.desktop.sandbox.main.ts index 79258547199..894e6785212 100644 --- a/src/vs/workbench/workbench.desktop.sandbox.main.ts +++ b/src/vs/workbench/workbench.desktop.sandbox.main.ts @@ -27,12 +27,6 @@ import 'vs/workbench/electron-sandbox/desktop.main'; //#region --- workbench services -import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -// TODO@bpasero sandbox: remove me when extension host is present -class SimpleExtensionService extends NullExtensionService { } - -registerSingleton(IExtensionService, SimpleExtensionService); +import 'vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService'; //#endregion diff --git a/src/vs/workbench/workbench.sandbox.main.ts b/src/vs/workbench/workbench.sandbox.main.ts index e0708193c34..dd9ddd715b1 100644 --- a/src/vs/workbench/workbench.sandbox.main.ts +++ b/src/vs/workbench/workbench.sandbox.main.ts @@ -58,7 +58,7 @@ import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionMana import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService'; import 'vs/workbench/services/credentials/electron-sandbox/credentialsService'; import 'vs/workbench/services/encryption/electron-sandbox/encryptionService'; -import 'vs/workbench/services/localizations/electron-sandbox/localizationsService'; +import 'vs/workbench/services/localization/electron-sandbox/languagePackService'; import 'vs/workbench/services/telemetry/electron-sandbox/telemetryService'; import 'vs/workbench/services/extensions/electron-sandbox/extensionHostStarter'; import 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; @@ -98,7 +98,7 @@ registerSingleton(IUserDataInitializationService, UserDataInitializationService) import 'vs/workbench/contrib/logs/electron-sandbox/logs.contribution'; // Localizations -import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; +import 'vs/workbench/contrib/localization/electron-sandbox/localization.contribution'; // Explorer import 'vs/workbench/contrib/files/electron-sandbox/files.contribution'; diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 3d7b87599f1..292d369a557 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -4498,6 +4498,144 @@ declare module 'vscode' { resolveCompletionItem?(item: T, token: CancellationToken): ProviderResult; } + + /** + * The inline completion item provider interface defines the contract between extensions and + * the inline completion feature. + * + * Providers are asked for completions either explicitly by a user gesture or implicitly when typing. + */ + export interface InlineCompletionItemProvider { + + /** + * Provides inline completion items for the given position and document. + * If inline completions are enabled, this method will be called whenever the user stopped typing. + * It will also be called when the user explicitly triggers inline completions or explicitly asks for the next or previous inline completion. + * In that case, all available inline completions should be returned. + * `context.triggerKind` can be used to distinguish between these scenarios. + * + * @param document The document inline completions are requested for. + * @param position The position inline completions are requested for. + * @param context A context object with additional information. + * @param token A cancellation token. + * @return An array of completion items or a thenable that resolves to an array of completion items. + */ + provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult; + } + + /** + * Represents a collection of {@link InlineCompletionItem inline completion items} to be presented + * in the editor. + */ + export class InlineCompletionList { + /** + * The inline completion items. + */ + items: InlineCompletionItem[]; + + /** + * Creates a new list of inline completion items. + */ + constructor(items: InlineCompletionItem[]); + } + + /** + * Provides information about the context in which an inline completion was requested. + */ + export interface InlineCompletionContext { + /** + * Describes how the inline completion was triggered. + */ + readonly triggerKind: InlineCompletionTriggerKind; + + /** + * Provides information about the currently selected item in the autocomplete widget if it is visible. + * + * If set, provided inline completions must extend the text of the selected item + * and use the same range, otherwise they are not shown as preview. + * As an example, if the document text is `console.` and the selected item is `.log` replacing the `.` in the document, + * the inline completion must also replace `.` and start with `.log`, for example `.log()`. + * + * Inline completion providers are requested again whenever the selected item changes. + */ + readonly selectedCompletionInfo: SelectedCompletionInfo | undefined; + } + + /** + * Describes the currently selected completion item. + */ + export interface SelectedCompletionInfo { + /** + * The range that will be replaced if this completion item is accepted. + */ + readonly range: Range; + + /** + * The text the range will be replaced with if this completion is accepted. + */ + readonly text: string; + } + + /** + * Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. + */ + export enum InlineCompletionTriggerKind { + /** + * Completion was triggered explicitly by a user gesture. + * Return multiple completion items to enable cycling through them. + */ + Invoke = 0, + + /** + * Completion was triggered automatically while editing. + * It is sufficient to return a single completion item in this case. + */ + Automatic = 1, + } + + /** + * An inline completion item represents a text snippet that is proposed inline to complete text that is being typed. + * + * @see {@link InlineCompletionItemProvider.provideInlineCompletionItems} + */ + export class InlineCompletionItem { + /** + * The text to replace the range with. Must be set. + * Is used both for the preview and the accept operation. + */ + insertText: string | SnippetString; + + /** + * A text that is used to decide if this inline completion should be shown. When `falsy` + * the {@link InlineCompletionItem.insertText} is used. + * + * An inline completion is shown if the text to replace is a prefix of the filter text. + */ + filterText?: string; + + /** + * The range to replace. + * Must begin and end on the same line. + * + * Prefer replacements over insertions to provide a better experience when the user deletes typed text. + */ + range?: Range; + + /** + * An optional {@link Command} that is executed *after* inserting this completion. + */ + command?: Command; + + /** + * Creates a new inline completion item. + * + * @param insertText The text to replace the range with. + * @param range The range to replace. If not set, the word at the requested position will be used. + * @param command An optional {@link Command} that is executed *after* inserting this completion. + */ + constructor(insertText: string | SnippetString, range?: Range, command?: Command); + } + /** * A document link is a range in a text document that links to an internal or external resource, like another * text document or a web site. @@ -12202,6 +12340,19 @@ declare module 'vscode' { */ export function registerCompletionItemProvider(selector: DocumentSelector, provider: CompletionItemProvider, ...triggerCharacters: string[]): Disposable; + /** + * Registers an inline completion provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An inline completion provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerInlineCompletionItemProvider(selector: DocumentSelector, provider: InlineCompletionItemProvider): Disposable; + /** * Register a code action provider. * @@ -12587,7 +12738,6 @@ declare module 'vscode' { * @return A {@link Disposable} that unsets this configuration. */ export function setLanguageConfiguration(language: string, configuration: LanguageConfiguration): Disposable; - } /** diff --git a/src/vscode-dts/vscode.proposed.documentPaste.d.ts b/src/vscode-dts/vscode.proposed.documentPaste.d.ts new file mode 100644 index 00000000000..1777c8d4145 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.documentPaste.d.ts @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/30066/ + + /** + * Provider invoked when the user copies and pastes code. + */ + interface DocumentPasteEditProvider { + + /** + * Optional method invoked after the user copies text in a file. + * + * During {@link prepareDocumentPaste}, an extension can compute metadata that is attached to + * a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}. + * + * @param document Document where the copy took place. + * @param range Range being copied in the `document`. + * @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}. + * @param token A cancellation token. + */ + prepareDocumentPaste?(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): void | Thenable; + + /** + * Invoked before the user pastes into a document. + * + * In this method, extensions can return a workspace edit that replaces the standard pasting behavior. + * + * @param document Document being pasted into + * @param range Currently selected range in the document. + * @param dataTransfer The data transfer associated with the paste. + * @param token A cancellation token. + * + * @return Optional workspace edit that applies the paste. Return undefined to use standard pasting. + */ + provideDocumentPasteEdits(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult; + } + + namespace languages { + export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider): Disposable; + } +} diff --git a/src/vscode-dts/vscode.proposed.inlineCompletions.d.ts b/src/vscode-dts/vscode.proposed.inlineCompletions.d.ts deleted file mode 100644 index c070547c967..00000000000 --- a/src/vscode-dts/vscode.proposed.inlineCompletions.d.ts +++ /dev/null @@ -1,162 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - // https://github.com/microsoft/vscode/issues/124024 @hediet @alexdima - - export namespace languages { - - /** - * Registers an inline completion provider. - * - * Multiple providers can be registered for a language. In that case providers are asked in - * parallel and the results are merged. A failing provider (rejected promise or exception) will - * not cause a failure of the whole operation. - * - * @param selector A selector that defines the documents this provider is applicable to. - * @param provider An inline completion provider. - * @return A {@link Disposable} that unregisters this provider when being disposed. - */ - export function registerInlineCompletionItemProvider(selector: DocumentSelector, provider: InlineCompletionItemProvider): Disposable; - } - - /** - * The inline completion item provider interface defines the contract between extensions and - * the inline completion feature. - * - * Providers are asked for completions either explicitly by a user gesture or implicitly when typing. - */ - export interface InlineCompletionItemProvider { - - /** - * Provides inline completion items for the given position and document. - * If inline completions are enabled, this method will be called whenever the user stopped typing. - * It will also be called when the user explicitly triggers inline completions or explicitly asks for the next or previous inline completion. - * In that case, all available inline completions should be returned. - * `context.triggerKind` can be used to distinguish between these scenarios. - * - * @param document The document inline completions are requested for. - * @param position The position inline completions are requested for. - * @param context A context object with additional information. - * @param token A cancellation token. - * @return An array of completion items or a thenable that resolves to an array of completion items. - */ - provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult; - } - - /** - * Represents a collection of {@link InlineCompletionItem inline completion items} to be presented - * in the editor. - */ - export class InlineCompletionList { - /** - * The inline completion items. - */ - items: InlineCompletionItem[]; - - /** - * Creates a new list of inline completion items. - */ - constructor(items: InlineCompletionItem[]); - } - - /** - * Provides information about the context in which an inline completion was requested. - */ - export interface InlineCompletionContext { - /** - * Describes how the inline completion was triggered. - */ - readonly triggerKind: InlineCompletionTriggerKind; - - /** - * Provides information about the currently selected item in the autocomplete widget if it is visible. - * - * If set, provided inline completions must extend the text of the selected item - * and use the same range, otherwise they are not shown as preview. - * As an example, if the document text is `console.` and the selected item is `.log` replacing the `.` in the document, - * the inline completion must also replace `.` and start with `.log`, for example `.log()`. - * - * Inline completion providers are requested again whenever the selected item changes. - */ - readonly selectedCompletionInfo: SelectedCompletionInfo | undefined; - } - - /** - * Describes the currently selected completion item. - */ - export interface SelectedCompletionInfo { - /** - * The range that will be replaced if this completion item is accepted. - */ - readonly range: Range; - - /** - * The text the range will be replaced with if this completion is accepted. - */ - readonly text: string; - } - - /** - * Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. - */ - export enum InlineCompletionTriggerKind { - /** - * Completion was triggered explicitly by a user gesture. - * Return multiple completion items to enable cycling through them. - */ - Invoke = 0, - - /** - * Completion was triggered automatically while editing. - * It is sufficient to return a single completion item in this case. - */ - Automatic = 1, - } - - /** - * An inline completion item represents a text snippet that is proposed inline to complete text that is being typed. - * - * @see {@link InlineCompletionItemProvider.provideInlineCompletionItems} - */ - export class InlineCompletionItem { - /** - * The text to replace the range with. Must be set. - * Is used both for the preview and the accept operation. - */ - insertText: string | SnippetString; - - /** - * A text that is used to decide if this inline completion should be shown. When `falsy` - * the {@link InlineCompletionItem.insertText} is used. - * - * An inline completion is shown if the text to replace is a prefix of the filter text. - */ - filterText?: string; - - /** - * The range to replace. - * Must begin and end on the same line. - * - * Prefer replacements over insertions to provide a better experience when the user deletes typed text. - */ - range?: Range; - - /** - * An optional {@link Command} that is executed *after* inserting this completion. - */ - command?: Command; - - /** - * Creates a new inline completion item. - * - * @param insertText The text to replace the range with. - * @param range The range to replace. If not set, the word at the requested position will be used. - * @param command An optional {@link Command} that is executed *after* inserting this completion. - */ - constructor(insertText: string | SnippetString, range?: Range, command?: Command); - } -} diff --git a/src/vscode-dts/vscode.proposed.scmInput.d.ts b/src/vscode-dts/vscode.proposed.scmInput.d.ts new file mode 100644 index 00000000000..6efdb57ae45 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.scmInput.d.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/150268 + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * Controls whether the input box is enabled (default is `true`). + */ + enabled: boolean; + } +} diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index be81bb17d4c..a6c86ba20d1 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -9,11 +9,11 @@ import { installAllHandlers } from '../../utils'; export function setup(logger: Logger) { describe('Localization', () => { - // Shared before/after handling installAllHandlers(logger); - it('starts with "DE" locale and verifies title and viewlets text is in German', async function () { + // skipped until translations are available https://github.com/microsoft/vscode/issues/150324 + it.skip('starts with "DE" locale and verifies title and viewlets text is in German', async function () { const app = this.app as Application; await app.workbench.extensions.openExtensionsViewlet();