actions.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. 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;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. import { Separator, SubmenuAction } from '../../../base/common/actions.js';
  15. import { CSSIcon } from '../../../base/common/codicons.js';
  16. import { Emitter } from '../../../base/common/event.js';
  17. import { Iterable } from '../../../base/common/iterator.js';
  18. import { toDisposable } from '../../../base/common/lifecycle.js';
  19. import { LinkedList } from '../../../base/common/linkedList.js';
  20. import { ICommandService } from '../../commands/common/commands.js';
  21. import { IContextKeyService } from '../../contextkey/common/contextkey.js';
  22. import { createDecorator } from '../../instantiation/common/instantiation.js';
  23. import { ThemeIcon } from '../../theme/common/themeService.js';
  24. export function isIMenuItem(item) {
  25. return item.command !== undefined;
  26. }
  27. export class MenuId {
  28. constructor(debugName) {
  29. this.id = MenuId._idPool++;
  30. this._debugName = debugName;
  31. }
  32. }
  33. MenuId._idPool = 0;
  34. MenuId.CommandPalette = new MenuId('CommandPalette');
  35. MenuId.EditorContext = new MenuId('EditorContext');
  36. MenuId.SimpleEditorContext = new MenuId('SimpleEditorContext');
  37. MenuId.EditorContextCopy = new MenuId('EditorContextCopy');
  38. MenuId.EditorContextPeek = new MenuId('EditorContextPeek');
  39. MenuId.MenubarEditMenu = new MenuId('MenubarEditMenu');
  40. MenuId.MenubarCopy = new MenuId('MenubarCopy');
  41. MenuId.MenubarGoMenu = new MenuId('MenubarGoMenu');
  42. MenuId.MenubarSelectionMenu = new MenuId('MenubarSelectionMenu');
  43. MenuId.InlineCompletionsActions = new MenuId('InlineCompletionsActions');
  44. export const IMenuService = createDecorator('menuService');
  45. export const MenuRegistry = new class {
  46. constructor() {
  47. this._commands = new Map();
  48. this._menuItems = new Map();
  49. this._onDidChangeMenu = new Emitter();
  50. this.onDidChangeMenu = this._onDidChangeMenu.event;
  51. this._commandPaletteChangeEvent = {
  52. has: id => id === MenuId.CommandPalette
  53. };
  54. }
  55. addCommand(command) {
  56. return this.addCommands(Iterable.single(command));
  57. }
  58. addCommands(commands) {
  59. for (const command of commands) {
  60. this._commands.set(command.id, command);
  61. }
  62. this._onDidChangeMenu.fire(this._commandPaletteChangeEvent);
  63. return toDisposable(() => {
  64. let didChange = false;
  65. for (const command of commands) {
  66. didChange = this._commands.delete(command.id) || didChange;
  67. }
  68. if (didChange) {
  69. this._onDidChangeMenu.fire(this._commandPaletteChangeEvent);
  70. }
  71. });
  72. }
  73. getCommand(id) {
  74. return this._commands.get(id);
  75. }
  76. getCommands() {
  77. const map = new Map();
  78. this._commands.forEach((value, key) => map.set(key, value));
  79. return map;
  80. }
  81. appendMenuItem(id, item) {
  82. return this.appendMenuItems(Iterable.single({ id, item }));
  83. }
  84. appendMenuItems(items) {
  85. const changedIds = new Set();
  86. const toRemove = new LinkedList();
  87. for (const { id, item } of items) {
  88. let list = this._menuItems.get(id);
  89. if (!list) {
  90. list = new LinkedList();
  91. this._menuItems.set(id, list);
  92. }
  93. toRemove.push(list.push(item));
  94. changedIds.add(id);
  95. }
  96. this._onDidChangeMenu.fire(changedIds);
  97. return toDisposable(() => {
  98. if (toRemove.size > 0) {
  99. for (let fn of toRemove) {
  100. fn();
  101. }
  102. this._onDidChangeMenu.fire(changedIds);
  103. toRemove.clear();
  104. }
  105. });
  106. }
  107. getMenuItems(id) {
  108. let result;
  109. if (this._menuItems.has(id)) {
  110. result = [...this._menuItems.get(id)];
  111. }
  112. else {
  113. result = [];
  114. }
  115. if (id === MenuId.CommandPalette) {
  116. // CommandPalette is special because it shows
  117. // all commands by default
  118. this._appendImplicitItems(result);
  119. }
  120. return result;
  121. }
  122. _appendImplicitItems(result) {
  123. const set = new Set();
  124. for (const item of result) {
  125. if (isIMenuItem(item)) {
  126. set.add(item.command.id);
  127. if (item.alt) {
  128. set.add(item.alt.id);
  129. }
  130. }
  131. }
  132. this._commands.forEach((command, id) => {
  133. if (!set.has(id)) {
  134. result.push({ command });
  135. }
  136. });
  137. }
  138. };
  139. export class SubmenuItemAction extends SubmenuAction {
  140. constructor(item, _menuService, _contextKeyService, _options) {
  141. super(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, [], 'submenu');
  142. this.item = item;
  143. this._menuService = _menuService;
  144. this._contextKeyService = _contextKeyService;
  145. this._options = _options;
  146. }
  147. get actions() {
  148. const result = [];
  149. const menu = this._menuService.createMenu(this.item.submenu, this._contextKeyService);
  150. const groups = menu.getActions(this._options);
  151. menu.dispose();
  152. for (const [, actions] of groups) {
  153. if (actions.length > 0) {
  154. result.push(...actions);
  155. result.push(new Separator());
  156. }
  157. }
  158. if (result.length) {
  159. result.pop(); // remove last separator
  160. }
  161. return result;
  162. }
  163. }
  164. // implements IAction, does NOT extend Action, so that no one
  165. // subscribes to events of Action or modified properties
  166. let MenuItemAction = class MenuItemAction {
  167. constructor(item, alt, options, contextKeyService, _commandService) {
  168. var _a, _b;
  169. this._commandService = _commandService;
  170. this.id = item.id;
  171. this.label = (options === null || options === void 0 ? void 0 : options.renderShortTitle) && item.shortTitle
  172. ? (typeof item.shortTitle === 'string' ? item.shortTitle : item.shortTitle.value)
  173. : (typeof item.title === 'string' ? item.title : item.title.value);
  174. this.tooltip = (_b = (typeof item.tooltip === 'string' ? item.tooltip : (_a = item.tooltip) === null || _a === void 0 ? void 0 : _a.value)) !== null && _b !== void 0 ? _b : '';
  175. this.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);
  176. this.checked = undefined;
  177. if (item.toggled) {
  178. const toggled = (item.toggled.condition ? item.toggled : { condition: item.toggled });
  179. this.checked = contextKeyService.contextMatchesRules(toggled.condition);
  180. if (this.checked && toggled.tooltip) {
  181. this.tooltip = typeof toggled.tooltip === 'string' ? toggled.tooltip : toggled.tooltip.value;
  182. }
  183. if (toggled.title) {
  184. this.label = typeof toggled.title === 'string' ? toggled.title : toggled.title.value;
  185. }
  186. }
  187. this.item = item;
  188. this.alt = alt ? new MenuItemAction(alt, undefined, options, contextKeyService, _commandService) : undefined;
  189. this._options = options;
  190. if (ThemeIcon.isThemeIcon(item.icon)) {
  191. this.class = CSSIcon.asClassName(item.icon);
  192. }
  193. }
  194. dispose() {
  195. // there is NOTHING to dispose and the MenuItemAction should
  196. // never have anything to dispose as it is a convenience type
  197. // to bridge into the rendering world.
  198. }
  199. run(...args) {
  200. var _a, _b;
  201. let runArgs = [];
  202. if ((_a = this._options) === null || _a === void 0 ? void 0 : _a.arg) {
  203. runArgs = [...runArgs, this._options.arg];
  204. }
  205. if ((_b = this._options) === null || _b === void 0 ? void 0 : _b.shouldForwardArgs) {
  206. runArgs = [...runArgs, ...args];
  207. }
  208. return this._commandService.executeCommand(this.id, ...runArgs);
  209. }
  210. };
  211. MenuItemAction = __decorate([
  212. __param(3, IContextKeyService),
  213. __param(4, ICommandService)
  214. ], MenuItemAction);
  215. export { MenuItemAction };
  216. //#endregion