Skip to content

Commit 6a25cfa

Browse files
authored
Merge pull request microsoft#72345 from hedgerh/command-execute-events
onDidExecuteCommand API
2 parents e0b6026 + 7beb320 commit 6a25cfa

13 files changed

Lines changed: 76 additions & 6 deletions

File tree

src/vs/editor/standalone/browser/simpleServices.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ export class StandaloneCommandService implements ICommandService {
234234
private readonly _dynamicCommands: { [id: string]: ICommand; };
235235

236236
private readonly _onWillExecuteCommand = new Emitter<ICommandEvent>();
237+
private readonly _onDidExecuteCommand = new Emitter<ICommandEvent>();
237238
public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
239+
public readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
238240

239241
constructor(instantiationService: IInstantiationService) {
240242
this._instantiationService = instantiationService;
@@ -256,8 +258,10 @@ export class StandaloneCommandService implements ICommandService {
256258
}
257259

258260
try {
259-
this._onWillExecuteCommand.fire({ commandId: id });
261+
this._onWillExecuteCommand.fire({ commandId: id, args });
260262
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T;
263+
264+
this._onDidExecuteCommand.fire({ commandId: id, args });
261265
return Promise.resolve(result);
262266
} catch (err) {
263267
return Promise.reject(err);

src/vs/editor/test/browser/editorTestServices.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export class TestCommandService implements ICommandService {
3232
private readonly _onWillExecuteCommand = new Emitter<ICommandEvent>();
3333
public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
3434

35+
private readonly _onDidExecuteCommand = new Emitter<ICommandEvent>();
36+
public readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
37+
3538
constructor(instantiationService: IInstantiationService) {
3639
this._instantiationService = instantiationService;
3740
}
@@ -43,8 +46,9 @@ export class TestCommandService implements ICommandService {
4346
}
4447

4548
try {
46-
this._onWillExecuteCommand.fire({ commandId: id });
49+
this._onWillExecuteCommand.fire({ commandId: id, args });
4750
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T;
51+
this._onDidExecuteCommand.fire({ commandId: id, args });
4852
return Promise.resolve(result);
4953
} catch (err) {
5054
return Promise.reject(err);

src/vs/editor/test/browser/services/openerService.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ suite('OpenerService', function () {
1717
const commandService = new class implements ICommandService {
1818
_serviceBrand: any;
1919
onWillExecuteCommand = () => ({ dispose: () => { } });
20+
onDidExecuteCommand = () => ({ dispose: () => { } });
2021
executeCommand(id: string, ...args: any[]): Promise<any> {
2122
lastCommand = { id, args };
2223
return Promise.resolve(undefined);

src/vs/platform/commands/common/commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ export const ICommandService = createDecorator<ICommandService>('commandService'
1515

1616
export interface ICommandEvent {
1717
commandId: string;
18+
args: any[];
1819
}
1920

2021
export interface ICommandService {
2122
_serviceBrand: any;
2223
onWillExecuteCommand: Event<ICommandEvent>;
24+
onDidExecuteCommand: Event<ICommandEvent>;
2325
executeCommand<T = any>(commandId: string, ...args: any[]): Promise<T | undefined>;
2426
}
2527

@@ -135,6 +137,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
135137
export const NullCommandService: ICommandService = {
136138
_serviceBrand: undefined,
137139
onWillExecuteCommand: () => ({ dispose: () => { } }),
140+
onDidExecuteCommand: () => ({ dispose: () => { } }),
138141
executeCommand() {
139142
return Promise.resolve(undefined);
140143
}

src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ suite('AbstractKeybindingService', () => {
121121
let commandService: ICommandService = {
122122
_serviceBrand: undefined,
123123
onWillExecuteCommand: () => ({ dispose: () => { } }),
124+
onDidExecuteCommand: () => ({ dispose: () => { } }),
124125
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
125126
executeCommandCalls.push({
126127
commandId: commandId,

src/vs/vscode.proposed.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,22 @@ declare module 'vscode' {
565565

566566
//#endregion
567567

568+
//#region Joh: onDidExecuteCommand
569+
570+
export interface CommandExecutionEvent {
571+
command: string;
572+
arguments: any[];
573+
}
574+
575+
export namespace commands {
576+
/**
577+
* An event that is emitted when a [command](#Command) is executed.
578+
*/
579+
export const onDidExecuteCommand: Event<CommandExecutionEvent>;
580+
}
581+
582+
//#endregion
583+
568584
//#region Joh: decorations
569585

570586
//todo@joh -> make class

src/vs/workbench/api/browser/mainThreadCommands.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
1515
private readonly _commandRegistrations = new Map<string, IDisposable>();
1616
private readonly _generateCommandsDocumentationRegistration: IDisposable;
1717
private readonly _proxy: ExtHostCommandsShape;
18+
private _onDidExecuteCommandListener?: IDisposable;
1819

1920
constructor(
2021
extHostContext: IExtHostContext,
@@ -77,6 +78,19 @@ export class MainThreadCommands implements MainThreadCommandsShape {
7778
return this._commandService.executeCommand<T>(id, ...args);
7879
}
7980

81+
$registerCommandListener() {
82+
if (!this._onDidExecuteCommandListener) {
83+
this._onDidExecuteCommandListener = this._commandService.onDidExecuteCommand(command => this._proxy.$handleDidExecuteCommand(command));
84+
}
85+
}
86+
87+
$unregisterCommandListener() {
88+
if (this._onDidExecuteCommandListener) {
89+
this._onDidExecuteCommandListener.dispose();
90+
this._onDidExecuteCommandListener = undefined;
91+
}
92+
}
93+
8094
$getCommands(): Promise<string[]> {
8195
return Promise.resolve([...CommandsRegistry.getCommands().keys()]);
8296
}

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model'
2121
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
2222
import * as modes from 'vs/editor/common/modes';
2323
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
24-
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
24+
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
2525
import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
2626
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
2727
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -115,6 +115,8 @@ export interface MainThreadClipboardShape extends IDisposable {
115115

116116
export interface MainThreadCommandsShape extends IDisposable {
117117
$registerCommand(id: string): void;
118+
$registerCommandListener(): void;
119+
$unregisterCommandListener(): void;
118120
$unregisterCommand(id: string): void;
119121
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined>;
120122
$getCommands(): Promise<string[]>;
@@ -736,6 +738,7 @@ export interface MainThreadWindowShape extends IDisposable {
736738
export interface ExtHostCommandsShape {
737739
$executeContributedCommand<T>(id: string, ...args: any[]): Promise<T>;
738740
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>;
741+
$handleDidExecuteCommand(command: ICommandEvent): void;
739742
}
740743

741744
export interface ExtHostConfigurationShape {

src/vs/workbench/api/common/extHostCommands.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { validateConstraint } from 'vs/base/common/types';
7-
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
7+
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
88
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
99
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
1010
import { cloneAndChange } from 'vs/base/common/objects';
@@ -17,6 +17,7 @@ import { revive } from 'vs/base/common/marshalling';
1717
import { Range } from 'vs/editor/common/core/range';
1818
import { Position } from 'vs/editor/common/core/position';
1919
import { URI } from 'vs/base/common/uri';
20+
import { Event, Emitter } from 'vs/base/common/event';
2021
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
2122

2223
interface CommandHandler {
@@ -31,6 +32,9 @@ export interface ArgumentProcessor {
3132

3233
export class ExtHostCommands implements ExtHostCommandsShape {
3334

35+
private readonly _onDidExecuteCommand: Emitter<vscode.CommandExecutionEvent>;
36+
readonly onDidExecuteCommand: Event<vscode.CommandExecutionEvent>;
37+
3438
private readonly _commands = new Map<string, CommandHandler>();
3539
private readonly _proxy: MainThreadCommandsShape;
3640
private readonly _converter: CommandsConverter;
@@ -42,6 +46,11 @@ export class ExtHostCommands implements ExtHostCommandsShape {
4246
logService: ILogService
4347
) {
4448
this._proxy = mainContext.getProxy(MainContext.MainThreadCommands);
49+
this._onDidExecuteCommand = new Emitter<vscode.CommandExecutionEvent>({
50+
onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(),
51+
onLastListenerRemove: () => this._proxy.$unregisterCommandListener(),
52+
});
53+
this.onDidExecuteCommand = this._onDidExecuteCommand.event;
4554
this._logService = logService;
4655
this._converter = new CommandsConverter(this);
4756
this._argumentProcessors = [
@@ -106,6 +115,10 @@ export class ExtHostCommands implements ExtHostCommandsShape {
106115
});
107116
}
108117

118+
$handleDidExecuteCommand(command: ICommandEvent): void {
119+
this._onDidExecuteCommand.fire({ command: command.commandId, arguments: command.args });
120+
}
121+
109122
executeCommand<T>(id: string, ...args: any[]): Promise<T> {
110123
this._logService.trace('ExtHostCommands#executeCommand', id);
111124

@@ -154,6 +167,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
154167

155168
try {
156169
const result = callback.apply(thisArg, args);
170+
this._onDidExecuteCommand.fire({ command: id, arguments: args });
157171
return Promise.resolve(result);
158172
} catch (err) {
159173
this._logService.error(err, id);

src/vs/workbench/api/node/extHost.api.impl.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,11 @@ export function createApiFactory(
244244
},
245245
getCommands(filterInternal: boolean = false): Thenable<string[]> {
246246
return extHostCommands.getCommands(filterInternal);
247-
}
247+
},
248+
onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => {
249+
checkProposedApiEnabled(extension);
250+
return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables);
251+
}),
248252
};
249253

250254
// namespace: env

0 commit comments

Comments
 (0)