diff --git a/packages/keymaps/src/browser/keybindings-widget.tsx b/packages/keymaps/src/browser/keybindings-widget.tsx index a03888a36332f..ca53fbae439bd 100644 --- a/packages/keymaps/src/browser/keybindings-widget.tsx +++ b/packages/keymaps/src/browser/keybindings-widget.tsx @@ -20,7 +20,7 @@ import * as fuzzy from 'fuzzy'; import { injectable, inject, postConstruct } from 'inversify'; import { CommandRegistry, Emitter, Event } from '@theia/core/lib/common'; import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget'; -import { KeybindingRegistry, SingleTextInputDialog, KeySequence, ConfirmDialog, Message, KeybindingScope } from '@theia/core/lib/browser'; +import { KeybindingRegistry, SingleTextInputDialog, KeySequence, ConfirmDialog, Message, KeybindingScope, SingleTextInputDialogProps, Key } from '@theia/core/lib/browser'; import { KeymapsParser } from './keymaps-parser'; import { KeymapsService, KeybindingJson } from './keymaps-service'; import { AlertMessage } from '@theia/core/lib/browser/widgets/alert-message'; @@ -500,11 +500,11 @@ export class KeybindingWidget extends ReactWidget { const id = this.getRawValue(item.id); const keybinding = (item.keybinding) ? this.getRawValue(item.keybinding) : ''; const context = (item.context) ? this.getRawValue(item.context) : ''; - const dialog = new SingleTextInputDialog({ + const dialog = new EditKeybindingDialog({ title: `Edit Keybinding For ${command}`, initialValue: keybinding, validate: newKeybinding => this.validateKeybinding(command, keybinding, newKeybinding), - }); + }, this.keymapsService, item); dialog.open().then(async newKeybinding => { if (newKeybinding) { await this.keymapsService.setKeybinding({ 'command': id, 'keybinding': newKeybinding, 'context': context }); @@ -631,3 +631,77 @@ export class KeybindingWidget extends ReactWidget { } } +/** + * Dialog used to edit keybindings, and reset custom keybindings. + */ +class EditKeybindingDialog extends SingleTextInputDialog { + + /** + * The keybinding item in question. + */ + protected item: KeybindingItem; + + /** + * HTMLButtonElement used to reset custom keybindings. + * Custom keybindings have a `User` scope (exist in `keymaps.json`). + */ + protected resetButton: HTMLButtonElement | undefined; + + constructor( + @inject(SingleTextInputDialogProps) protected readonly props: SingleTextInputDialogProps, + @inject(KeymapsService) protected readonly keymapsService: KeymapsService, + item: KeybindingItem + ) { + super(props); + this.item = item; + // Add the `Reset` button if the command currently has a custom keybinding. + if (this.item.source && + this.item.source === KeybindingScope[1].toLocaleLowerCase()) { + this.appendResetButton(); + } + } + + protected onAfterAttach(msg: Message): void { + super.onAfterAttach(msg); + if (this.resetButton) { + this.addResetAction(this.resetButton, 'click'); + } + } + + /** + * 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. + */ + protected addResetAction(element: HTMLElement, ...additionalEventTypes: K[]): void { + this.addKeyListener(element, Key.ENTER, () => { + this.reset(); + this.close(); + }, ...additionalEventTypes); + } + + /** + * Create the `Reset` button, and append it to the dialog. + * @returns the `Reset` button. + */ + protected appendResetButton(): HTMLButtonElement { + // Create the `Reset` button. + this.resetButton = this.createButton('Reset'); + // Add the `Reset` button to the dialog control panel, before the `Accept` button. + this.controlPanel.insertBefore(this.resetButton, this.acceptButton!); + this.resetButton.title = 'Reset Keybinding'; + this.resetButton.classList.add('secondary'); + return this.resetButton; + } + + /** + * Perform keybinding reset. + */ + protected reset(): void { + // Extract the raw id from the keybinding item (without fuzzy matching). + const id = this.item.id.replace(new RegExp(/(.*?)<\/match>/g), '$1'); + // Remove the custom keybinding, resetting it to its default value. + this.keymapsService.removeKeybinding(id); + } + +}