commands.js 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { Emitter } from '../../../base/common/event.js';
  6. import { Iterable } from '../../../base/common/iterator.js';
  7. import { Disposable, toDisposable } from '../../../base/common/lifecycle.js';
  8. import { LinkedList } from '../../../base/common/linkedList.js';
  9. import { validateConstraints } from '../../../base/common/types.js';
  10. import { createDecorator } from '../../instantiation/common/instantiation.js';
  11. export const ICommandService = createDecorator('commandService');
  12. export const CommandsRegistry = new class {
  13. constructor() {
  14. this._commands = new Map();
  15. this._onDidRegisterCommand = new Emitter();
  16. this.onDidRegisterCommand = this._onDidRegisterCommand.event;
  17. }
  18. registerCommand(idOrCommand, handler) {
  19. if (!idOrCommand) {
  20. throw new Error(`invalid command`);
  21. }
  22. if (typeof idOrCommand === 'string') {
  23. if (!handler) {
  24. throw new Error(`invalid command`);
  25. }
  26. return this.registerCommand({ id: idOrCommand, handler });
  27. }
  28. // add argument validation if rich command metadata is provided
  29. if (idOrCommand.description) {
  30. const constraints = [];
  31. for (let arg of idOrCommand.description.args) {
  32. constraints.push(arg.constraint);
  33. }
  34. const actualHandler = idOrCommand.handler;
  35. idOrCommand.handler = function (accessor, ...args) {
  36. validateConstraints(args, constraints);
  37. return actualHandler(accessor, ...args);
  38. };
  39. }
  40. // find a place to store the command
  41. const { id } = idOrCommand;
  42. let commands = this._commands.get(id);
  43. if (!commands) {
  44. commands = new LinkedList();
  45. this._commands.set(id, commands);
  46. }
  47. let removeFn = commands.unshift(idOrCommand);
  48. let ret = toDisposable(() => {
  49. removeFn();
  50. const command = this._commands.get(id);
  51. if (command === null || command === void 0 ? void 0 : command.isEmpty()) {
  52. this._commands.delete(id);
  53. }
  54. });
  55. // tell the world about this command
  56. this._onDidRegisterCommand.fire(id);
  57. return ret;
  58. }
  59. registerCommandAlias(oldId, newId) {
  60. return CommandsRegistry.registerCommand(oldId, (accessor, ...args) => accessor.get(ICommandService).executeCommand(newId, ...args));
  61. }
  62. getCommand(id) {
  63. const list = this._commands.get(id);
  64. if (!list || list.isEmpty()) {
  65. return undefined;
  66. }
  67. return Iterable.first(list);
  68. }
  69. getCommands() {
  70. const result = new Map();
  71. for (const key of this._commands.keys()) {
  72. const command = this.getCommand(key);
  73. if (command) {
  74. result.set(key, command);
  75. }
  76. }
  77. return result;
  78. }
  79. };
  80. export const NullCommandService = {
  81. _serviceBrand: undefined,
  82. onWillExecuteCommand: () => Disposable.None,
  83. onDidExecuteCommand: () => Disposable.None,
  84. executeCommand() {
  85. return Promise.resolve(undefined);
  86. }
  87. };
  88. CommandsRegistry.registerCommand('noop', () => { });