未验证 提交 6a25cfa6 编写于 作者: J Johannes Rieken 提交者: GitHub

Merge pull request #72345 from hedgerh/command-execute-events

onDidExecuteCommand API
......@@ -234,7 +234,9 @@ export class StandaloneCommandService implements ICommandService {
private readonly _dynamicCommands: { [id: string]: ICommand; };
private readonly _onWillExecuteCommand = new Emitter<ICommandEvent>();
private readonly _onDidExecuteCommand = new Emitter<ICommandEvent>();
public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
public readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
constructor(instantiationService: IInstantiationService) {
this._instantiationService = instantiationService;
......@@ -256,8 +258,10 @@ export class StandaloneCommandService implements ICommandService {
}
try {
this._onWillExecuteCommand.fire({ commandId: id });
this._onWillExecuteCommand.fire({ commandId: id, args });
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T;
this._onDidExecuteCommand.fire({ commandId: id, args });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
......
......@@ -32,6 +32,9 @@ export class TestCommandService implements ICommandService {
private readonly _onWillExecuteCommand = new Emitter<ICommandEvent>();
public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
private readonly _onDidExecuteCommand = new Emitter<ICommandEvent>();
public readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
constructor(instantiationService: IInstantiationService) {
this._instantiationService = instantiationService;
}
......@@ -43,8 +46,9 @@ export class TestCommandService implements ICommandService {
}
try {
this._onWillExecuteCommand.fire({ commandId: id });
this._onWillExecuteCommand.fire({ commandId: id, args });
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T;
this._onDidExecuteCommand.fire({ commandId: id, args });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
......
......@@ -17,6 +17,7 @@ suite('OpenerService', function () {
const commandService = new class implements ICommandService {
_serviceBrand: any;
onWillExecuteCommand = () => ({ dispose: () => { } });
onDidExecuteCommand = () => ({ dispose: () => { } });
executeCommand(id: string, ...args: any[]): Promise<any> {
lastCommand = { id, args };
return Promise.resolve(undefined);
......
......@@ -15,11 +15,13 @@ export const ICommandService = createDecorator<ICommandService>('commandService'
export interface ICommandEvent {
commandId: string;
args: any[];
}
export interface ICommandService {
_serviceBrand: any;
onWillExecuteCommand: Event<ICommandEvent>;
onDidExecuteCommand: Event<ICommandEvent>;
executeCommand<T = any>(commandId: string, ...args: any[]): Promise<T | undefined>;
}
......@@ -135,6 +137,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
export const NullCommandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
onDidExecuteCommand: () => ({ dispose: () => { } }),
executeCommand() {
return Promise.resolve(undefined);
}
......
......@@ -121,6 +121,7 @@ suite('AbstractKeybindingService', () => {
let commandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
onDidExecuteCommand: () => ({ dispose: () => { } }),
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
executeCommandCalls.push({
commandId: commandId,
......
......@@ -565,6 +565,22 @@ declare module 'vscode' {
//#endregion
//#region Joh: onDidExecuteCommand
export interface CommandExecutionEvent {
command: string;
arguments: any[];
}
export namespace commands {
/**
* An event that is emitted when a [command](#Command) is executed.
*/
export const onDidExecuteCommand: Event<CommandExecutionEvent>;
}
//#endregion
//#region Joh: decorations
//todo@joh -> make class
......
......@@ -15,6 +15,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
private readonly _commandRegistrations = new Map<string, IDisposable>();
private readonly _generateCommandsDocumentationRegistration: IDisposable;
private readonly _proxy: ExtHostCommandsShape;
private _onDidExecuteCommandListener?: IDisposable;
constructor(
extHostContext: IExtHostContext,
......@@ -77,6 +78,19 @@ export class MainThreadCommands implements MainThreadCommandsShape {
return this._commandService.executeCommand<T>(id, ...args);
}
$registerCommandListener() {
if (!this._onDidExecuteCommandListener) {
this._onDidExecuteCommandListener = this._commandService.onDidExecuteCommand(command => this._proxy.$handleDidExecuteCommand(command));
}
}
$unregisterCommandListener() {
if (this._onDidExecuteCommandListener) {
this._onDidExecuteCommandListener.dispose();
this._onDidExecuteCommandListener = undefined;
}
}
$getCommands(): Promise<string[]> {
return Promise.resolve([...CommandsRegistry.getCommands().keys()]);
}
......
......@@ -21,7 +21,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model'
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import * as modes from 'vs/editor/common/modes';
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
......@@ -115,6 +115,8 @@ export interface MainThreadClipboardShape extends IDisposable {
export interface MainThreadCommandsShape extends IDisposable {
$registerCommand(id: string): void;
$registerCommandListener(): void;
$unregisterCommandListener(): void;
$unregisterCommand(id: string): void;
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined>;
$getCommands(): Promise<string[]>;
......@@ -736,6 +738,7 @@ export interface MainThreadWindowShape extends IDisposable {
export interface ExtHostCommandsShape {
$executeContributedCommand<T>(id: string, ...args: any[]): Promise<T>;
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>;
$handleDidExecuteCommand(command: ICommandEvent): void;
}
export interface ExtHostConfigurationShape {
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { validateConstraint } from 'vs/base/common/types';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { cloneAndChange } from 'vs/base/common/objects';
......@@ -17,6 +17,7 @@ import { revive } from 'vs/base/common/marshalling';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
interface CommandHandler {
......@@ -31,6 +32,9 @@ export interface ArgumentProcessor {
export class ExtHostCommands implements ExtHostCommandsShape {
private readonly _onDidExecuteCommand: Emitter<vscode.CommandExecutionEvent>;
readonly onDidExecuteCommand: Event<vscode.CommandExecutionEvent>;
private readonly _commands = new Map<string, CommandHandler>();
private readonly _proxy: MainThreadCommandsShape;
private readonly _converter: CommandsConverter;
......@@ -42,6 +46,11 @@ export class ExtHostCommands implements ExtHostCommandsShape {
logService: ILogService
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadCommands);
this._onDidExecuteCommand = new Emitter<vscode.CommandExecutionEvent>({
onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(),
onLastListenerRemove: () => this._proxy.$unregisterCommandListener(),
});
this.onDidExecuteCommand = this._onDidExecuteCommand.event;
this._logService = logService;
this._converter = new CommandsConverter(this);
this._argumentProcessors = [
......@@ -106,6 +115,10 @@ export class ExtHostCommands implements ExtHostCommandsShape {
});
}
$handleDidExecuteCommand(command: ICommandEvent): void {
this._onDidExecuteCommand.fire({ command: command.commandId, arguments: command.args });
}
executeCommand<T>(id: string, ...args: any[]): Promise<T> {
this._logService.trace('ExtHostCommands#executeCommand', id);
......@@ -154,6 +167,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
try {
const result = callback.apply(thisArg, args);
this._onDidExecuteCommand.fire({ command: id, arguments: args });
return Promise.resolve(result);
} catch (err) {
this._logService.error(err, id);
......
......@@ -244,7 +244,11 @@ export function createApiFactory(
},
getCommands(filterInternal: boolean = false): Thenable<string[]> {
return extHostCommands.getCommands(filterInternal);
}
},
onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => {
checkProposedApiEnabled(extension);
return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables);
}),
};
// namespace: env
......
......@@ -22,6 +22,9 @@ export class CommandService extends Disposable implements ICommandService {
private readonly _onWillExecuteCommand: Emitter<ICommandEvent> = this._register(new Emitter<ICommandEvent>());
public readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
private readonly _onDidExecuteCommand: Emitter<ICommandEvent> = new Emitter<ICommandEvent>();
public readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IExtensionService private readonly _extensionService: IExtensionService,
......@@ -77,8 +80,9 @@ export class CommandService extends Disposable implements ICommandService {
return Promise.reject(new Error(`command '${id}' not found`));
}
try {
this._onWillExecuteCommand.fire({ commandId: id });
this._onWillExecuteCommand.fire({ commandId: id, args });
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]);
this._onDidExecuteCommand.fire({ commandId: id, args });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
......
......@@ -523,6 +523,7 @@ class MockCommandService implements ICommandService {
public callCount = 0;
onWillExecuteCommand = () => Disposable.None;
onDidExecuteCommand = () => Disposable.None;
public executeCommand(commandId: string, ...args: any[]): Promise<any> {
this.callCount++;
......
......@@ -26,6 +26,7 @@ const emptyDialogService = new class implements IDialogService {
const emptyCommandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
onDidExecuteCommand: () => ({ dispose: () => { } }),
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
return Promise.resolve(undefined);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册