mirror of
https://github.com/coder/code-server.git
synced 2026-05-12 07:17:26 +02:00
Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
149
lib/vscode/src/vs/platform/commands/common/commands.ts
Normal file
149
lib/vscode/src/vs/platform/commands/common/commands.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TypeConstraint, validateConstraints } from 'vs/base/common/types';
|
||||
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
|
||||
export const ICommandService = createDecorator<ICommandService>('commandService');
|
||||
|
||||
export interface ICommandEvent {
|
||||
commandId: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export interface ICommandService {
|
||||
readonly _serviceBrand: undefined;
|
||||
onWillExecuteCommand: Event<ICommandEvent>;
|
||||
onDidExecuteCommand: Event<ICommandEvent>;
|
||||
executeCommand<T = any>(commandId: string, ...args: any[]): Promise<T | undefined>;
|
||||
}
|
||||
|
||||
export type ICommandsMap = Map<string, ICommand>;
|
||||
|
||||
export interface ICommandHandler {
|
||||
(accessor: ServicesAccessor, ...args: any[]): void;
|
||||
}
|
||||
|
||||
export interface ICommand {
|
||||
id: string;
|
||||
handler: ICommandHandler;
|
||||
description?: ICommandHandlerDescription | null;
|
||||
}
|
||||
|
||||
export interface ICommandHandlerDescription {
|
||||
readonly description: string;
|
||||
readonly args: ReadonlyArray<{
|
||||
readonly name: string;
|
||||
readonly description?: string;
|
||||
readonly constraint?: TypeConstraint;
|
||||
readonly schema?: IJSONSchema;
|
||||
}>;
|
||||
readonly returns?: string;
|
||||
}
|
||||
|
||||
export interface ICommandRegistry {
|
||||
onDidRegisterCommand: Event<string>;
|
||||
registerCommand(id: string, command: ICommandHandler): IDisposable;
|
||||
registerCommand(command: ICommand): IDisposable;
|
||||
registerCommandAlias(oldId: string, newId: string): IDisposable;
|
||||
getCommand(id: string): ICommand | undefined;
|
||||
getCommands(): ICommandsMap;
|
||||
}
|
||||
|
||||
export const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {
|
||||
|
||||
private readonly _commands = new Map<string, LinkedList<ICommand>>();
|
||||
|
||||
private readonly _onDidRegisterCommand = new Emitter<string>();
|
||||
readonly onDidRegisterCommand: Event<string> = this._onDidRegisterCommand.event;
|
||||
|
||||
registerCommand(idOrCommand: string | ICommand, handler?: ICommandHandler): IDisposable {
|
||||
|
||||
if (!idOrCommand) {
|
||||
throw new Error(`invalid command`);
|
||||
}
|
||||
|
||||
if (typeof idOrCommand === 'string') {
|
||||
if (!handler) {
|
||||
throw new Error(`invalid command`);
|
||||
}
|
||||
return this.registerCommand({ id: idOrCommand, handler });
|
||||
}
|
||||
|
||||
// add argument validation if rich command metadata is provided
|
||||
if (idOrCommand.description) {
|
||||
const constraints: Array<TypeConstraint | undefined> = [];
|
||||
for (let arg of idOrCommand.description.args) {
|
||||
constraints.push(arg.constraint);
|
||||
}
|
||||
const actualHandler = idOrCommand.handler;
|
||||
idOrCommand.handler = function (accessor, ...args: any[]) {
|
||||
validateConstraints(args, constraints);
|
||||
return actualHandler(accessor, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
// find a place to store the command
|
||||
const { id } = idOrCommand;
|
||||
|
||||
let commands = this._commands.get(id);
|
||||
if (!commands) {
|
||||
commands = new LinkedList<ICommand>();
|
||||
this._commands.set(id, commands);
|
||||
}
|
||||
|
||||
let removeFn = commands.unshift(idOrCommand);
|
||||
|
||||
let ret = toDisposable(() => {
|
||||
removeFn();
|
||||
const command = this._commands.get(id);
|
||||
if (command?.isEmpty()) {
|
||||
this._commands.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
// tell the world about this command
|
||||
this._onDidRegisterCommand.fire(id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
registerCommandAlias(oldId: string, newId: string): IDisposable {
|
||||
return CommandsRegistry.registerCommand(oldId, (accessor, ...args) => accessor.get(ICommandService).executeCommand(newId, ...args));
|
||||
}
|
||||
|
||||
getCommand(id: string): ICommand | undefined {
|
||||
const list = this._commands.get(id);
|
||||
if (!list || list.isEmpty()) {
|
||||
return undefined;
|
||||
}
|
||||
return Iterable.first(list);
|
||||
}
|
||||
|
||||
getCommands(): ICommandsMap {
|
||||
const result = new Map<string, ICommand>();
|
||||
for (const key of this._commands.keys()) {
|
||||
const command = this.getCommand(key);
|
||||
if (command) {
|
||||
result.set(key, command);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export const NullCommandService: ICommandService = {
|
||||
_serviceBrand: undefined,
|
||||
onWillExecuteCommand: () => Disposable.None,
|
||||
onDidExecuteCommand: () => Disposable.None,
|
||||
executeCommand() {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user