UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

353 lines • 14.3 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2017 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandRegistry = exports.CommandService = exports.commandServicePath = exports.CommandContribution = exports.Command = void 0; const inversify_1 = require("inversify"); const event_1 = require("./event"); const disposable_1 = require("./disposable"); const contribution_provider_1 = require("./contribution-provider"); const nls_1 = require("./nls"); const debounce = require("p-debounce"); const types_1 = require("./types"); var Command; (function (Command) { /* Determine whether object is a Command */ function is(arg) { return (0, types_1.isObject)(arg) && 'id' in arg; } Command.is = is; /** Utility function to easily translate commands */ function toLocalizedCommand(command, nlsLabelKey = command.id, nlsCategoryKey) { return Object.assign(Object.assign({}, command), { label: command.label && nls_1.nls.localize(nlsLabelKey, command.label), originalLabel: command.label, category: nlsCategoryKey && command.category && nls_1.nls.localize(nlsCategoryKey, command.category) || command.category, originalCategory: command.category }); } Command.toLocalizedCommand = toLocalizedCommand; function toDefaultLocalizedCommand(command) { return Object.assign(Object.assign({}, command), { label: command.label && nls_1.nls.localizeByDefault(command.label), originalLabel: command.label, category: command.category && nls_1.nls.localizeByDefault(command.category), originalCategory: command.category }); } Command.toDefaultLocalizedCommand = toDefaultLocalizedCommand; /** Comparator function for when sorting commands */ function compareCommands(a, b) { if (a.label && b.label) { const aCommand = (a.category ? `${a.category}: ${a.label}` : a.label).toLowerCase(); const bCommand = (b.category ? `${b.category}: ${b.label}` : b.label).toLowerCase(); return (aCommand).localeCompare(bCommand); } else { return 0; } } Command.compareCommands = compareCommands; /** * Determine if two commands are equal. * * @param a the first command for comparison. * @param b the second command for comparison. */ function equals(a, b) { return (a.id === b.id && a.label === b.label && a.iconClass === b.iconClass && a.category === b.category); } Command.equals = equals; })(Command = exports.Command || (exports.Command = {})); exports.CommandContribution = Symbol('CommandContribution'); exports.commandServicePath = '/services/commands'; exports.CommandService = Symbol('CommandService'); /** * The command registry manages commands and handlers. */ let CommandRegistry = class CommandRegistry { constructor(contributionProvider) { this.contributionProvider = contributionProvider; this._commands = {}; this._handlers = {}; this.toUnregisterCommands = new Map(); // List of recently used commands. this._recent = []; this.onWillExecuteCommandEmitter = new event_1.Emitter(); this.onWillExecuteCommand = this.onWillExecuteCommandEmitter.event; this.onDidExecuteCommandEmitter = new event_1.Emitter(); this.onDidExecuteCommand = this.onDidExecuteCommandEmitter.event; this.onCommandsChangedEmitter = new event_1.Emitter(); this.onCommandsChanged = this.onCommandsChangedEmitter.event; this.fireDidChange = debounce(() => this.doFireDidChange(), 0); } onStart() { const contributions = this.contributionProvider.getContributions(); for (const contrib of contributions) { contrib.registerCommands(this); } } *getAllCommands() { var _a; for (const command of Object.values(this._commands)) { yield Object.assign(Object.assign({}, command), { handlers: (_a = this._handlers[command.id]) !== null && _a !== void 0 ? _a : [] }); } } /** * Register the given command and handler if present. * * Throw if a command is already registered for the given command identifier. */ registerCommand(command, handler) { if (this._commands[command.id]) { console.warn(`A command ${command.id} is already registered.`); return disposable_1.Disposable.NULL; } const toDispose = new disposable_1.DisposableCollection(this.doRegisterCommand(command)); if (handler) { toDispose.push(this.registerHandler(command.id, handler)); } this.toUnregisterCommands.set(command.id, toDispose); toDispose.push(disposable_1.Disposable.create(() => this.toUnregisterCommands.delete(command.id))); return toDispose; } doRegisterCommand(command) { this._commands[command.id] = command; return { dispose: () => { delete this._commands[command.id]; } }; } unregisterCommand(commandOrId) { const id = Command.is(commandOrId) ? commandOrId.id : commandOrId; const toUnregister = this.toUnregisterCommands.get(id); if (toUnregister) { toUnregister.dispose(); } } /** * Register the given handler for the given command identifier. * * If there is already a handler for the given command * then the given handler is registered as more specific, and * has higher priority during enablement, visibility and toggle state evaluations. */ registerHandler(commandId, handler) { let handlers = this._handlers[commandId]; if (!handlers) { this._handlers[commandId] = handlers = []; } handlers.unshift(handler); this.fireDidChange(); return { dispose: () => { const idx = handlers.indexOf(handler); if (idx >= 0) { handlers.splice(idx, 1); this.fireDidChange(); } } }; } doFireDidChange() { this.onCommandsChangedEmitter.fire(); } /** * Test whether there is an active handler for the given command. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isEnabled(command, ...args) { return typeof this.getActiveHandler(command, ...args) !== 'undefined'; } /** * Test whether there is a visible handler for the given command. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isVisible(command, ...args) { return typeof this.getVisibleHandler(command, ...args) !== 'undefined'; } /** * Test whether there is a toggled handler for the given command. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isToggled(command, ...args) { return typeof this.getToggledHandler(command, ...args) !== 'undefined'; } /** * Execute the active handler for the given command and arguments. * * Reject if a command cannot be executed. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any async executeCommand(commandId, ...args) { const handler = this.getActiveHandler(commandId, ...args); if (handler) { await this.fireWillExecuteCommand(commandId, args); const result = await handler.execute(...args); this.onDidExecuteCommandEmitter.fire({ commandId, args }); return result; } throw Object.assign(new Error(`The command '${commandId}' cannot be executed. There are no active handlers available for the command.`), { code: 'NO_ACTIVE_HANDLER' }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any async fireWillExecuteCommand(commandId, args = []) { await event_1.WaitUntilEvent.fire(this.onWillExecuteCommandEmitter, { commandId, args }, 30000); } /** * Get a visible handler for the given command or `undefined`. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any getVisibleHandler(commandId, ...args) { const handlers = this._handlers[commandId]; if (handlers) { for (const handler of handlers) { try { if (!handler.isVisible || handler.isVisible(...args)) { return handler; } } catch (error) { console.error(error); } } } return undefined; } /** * Get an active handler for the given command or `undefined`. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any getActiveHandler(commandId, ...args) { const handlers = this._handlers[commandId]; if (handlers) { for (const handler of handlers) { try { if (!handler.isEnabled || handler.isEnabled(...args)) { return handler; } } catch (error) { console.error(error); } } } return undefined; } /** * Get a toggled handler for the given command or `undefined`. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any getToggledHandler(commandId, ...args) { const handlers = this._handlers[commandId]; if (handlers) { for (const handler of handlers) { try { if (handler.isToggled && handler.isToggled(...args)) { return handler; } } catch (error) { console.error(error); } } } return undefined; } /** * Returns with all handlers for the given command. If the command does not have any handlers, * or the command is not registered, returns an empty array. */ getAllHandlers(commandId) { const handlers = this._handlers[commandId]; return handlers ? handlers.slice() : []; } /** * Get all registered commands. */ get commands() { return Object.values(this._commands); } /** * Get a command for the given command identifier. */ getCommand(id) { return this._commands[id]; } /** * Get all registered commands identifiers. */ get commandIds() { return Object.keys(this._commands); } /** * Get the list of recently used commands. */ get recent() { const commands = []; for (const recentId of this._recent) { const command = this.getCommand(recentId); if (command) { commands.push(command); } } return commands; } /** * Set the list of recently used commands. * @param commands the list of recently used commands. */ set recent(commands) { this._recent = Array.from(new Set(commands.map(e => e.id))); } /** * Adds a command to recently used list. * Prioritizes commands that were recently executed to be most recent. * * @param recent a recent command, or array of recent commands. */ addRecentCommand(recent) { for (const recentCommand of Array.isArray(recent) ? recent : [recent]) { // Determine if the command currently exists in the recently used list. const index = this._recent.findIndex(commandId => commandId === recentCommand.id); // If the command exists, remove it from the array so it can later be placed at the top. if (index >= 0) { this._recent.splice(index, 1); } // Add the recent command to the beginning of the array (most recent). this._recent.unshift(recentCommand.id); } } /** * Clear the list of recently used commands. */ clearCommandHistory() { this.recent = []; } }; CommandRegistry = __decorate([ (0, inversify_1.injectable)(), __param(0, (0, inversify_1.inject)(contribution_provider_1.ContributionProvider)), __param(0, (0, inversify_1.named)(exports.CommandContribution)), __metadata("design:paramtypes", [Object]) ], CommandRegistry); exports.CommandRegistry = CommandRegistry; //# sourceMappingURL=command.js.map