Skip to content

Commit

Permalink
GH-210: Added accelerators to menu items.
Browse files Browse the repository at this point in the history
Signed-off-by: Akos Kitta <[email protected]>
  • Loading branch information
kittaakos authored and akosyakov committed Sep 5, 2017
1 parent be1b066 commit 59c9943
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 39 deletions.
23 changes: 10 additions & 13 deletions packages/core/src/browser/menu/browser-menu-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import { injectable, inject } from "inversify";
import { MenuBar as MenuBarWidget, Menu as MenuWidget, Widget } from "@phosphor/widgets";
import { CommandRegistry as PhosphorCommandRegistry } from "@phosphor/commands";
import {
CommandRegistry, KeybindingRegistry,
ActionMenuNode, CompositeMenuNode, MenuModelRegistry, MAIN_MENU_BAR
} from "../../common";
import { CommandRegistry, KeybindingRegistry, ActionMenuNode, CompositeMenuNode, MenuModelRegistry, MAIN_MENU_BAR } from "../../common";
import { FrontendApplicationContribution, FrontendApplication } from "../frontend-application";

@injectable()
Expand Down Expand Up @@ -58,25 +55,25 @@ export class BrowserMainMenuFactory {
const getHandler = (commandId: string) => {
return commandRegistry.getActiveHandler(commandId) || {
execute: () => { },
isEnabled: () => { return false; },
isVisible: () => { return true; }
isEnabled: () => false,
isVisible: () => true
};
};
commands.addCommand(command.id, {
execute: (e: any) => getHandler(command.id).execute(),
label: menu.label,
icon: command.iconClass,
isEnabled: (e: any) => {
const handler = getHandler(command.id)
return !handler.isEnabled || handler.isEnabled()
const handler = getHandler(command.id);
return !handler.isEnabled || handler.isEnabled();
},
isVisible: (e: any) => {
const handler = getHandler(command.id)
return !handler.isVisible || handler.isVisible()
const handler = getHandler(command.id);
return !handler.isVisible || handler.isVisible();
}
});

const binding = keybindingRegistry.getKeybindingForCommand(command.id);
const binding = keybindingRegistry.getKeybindingForCommand(command.id, false);
if (binding) {
const keys = binding.accelerator || [];
commands.addKeyBinding({
Expand Down Expand Up @@ -104,9 +101,9 @@ class DynamicMenuBarWidget extends MenuBarWidget {
// HACK we need to hook in on private method _openChildMenu. Don't do this at home!
DynamicMenuBarWidget.prototype['_openChildMenu'] = () => {
if (this.activeMenu instanceof DynamicMenuWidget) {
this.activeMenu.aboutToShow()
this.activeMenu.aboutToShow();
}
super['_openChildMenu']()
super['_openChildMenu']();
}
}
}
Expand Down
23 changes: 16 additions & 7 deletions packages/core/src/common/keybinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,15 @@ export class KeybindingRegistry {
}

/**
* The `checkAvailability` flag with `false` could come handy when we do not want to check whether the command is currently active or not.
* For instance, when building the main menu, it could easily happen that the command is not yet active (no active editors and so on)
* but still, we have to build the key accelerator.
*
* @param commandId the unique ID of the command for we the associated ke binding are looking for.
* @param checkAvailability if `false` then the availability of the command will not be checked. Default is `true`
*/
getKeybindingForCommand(commandId: string): Keybinding | undefined {
return (this.commands[commandId] || []).find(binding => this.isValid(binding));
getKeybindingForCommand(commandId: string, checkAvailability: boolean = true): Keybinding | undefined {
return (this.commands[commandId] || []).find(binding => this.isValid(binding, checkAvailability));
}

/**
Expand All @@ -141,12 +146,16 @@ export class KeybindingRegistry {
return (this.keybindings[keyCode.keystroke] || []).find(binding => this.isValid(binding));
}

private isValid(binding: Keybinding): boolean {
let cmd = this.commandRegistry.getCommand(binding.commandId);
private isValid(binding: Keybinding, checkAvailability: boolean = true): boolean {
const cmd = this.commandRegistry.getCommand(binding.commandId);
if (cmd) {
let handler = this.commandRegistry.getActiveHandler(cmd.id);
// TODO? isActive()
if (handler && (!handler.isVisible || handler.isVisible())) {
if (checkAvailability) {
const handler = this.commandRegistry.getActiveHandler(cmd.id);
// TODO? isActive()
if (handler && (!handler.isVisible || handler.isVisible())) {
return true;
}
} else {
return true;
}
}
Expand Down
8 changes: 5 additions & 3 deletions packages/monaco/src/browser/monaco-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import MenuRegistry = monaco.actions.MenuRegistry;
import MenuId = monaco.actions.MenuId;

/**
* Editor commands for the `Selection` menu contribution.
* Editor commands (and actions) for the `Selection` menu contribution.
*/
export namespace MonacoSelectionCommands {

Expand All @@ -47,6 +47,7 @@ export namespace MonacoSelectionCommands {
export const SELECTION_ADD_PREVIOUS_OCCURRENCE = 'editor.action.addSelectionToPreviousFindMatch';
export const SELECTION_SELECT_ALL_OCCURRENCES = 'editor.action.selectHighlights';

// If you are wondering where the accelerators come from for the menus, see the `monaco-keybinding` module.
export const ACTIONS: { id: string, label: string, delegateId?: string }[] = [
{ id: SELECTION_SELECT_ALL, label: 'Select All', delegateId: 'editor.action.selectAll' },
{ id: SELECTION_EXPAND_SELECTION, label: 'Expand Selection' },
Expand Down Expand Up @@ -103,7 +104,7 @@ export class MonacoEditorCommandHandlers implements CommandContribution {
});

// VSCode registers some commands as core commands and not as @editorAction. These have to be treated differently.
[...MonacoSelectionCommands.ACTIONS].forEach(action => {
MonacoSelectionCommands.ACTIONS.forEach(action => {
if (action.delegateId) {
const { id, delegateId } = action;
commands.registerHandler(id, {
Expand All @@ -115,7 +116,8 @@ export class MonacoEditorCommandHandlers implements CommandContribution {
editor.commandService.executeCommand(delegateId!);
}
}
}
},
isEnabled: () => !!getCurrent(this.editorManager)
});
}
});
Expand Down
10 changes: 5 additions & 5 deletions packages/monaco/src/browser/monaco-context-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { EDITOR_CONTEXT_MENU_ID } from "@theia/editor/lib/browser";
import { ContextMenuRenderer, toAnchor } from "@theia/core/lib/browser";
import IContextMenuService = monaco.editor.IContextMenuService;
import IContextMenuDelegate = monaco.editor.IContextMenuDelegate;
import { Menu } from "@phosphor/widgets"
import { CommandRegistry } from "@phosphor/commands"
import { Menu } from "@phosphor/widgets";
import { CommandRegistry } from "@phosphor/commands";

@injectable()
export class MonacoContextMenuService implements IContextMenuService {
Expand All @@ -27,7 +27,7 @@ export class MonacoContextMenuService implements IContextMenuService {
this.contextMenuRenderer.render(EDITOR_CONTEXT_MENU_ID, anchor);
} else {
delegate.getActions().then(actions => {
const commands = new CommandRegistry()
const commands = new CommandRegistry();
const menu = new Menu({
commands
});
Expand All @@ -47,8 +47,8 @@ export class MonacoContextMenuService implements IContextMenuService {
});
}
menu.open(anchor.x, anchor.y);
})
});
}
}

}
}
25 changes: 14 additions & 11 deletions packages/monaco/src/browser/monaco-keybinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { isOSX } from '@theia/core/lib/common/os';
import { isFirefox, isIE, isWebKit } from '@theia/core/lib/browser';
import { Keybinding, KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/common/keybinding';
import { Accelerator, Key, KeyCode, Keystroke, Modifier } from '@theia/core/lib/common/keys';
import { MonacoSelectionCommands } from './monaco-command';
import MenuRegistry = monaco.actions.MenuRegistry;
import MenuId = monaco.actions.MenuId;
import KeybindingsRegistry = monaco.keybindings.KeybindingsRegistry;
Expand Down Expand Up @@ -162,9 +163,10 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
registerKeyBindings(registry: KeybindingRegistry): void {

const ids = MenuRegistry.getMenuItems(MenuId.EditorContext).map(item => item.command.id);
ids.push(...MonacoSelectionCommands.ACTIONS.map(({ id }) => id));
const accelerator = (kb: IKeybindingItem): Accelerator => {
const keyCode = kb.keybinding;
let keys: string[] = [];
const keys: string[] = [];
if (keyCode & KeyMod.WinCtrl) {
keys.push('Accel');
}
Expand All @@ -186,7 +188,7 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
const sequence: Keystroke = {
first: Key.getKey(MONACO_KEY_CODE_MAP[keyCode & 255]),
modifiers: []
}
};
// CTRL + COMMAND
if ((keyCode & KeyMod.CtrlCmd) || (keyCode & KeyMod.WinCtrl)) {
sequence.modifiers!.push(Modifier.M1);
Expand All @@ -204,21 +206,22 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
sequence.modifiers!.push(Modifier.M4);
}
return KeyCode.createKeyCode(sequence);
}
};

const a = KeybindingsRegistry.getDefaultKeybindings();
console.log(a);

const bindings: Keybinding[] = KeybindingsRegistry.getDefaultKeybindings()
.filter(kb => ids.indexOf(kb.command) >= 0)
.map(kb => {
return {
commandId: kb.command,
keyCode: keyCode(kb),
accelerator: accelerator(kb),
}
});
.map(kb => ({
commandId: kb.command,
keyCode: keyCode(kb),
accelerator: accelerator(kb),
}));

bindings.forEach(binding => {
registry.registerKeyBinding(binding);
})
});

}

Expand Down

0 comments on commit 59c9943

Please sign in to comment.