Skip to content

Commit

Permalink
Update the 'keymaps' documentation.
Browse files Browse the repository at this point in the history
- update the documentation of the `@theia/keymaps` extension as
part of the ongoing effort to improve documentation for the
milestone 1.0.0 release.

Signed-off-by: Vincent Fugnitto <[email protected]>
  • Loading branch information
vince-fugnitto committed Oct 14, 2019
1 parent b98c5fb commit d147752
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 22 deletions.
7 changes: 7 additions & 0 deletions packages/core/src/browser/keybinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,14 @@ export interface ScopedKeybinding extends Keybinding {
}

export const KeybindingContribution = Symbol('KeybindingContribution');
/**
* Representation of a keybinding contribution.
*/
export interface KeybindingContribution {
/**
* Registers keybindings.
* @param keybindings the keybinding registry.
*/
registerKeybindings(keybindings: KeybindingRegistry): void;
}

Expand Down
9 changes: 7 additions & 2 deletions packages/core/src/browser/shell/tab-bar-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,15 @@ export namespace TabBarToolbar {
* Clients should implement this interface if they want to contribute to the tab-bar toolbar.
*/
export const TabBarToolbarContribution = Symbol('TabBarToolbarContribution');
/**
* Representation of a tabbar toolbar contribution.
*/
export interface TabBarToolbarContribution {

/**
* Registers toolbar items.
* @param registry the tabbar toolbar registry.
*/
registerToolbarItems(registry: TabBarToolbarRegistry): void;

}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/common/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ export type MenuPath = string[];
export const MAIN_MENU_BAR: MenuPath = ['menubar'];

export const MenuContribution = Symbol('MenuContribution');

/**
* Representation of a menu contribution.
*/
export interface MenuContribution {
/**
* Registers menus.
* @param menus the menu model registry.
*/
registerMenus(menus: MenuModelRegistry): void;
}

Expand Down
58 changes: 38 additions & 20 deletions packages/keymaps/src/browser/keybindings-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,14 @@ export class KeybindingWidget extends ReactWidget {
@inject(KeymapsService)
protected readonly keymapsService: KeymapsService;

protected items: KeybindingItem[] = [];

static readonly ID = 'keybindings.view.widget';
static readonly LABEL = 'Keyboard Shortcuts';

/**
* The list of all available keybindings.
*/
protected items: KeybindingItem[] = [];

/**
* The current user search query.
*/
Expand All @@ -94,6 +97,9 @@ export class KeybindingWidget extends ReactWidget {
* The regular expression used to extract values between fuzzy results.
*/
protected readonly regexp = /<match>(.*?)<\/match>/g;
/**
* The regular expression used to extract values between the keybinding separator.
*/
protected readonly keybindingSeparator = /<match>\+<\/match>/g;

/**
Expand All @@ -108,8 +114,14 @@ export class KeybindingWidget extends ReactWidget {
protected readonly onDidUpdateEmitter = new Emitter<void>();
readonly onDidUpdate: Event<void> = this.onDidUpdateEmitter.event;

/**
* Search keybindings.
*/
protected readonly searchKeybindings: () => void = debounce(() => this.doSearchKeybindings(), 50);

/**
* Initialize the widget.
*/
@postConstruct()
protected init(): void {
this.id = KeybindingWidget.ID;
Expand Down Expand Up @@ -368,15 +380,15 @@ export class KeybindingWidget extends ReactWidget {

/**
* Render the actions container with action icons.
* @param item {KeybindingItem} the keybinding item for the row.
* @param item the keybinding item for the row.
*/
protected renderActions(item: KeybindingItem): React.ReactNode {
return <span className='kb-actions-icons'>{this.renderEdit(item)}{this.renderReset(item)}</span>;
}

/**
* Render the edit action used to update a keybinding.
* @param item {KeybindingItem} the keybinding item for the row.
* @param item the keybinding item for the row.
*/
protected renderEdit(item: KeybindingItem): React.ReactNode {
return <a title='Edit Keybinding' href='#' onClick={a => this.editKeybinding(item)}><i className='fa fa-pencil kb-action-item'></i></a>;
Expand All @@ -385,7 +397,7 @@ export class KeybindingWidget extends ReactWidget {
/**
* Render the reset action to reset the custom keybinding.
* Only visible if a keybinding has a `user` scope.
* @param item {KeybindingItem} the keybinding item for the row.
* @param item the keybinding item for the row.
*/
protected renderReset(item: KeybindingItem): React.ReactNode {
return (item.source && this.getRawValue(item.source) === KeybindingScope[1].toLocaleLowerCase())
Expand All @@ -394,7 +406,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Render the keybinding.
* @param keybinding {string} the keybinding value.
* @param keybinding the keybinding value.
*/
protected renderKeybinding(keybinding: string): React.ReactNode {
const regex = new RegExp(this.keybindingSeparator);
Expand Down Expand Up @@ -472,8 +484,14 @@ export class KeybindingWidget extends ReactWidget {

/**
* Compare two strings.
* @param a {string | undefined} the first string.
* @param b {string | undefined} the second string.
* - Strings are first normalized before comparison (`toLowerCase`).
* @param a the optional first string.
* @param b the optional second string.
*
* @returns an integer indicating whether `a` comes before, after or is equivalent to `b`.
* - returns `-1` if `a` occurs before `b`.
* - returns `1` if `a` occurs after `b`.
* - returns `0` if they are equivalent.
*/
protected compareItem(a: string | undefined, b: string | undefined): number {
if (a && b) {
Expand All @@ -498,7 +516,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Prompt users to update the keybinding for the given command.
* @param item {KeybindingItem} the keybinding item.
* @param item the keybinding item.
*/
protected editKeybinding(item: KeybindingItem): void {
const command = this.getRawValue(item.command);
Expand All @@ -519,7 +537,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Prompt users for confirmation before resetting.
* @param command {string} the command label.
* @param command the command label.
*
* @returns a Promise which resolves to `true` if a user accepts resetting.
*/
Expand All @@ -533,7 +551,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Reset the keybinding to its default value.
* @param item {KeybindingItem} the keybinding item.
* @param item the keybinding item.
*/
protected async resetKeybinding(item: KeybindingItem): Promise<void> {
const rawCommandId = this.getRawValue(item.id);
Expand All @@ -546,9 +564,9 @@ export class KeybindingWidget extends ReactWidget {

/**
* Validate the provided keybinding value against its previous value.
* @param command {string} the command label.
* @param oldKeybinding {string} the old keybinding value.
* @param keybinding {string} the new keybinding value.
* @param command the command label.
* @param oldKeybinding the old keybinding value.
* @param keybinding the new keybinding value.
*
* @returns the end user message to display.
*/
Expand All @@ -573,7 +591,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Build the cell data with highlights if applicable.
* @param raw {string} the raw cell value.
* @param raw the raw cell value.
*
* @returns the list of cell data.
*/
Expand Down Expand Up @@ -612,7 +630,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Render the fuzzy representation of a matched result.
* @param property {string} one of the `KeybindingItem` properties.
* @param property one of the `KeybindingItem` properties.
*/
protected renderMatchedData(property: string): React.ReactNode {
if (this.query !== '') {
Expand All @@ -629,7 +647,7 @@ export class KeybindingWidget extends ReactWidget {

/**
* Render the raw value of a item without fuzzy highlighting.
* @param property {string} one of the `KeybindingItem` properties.
* @param property one of the `KeybindingItem` properties.
*/
protected getRawValue(property: string): string {
return property.replace(new RegExp(this.regexp), '$1');
Expand Down Expand Up @@ -675,8 +693,8 @@ class EditKeybindingDialog extends SingleTextInputDialog {

/**
* Add `Reset` action used to reset a custom keybinding, and close the dialog.
* @param element {HTMLElement} the HTML element in question.
* @param additionalEventTypes {K[]} additional event types.
* @param element the HTML element in question.
* @param additionalEventTypes additional event types.
*/
protected addResetAction<K extends keyof HTMLElementEventMap>(element: HTMLElement, ...additionalEventTypes: K[]): void {
this.addKeyListener(element, Key.ENTER, () => {
Expand Down Expand Up @@ -712,7 +730,7 @@ class EditKeybindingDialog extends SingleTextInputDialog {

/**
* Extract the raw value from a string (without fuzzy matching).
* @param a {string} given string value for extraction.
* @param a given string value for extraction.
*
* @returns the raw value of a string without any fuzzy matching.
*/
Expand Down
3 changes: 3 additions & 0 deletions packages/keymaps/src/browser/keymaps-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export class KeymapsFrontendContribution extends AbstractViewContribution<Keybin
});
}

/**
* Determine if the current widget is the keybindings widget.
*/
protected withWidget<T>(widget: Widget | undefined = this.tryGetWidget(), fn: (widget: KeybindingWidget) => T): T | false {
if (widget instanceof KeybindingWidget && widget.id === KeybindingWidget.ID) {
return fn(widget);
Expand Down
5 changes: 5 additions & 0 deletions packages/keymaps/src/browser/keymaps-parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ describe('keymaps-parser', () => {
]`);
});

/**
* Assert that the content equals the expected content.
* @param expectation the expected string.
* @param content the content to verify.
*/
function assertParsing(expectation: string, content: string): void {
const errors: string[] = [];
const keybindings = parser.parse(content, errors);
Expand Down
9 changes: 9 additions & 0 deletions packages/keymaps/src/browser/keymaps-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export class KeymapsParser {
}).compile(keymapsSchema);
}

/**
* Parse the keybindings for potential errors.
* @param content the content.
* @param errors the optional list of parsing errors.
*/
parse(content: string, errors?: string[]): Keybinding[] {
const strippedContent = parser.stripComments(content);
const parsingErrors: parser.ParseError[] | undefined = errors ? [] : undefined;
Expand All @@ -76,6 +81,10 @@ export class KeymapsParser {
return [];
}

/**
* Print the parsed error code.
* @param code the error code if available.
*/
// https://github.com/Microsoft/node-jsonc-parser/issues/13
// tslint:disable-next-line:typedef
protected printParseErrorCode(code: number | undefined) {
Expand Down
38 changes: 38 additions & 0 deletions packages/keymaps/src/browser/keymaps-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,21 @@ import { KeymapsParser } from './keymaps-parser';
import * as jsoncparser from 'jsonc-parser';
import { Emitter } from '@theia/core/lib/common/';

/**
* Representation of a JSON keybinding.
*/
export interface KeybindingJson {
/**
* The keybinding command.
*/
command: string,
/**
* The actual keybinding.
*/
keybinding: string,
/**
* The keybinding context.
*/
context: string,
}

Expand All @@ -49,6 +61,9 @@ export class KeymapsService {

protected resource: Resource;

/**
* Initialize the keybinding service.
*/
@postConstruct()
protected async init(): Promise<void> {
this.resource = await this.resourceProvider(new URI().withScheme(UserStorageUri.SCHEME).withPath('keymaps.json'));
Expand All @@ -59,12 +74,18 @@ export class KeymapsService {
this.keyBindingRegistry.onKeybindingsChanged(() => this.changeKeymapEmitter.fire(undefined));
}

/**
* Reconcile all the keybindings, registering them to the registry.
*/
protected async reconcile(): Promise<void> {
const keybindings = await this.parseKeybindings();
this.keyBindingRegistry.setKeymap(KeybindingScope.USER, keybindings);
this.changeKeymapEmitter.fire(undefined);
}

/**
* Parsed the read keybindings.
*/
protected async parseKeybindings(): Promise<Keybinding[]> {
try {
const content = await this.resource.readContents();
Expand All @@ -74,6 +95,10 @@ export class KeymapsService {
}
}

/**
* Open the keybindings widget.
* @param ref the optional reference for opening the widget.
*/
open(ref?: Widget): void {
const options: WidgetOpenerOptions = {
widgetOptions: ref ? { area: 'main', mode: 'split-right', ref } : { area: 'main' },
Expand All @@ -82,6 +107,10 @@ export class KeymapsService {
open(this.opener, this.resource.uri, options);
}

/**
* Set the keybinding in the JSON.
* @param keybindingJson the JSON keybindings.
*/
async setKeybinding(keybindingJson: KeybindingJson): Promise<void> {
if (!this.resource.saveContents) {
return;
Expand All @@ -102,6 +131,10 @@ export class KeymapsService {
await this.resource.saveContents(JSON.stringify(keybindings, undefined, 4));
}

/**
* Remove the given keybinding with the given command id from the JSON.
* @param commandId the keybinding command id.
*/
async removeKeybinding(commandId: string): Promise<void> {
if (!this.resource.saveContents) {
return;
Expand All @@ -112,6 +145,11 @@ export class KeymapsService {
await this.resource.saveContents(JSON.stringify(filtered, undefined, 4));
}

/**
* Get the list of keybindings from the JSON.
*
* @returns the list of keybindings in JSON.
*/
async getKeybindings(): Promise<KeybindingJson[]> {
if (!this.resource.saveContents) {
return [];
Expand Down

0 comments on commit d147752

Please sign in to comment.