Skip to content

Commit

Permalink
feat: support keybinding via extensions (#198)
Browse files Browse the repository at this point in the history
* feat: develop keybinding services & controller

* feat: init actions via extension rather than MoleculeProvider

* feat: support keybinding in the menus of activitybar

* feat: support keybinding in the menus of menuBar

* fix: replace context menu in activity bar

* feat: improve keybinding icon in windows

* refactor: improve the usage of keybinding

* fix: extensionService no longer export
  • Loading branch information
mortalYoung authored Jun 25, 2021
1 parent a8ba3e3 commit fb3c370
Show file tree
Hide file tree
Showing 20 changed files with 282 additions and 60 deletions.
8 changes: 8 additions & 0 deletions src/components/menu/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
}
}

&__keybinding {
display: inline-block;
flex: 2 1 auto;
line-height: 1;
padding: 0 2em;
text-align: right;
}

&__separator {
height: 1px;
width: 100%;
Expand Down
15 changes: 9 additions & 6 deletions src/controller/activityBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import {
CONTEXT_MENU_EXPLORER,
CONTEXT_MENU_SEARCH,
CONTEXT_MENU_HIDE,
CONTEXT_MENU_COLOR_THEME,
CONTEXT_MENU_COMMAND_PALETTE,
CONTEXT_MENU_SETTINGS,
IActivityBarItem,
} from 'mo/model';
import { SelectColorThemeAction } from 'mo/monaco/selectColorThemeAction';
Expand All @@ -24,6 +21,12 @@ import {
} from 'mo/services';
import { CommandQuickAccessViewAction } from 'mo/monaco/quickAccessViewAction';
import { IMonacoService, MonacoService } from 'mo/monaco/monacoService';
import {
ACTION_QUICK_COMMAND,
ACTION_QUICK_ACCESS_SETTINGS,
ACTION_SELECT_THEME,
} from 'mo/model/keybinding';

export interface IActivityBarController {
/**
* Called when activity bar item is clicked
Expand Down Expand Up @@ -107,15 +110,15 @@ export class ActivityBarController
break;
}
// manage button contextMenu
case CONTEXT_MENU_COMMAND_PALETTE: {
case ACTION_QUICK_COMMAND: {
this.gotoQuickCommand();
break;
}
case CONTEXT_MENU_SETTINGS: {
case ACTION_QUICK_ACCESS_SETTINGS: {
this.settingsService.openSettingsInEditor();
break;
}
case CONTEXT_MENU_COLOR_THEME: {
case ACTION_SELECT_THEME: {
this.onSelectColorTheme();
break;
}
Expand Down
2 changes: 2 additions & 0 deletions src/extensions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ExtendsActivityBar } from './activityBar';
import { ExtendsPanel } from './panel';
import { ExtendsExplorer } from './explorer';
import { ExtendsEditorTree } from './editorTree';
import { ExtendsKeybinding } from './keybinding';

import { defaultColorThemeExtension } from './theme-defaults';
import { monokaiColorThemeExtension } from './theme-monokai';
Expand All @@ -28,4 +29,5 @@ export const defaultExtensions = [
monokaiColorThemeExtension,
paleNightColorThemeExtension,
ExtendsFolderTree,
ExtendsKeybinding,
];
15 changes: 15 additions & 0 deletions src/extensions/keybinding/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { IExtensionService } from 'mo/services';
import { IExtension } from 'mo/model';
import { SelectLocaleAction } from 'mo/i18n/selectLocaleAction';
import { QuickAccessSettings } from 'mo/monaco/quickAccessSettingsAction';
import { CommandQuickAccessViewAction } from 'mo/monaco/quickAccessViewAction';
import { SelectColorThemeAction } from 'mo/monaco/selectColorThemeAction';

export const ExtendsKeybinding: IExtension = {
activate(extensionCtx: IExtensionService) {
extensionCtx.registerAction(CommandQuickAccessViewAction);
extensionCtx.registerAction(SelectColorThemeAction);
extensionCtx.registerAction(QuickAccessSettings);
extensionCtx.registerAction(SelectLocaleAction);
},
};
8 changes: 7 additions & 1 deletion src/i18n/selectLocaleAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { Action2 } from 'mo/monaco/common';
import { localize } from './localize';
import { ILocaleService, LocaleService } from './localeService';
import { ILocale } from './localization';
import { KeyCode, KeyMod } from 'mo/monaco';
import { ACTION_SELECT_LOCALE } from 'mo/model/keybinding';

export class SelectLocaleAction extends Action2 {
static readonly ID = 'workbench.action.selectLocale';
static readonly ID = ACTION_SELECT_LOCALE;
static readonly LABEL = localize(
'select.locale',
'Select Display Language'
Expand All @@ -29,6 +31,10 @@ export class SelectLocaleAction extends Action2 {
alias: 'Select Display Language',
precondition: undefined,
f1: true,
keybinding: {
when: undefined,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L,
},
});
}

Expand Down
70 changes: 69 additions & 1 deletion src/model/keybinding.ts
Original file line number Diff line number Diff line change
@@ -1 +1,69 @@
export interface IKeybinding {}
import { KeyCode } from 'mo/monaco';

export const KeyCodeString: Partial<{ [key in KeyCode]: string }> = {
[KeyCode.Unknown]: '',
[KeyCode.Backspace]: '⌫',
[KeyCode.Tab]: '⇥',
[KeyCode.Enter]: '↩︎',
[KeyCode.KEY_0]: '0',
[KeyCode.KEY_1]: '1',
[KeyCode.KEY_2]: '2',
[KeyCode.KEY_3]: '3',
[KeyCode.KEY_4]: '4',
[KeyCode.KEY_5]: '5',
[KeyCode.KEY_6]: '6',
[KeyCode.KEY_7]: '7',
[KeyCode.KEY_8]: '8',
[KeyCode.KEY_9]: '9',
[KeyCode.KEY_A]: 'A',
[KeyCode.KEY_B]: 'B',
[KeyCode.KEY_C]: 'C',
[KeyCode.KEY_D]: 'D',
[KeyCode.KEY_E]: 'E',
[KeyCode.KEY_F]: 'F',
[KeyCode.KEY_G]: 'G',
[KeyCode.KEY_H]: 'H',
[KeyCode.KEY_I]: 'I',
[KeyCode.KEY_J]: 'J',
[KeyCode.KEY_K]: 'K',
[KeyCode.KEY_L]: 'L',
[KeyCode.KEY_M]: 'M',
[KeyCode.KEY_N]: 'N',
[KeyCode.KEY_O]: 'O',
[KeyCode.KEY_P]: 'P',
[KeyCode.KEY_Q]: 'Q',
[KeyCode.KEY_R]: 'R',
[KeyCode.KEY_S]: 'S',
[KeyCode.KEY_T]: 'T',
[KeyCode.KEY_U]: 'U',
[KeyCode.KEY_V]: 'V',
[KeyCode.KEY_W]: 'W',
[KeyCode.KEY_X]: 'X',
[KeyCode.KEY_Y]: 'Y',
[KeyCode.KEY_Z]: 'Z',
[KeyCode.US_SEMICOLON]: ';',
[KeyCode.US_EQUAL]: '+',
[KeyCode.US_COMMA]: ',',
[KeyCode.US_MINUS]: '-',
[KeyCode.US_DOT]: '.',
[KeyCode.US_SLASH]: '/',
[KeyCode.US_BACKTICK]: '~',
[KeyCode.US_OPEN_SQUARE_BRACKET]: '[',
[KeyCode.US_BACKSLASH]: '\\',
[KeyCode.US_CLOSE_SQUARE_BRACKET]: ']',
[KeyCode.US_QUOTE]: '"',
};

export interface ISimpleKeybinding {
ctrlKey: boolean;
shiftKey: boolean;
altKey: boolean;
metaKey: boolean;
keyCode: KeyCode;
}

export const ACTION_QUICK_ACCESS_SETTINGS =
'workbench.action.quickAccessSettings';
export const ACTION_QUICK_COMMAND = 'workbench.action.quickCommand';
export const ACTION_SELECT_THEME = 'workbench.action.selectTheme';
export const ACTION_SELECT_LOCALE = 'workbench.action.selectLocale';
15 changes: 8 additions & 7 deletions src/model/workbench/activityBar.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import * as React from 'react';
import { IMenuItemProps } from 'mo/components/menu';
import { localize } from 'mo/i18n/localize';
import {
ACTION_QUICK_ACCESS_SETTINGS,
ACTION_QUICK_COMMAND,
ACTION_SELECT_THEME,
} from '../keybinding';

/**
* The activity bar event definition
Expand Down Expand Up @@ -38,10 +43,6 @@ export interface IActivityBar {
export const ACTIVITY_BAR_GLOBAL_SETTINGS = 'global.menu.settings';
export const ACTIVITY_BAR_GLOBAL_ACCOUNT = 'global.menu.account';

export const CONTEXT_MENU_COMMAND_PALETTE = 'menu.commandPalette';
export const CONTEXT_MENU_SETTINGS = 'menu.settings';
export const CONTEXT_MENU_COLOR_THEME = 'menu.colorTheme';

export const CONTEXT_MENU_MENU = 'menubar';
export const CONTEXT_MENU_EXPLORER = 'sidebar.explore.title';
export const CONTEXT_MENU_SEARCH = 'sidebar.search.title';
Expand All @@ -62,15 +63,15 @@ export function builtInActivityBar(): IActivityBar {
type: 'global',
contextMenu: [
{
id: CONTEXT_MENU_COMMAND_PALETTE,
id: ACTION_QUICK_COMMAND,
name: localize('menu.commandPalette', 'Command Palette'),
},
{
id: CONTEXT_MENU_SETTINGS,
id: ACTION_QUICK_ACCESS_SETTINGS,
name: localize('menu.settings', 'Settings'),
},
{
id: CONTEXT_MENU_COLOR_THEME,
id: ACTION_SELECT_THEME,
name: localize('menu.colorTheme', 'Color Theme'),
},
],
Expand Down
8 changes: 0 additions & 8 deletions src/molecule.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ import {
NotificationService,
IColorThemeService,
ColorThemeService,
IExtensionService,
ExtensionService,
ISettingsService,
SettingsService,
IProblemsService,
Expand Down Expand Up @@ -101,12 +99,6 @@ export const colorTheme = container.resolve<IColorThemeService>(
ColorThemeService
);

/**
* Note: The extension service depends on other workbench services,
* So it need initialized be last one.
*/
export const extension = container.resolve<IExtensionService>(ExtensionService);

/**
* Settings service
*/
Expand Down
10 changes: 9 additions & 1 deletion src/monaco/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ export enum KeybindingWeight {
}

export abstract class Action2 {
constructor(readonly desc: Readonly<any>) {}
constructor(
readonly desc: Readonly<{
/**
* Specify visible in quick access view
*/
f1: boolean;
[key: string]: any;
}>
) {}
abstract run(accessor: ServicesAccessor, ...args: any[]): any;
}

Expand Down
3 changes: 2 additions & 1 deletion src/monaco/quickAccessSettingsAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { ISettingsService, SettingsService } from 'mo/services';
import { ServicesAccessor } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation';
import { container } from 'tsyringe';
import { Action2, KeybindingWeight } from './common';
import { ACTION_QUICK_ACCESS_SETTINGS } from 'mo/model/keybinding';

export class QuickAccessSettings extends Action2 {
static readonly ID = 'workbench.action.quickAccessSettings';
static readonly ID = ACTION_QUICK_ACCESS_SETTINGS;
static readonly LABEL = localize(
'quickAccessSettings.label',
'Open Settings (JSON)'
Expand Down
3 changes: 2 additions & 1 deletion src/monaco/quickAccessViewAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { EditorService, IEditorService } from 'mo/services';
import { Action2, KeybindingWeight } from './common';
import { MonacoService } from './monacoService';
import { registerQuickAccessProvider } from './quickAccessProvider';
import { ACTION_QUICK_COMMAND } from 'mo/model/keybinding';

export class CommandQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider {
static PREFIX = '>';
Expand Down Expand Up @@ -166,7 +167,7 @@ registerQuickAccessProvider({
});

export class CommandQuickAccessViewAction extends Action2 {
static ID = 'workbench.action.quickCommand';
static ID = ACTION_QUICK_COMMAND;

constructor() {
super({
Expand Down
3 changes: 2 additions & 1 deletion src/monaco/selectColorThemeAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import { ColorThemeService, IColorThemeService } from 'mo/services';
import { ServicesAccessor } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation';
import { container } from 'tsyringe';
import { Action2, KeybindingWeight } from './common';
import { ACTION_SELECT_THEME } from 'mo/model/keybinding';

export class SelectColorThemeAction extends Action2 {
static readonly ID = 'workbench.action.selectTheme';
static readonly ID = ACTION_SELECT_THEME;
static readonly LABEL = localize('selectTheme.label', 'Color Theme');
private readonly colorThemeService: IColorThemeService;

Expand Down
18 changes: 1 addition & 17 deletions src/provider/molecule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ import {
IExtensionService,
} from 'mo/services/extensionService';
import { IMonacoService, MonacoService } from 'mo/monaco/monacoService';
import { CommandQuickAccessViewAction } from 'mo/monaco/quickAccessViewAction';
import { registerAction2 } from 'mo/monaco/common';
import { QuickAccessSettings } from 'mo/monaco/quickAccessSettingsAction';
import { SelectColorThemeAction } from 'mo/monaco/selectColorThemeAction';
import { ILocaleService, LocaleService } from 'mo/i18n/localeService';
import { ILayoutService, LayoutService } from 'mo/services';
import { SelectLocaleAction } from 'mo/i18n/selectLocaleAction';

export interface IMoleculeProps {
extensions?: IExtension[];
locales?: ILocale[];
Expand Down Expand Up @@ -64,18 +60,6 @@ export class MoleculeProvider extends React.Component<IMoleculeProps> {
this.monacoService.initWorkspace(this.container!);
this.extensionService.load(defaultExtensions);
this.extensionService.load(extensions);

this.initWorkbenchActions();
}

/**
* TODO: move the register of actions to extensionService
*/
initWorkbenchActions() {
registerAction2(CommandQuickAccessViewAction);
registerAction2(SelectColorThemeAction);
registerAction2(QuickAccessSettings);
registerAction2(SelectLocaleAction);
}

public render() {
Expand Down
14 changes: 14 additions & 0 deletions src/services/extensionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ColorThemeService,
IColorThemeService,
} from './theme/colorThemeService';
import { Action2, registerAction2 } from 'mo/monaco/common';

export interface IExtensionService {
/**
Expand All @@ -22,6 +23,15 @@ export interface IExtensionService {
load(extensions: IExtension[]);
loadContributes(contributes: IContribute);
unload(extension: IExtension);
/**
* Register action based in Action2,
* @example
* ```ts
* const action = class Action extends Action2 {};
* registerAction(action);
* ```
*/
registerAction(actionClass: { new (): Action2 }): void;
}

@singleton()
Expand Down Expand Up @@ -71,6 +81,10 @@ export class ExtensionService implements IExtensionService {
});
}

public registerAction(actionClass: { new (): Action2 }) {
registerAction2(actionClass);
}

unload(extension: IExtension) {
console.log('unload extension:', extension.name);
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './extensionService';
export type { IExtensionService } from './extensionService';
export * from './theme/colorThemeService';
export * from './workbench';
export * from './settingsService';
Expand Down
Loading

0 comments on commit fb3c370

Please sign in to comment.