diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index da1810c9f44..5207fb6f12f 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -242,7 +242,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // namespace: commands const commands: typeof vscode.commands = { registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { - return extHostCommands.registerCommand(true, id, command, thisArgs); + return extHostCommands.registerCommand(true, id, command, thisArgs, undefined, extension); }, registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable { return extHostCommands.registerCommand(true, id, (...args: any[]): any => { @@ -262,7 +262,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, (err) => { extHostLogService.warn('An error occurred while running command ' + id, err); }); - }); + }, undefined, undefined, extension); }, registerDiffInformationCommand: (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => { checkProposedApiEnabled(extension); @@ -275,7 +275,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const diff = await extHostEditors.getDiffInformation(activeTextEditor.id); callback.apply(thisArg, [diff, ...args]); - }); + }, undefined, undefined, extension); }, executeCommand(id: string, ...args: any[]): Thenable { return extHostCommands.executeCommand(id, ...args); diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index 3816f690683..1a4048a1c42 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -24,11 +24,14 @@ import { ISelection } from 'vs/editor/common/core/selection'; import { TestItemImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi'; import { VSBuffer } from 'vs/base/common/buffer'; import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; interface CommandHandler { callback: Function; thisArg: any; description?: ICommandHandlerDescription; + extension?: IExtensionDescription; } export interface ArgumentProcessor { @@ -130,7 +133,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { }); } - registerCommand(global: boolean, id: string, callback: (...args: any[]) => T | Thenable, thisArg?: any, description?: ICommandHandlerDescription): extHostTypes.Disposable { + registerCommand(global: boolean, id: string, callback: (...args: any[]) => T | Thenable, thisArg?: any, description?: ICommandHandlerDescription, extension?: IExtensionDescription): extHostTypes.Disposable { this._logService.trace('ExtHostCommands#registerCommand', id); if (!id.trim().length) { @@ -141,7 +144,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { throw new Error(`command '${id}' already exists`); } - this._commands.set(id, { callback, thisArg, description }); + this._commands.set(id, { callback, thisArg, description, extension }); if (global) { this._proxy.$registerCommand(id); } @@ -165,7 +168,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { if (this._commands.has(id)) { // we stay inside the extension host and support // to pass any kind of parameters around - return this._executeContributedCommand(id, args); + return this._executeContributedCommand(id, args, false); } else { // automagically convert some argument types @@ -207,7 +210,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { } } - private async _executeContributedCommand(id: string, args: any[]): Promise { + private async _executeContributedCommand(id: string, args: any[], annotateError: boolean): Promise { const command = this._commands.get(id); if (!command) { throw new Error('Unknown command'); @@ -234,8 +237,19 @@ export class ExtHostCommands implements ExtHostCommandsShape { id = actual.command; } } - this._logService.error(err, id); - throw new Error(`Running the contributed command: '${id}' failed.`); + this._logService.error(err, id, command.extension?.identifier); + + if (!annotateError) { + throw err; + } + + throw new class CommandError extends Error { + readonly id = id; + readonly source = command!.extension?.displayName ?? command!.extension?.name; + constructor() { + super(toErrorMessage(err)); + } + }; } } @@ -246,7 +260,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { return Promise.reject(new Error(`Contributed command '${id}' does not exist.`)); } else { args = args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg)); - return this._executeContributedCommand(id, args); + return this._executeContributedCommand(id, args, true); } }