提交 ef33a6a6 编写于 作者: S Sandeep Somavarapu

Ability to edit when expression

上级 08a4504e
......@@ -42,32 +42,32 @@ export abstract class ContextKeyExpr {
return new ContextKeyAndExpr(expr);
}
public static deserialize(serialized: string | null | undefined): ContextKeyExpr | null {
public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | null {
if (!serialized) {
return null;
}
let pieces = serialized.split('&&');
let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p)));
let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict)));
return result.normalize();
}
private static _deserializeOne(serializedOne: string): ContextKeyExpr {
private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr {
serializedOne = serializedOne.trim();
if (serializedOne.indexOf('!=') >= 0) {
let pieces = serializedOne.split('!=');
return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1]));
return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('==') >= 0) {
let pieces = serializedOne.split('==');
return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1]));
return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('=~') >= 0) {
let pieces = serializedOne.split('=~');
return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1]));
return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));
}
if (/^\!\s*/.test(serializedOne)) {
......@@ -77,7 +77,7 @@ export abstract class ContextKeyExpr {
return new ContextKeyDefinedExpr(serializedOne);
}
private static _deserializeValue(serializedValue: string): any {
private static _deserializeValue(serializedValue: string, strict: boolean): any {
serializedValue = serializedValue.trim();
if (serializedValue === 'true') {
......@@ -96,17 +96,25 @@ export abstract class ContextKeyExpr {
return serializedValue;
}
private static _deserializeRegexValue(serializedValue: string): RegExp | null {
private static _deserializeRegexValue(serializedValue: string, strict: boolean): RegExp | null {
if (isFalsyOrWhitespace(serializedValue)) {
console.warn('missing regexp-value for =~-expression');
if (strict) {
throw new Error('missing regexp-value for =~-expression');
} else {
console.warn('missing regexp-value for =~-expression');
}
return null;
}
let start = serializedValue.indexOf('/');
let end = serializedValue.lastIndexOf('/');
if (start === end || start < 0 /* || to < 0 */) {
console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`);
if (strict) {
throw new Error(`bad regexp-value '${serializedValue}', missing /-enclosure`);
} else {
console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`);
}
return null;
}
......@@ -115,7 +123,11 @@ export abstract class ContextKeyExpr {
try {
return new RegExp(value, caseIgnoreFlag);
} catch (e) {
console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`);
if (strict) {
throw new Error(`bad regexp-value '${serializedValue}', parse error: ${e}`);
} else {
console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`);
}
return null;
}
}
......
......@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { OS } from 'vs/base/common/platform';
import { dispose } from 'vs/base/common/lifecycle';
import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { CheckboxActionItem } from 'vs/base/browser/ui/checkbox/checkbox';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
......@@ -25,15 +25,15 @@ import { DefineKeybindingWidget, KeybindingsSearchWidget, KeybindingsSearchOptio
import {
IKeybindingsEditor, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_COPY,
KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR,
KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS
KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN
} from 'vs/workbench/contrib/preferences/common/preferences';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { listHighlightForeground, badgeBackground, contrastBorder, badgeForeground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -42,9 +42,11 @@ import { WorkbenchList } from 'vs/platform/list/browser/listService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { KeybindingsEditorInput } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
import { CancellationToken } from 'vs/base/common/cancellation';
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
import { attachStylerCallback, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import { Emitter, Event } from 'vs/base/common/event';
const $ = DOM.$;
......@@ -52,6 +54,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
static readonly ID: string = 'workbench.editor.keybindings';
private _onDefineWhenExpression: Emitter<IKeybindingItemEntry> = this._register(new Emitter<IKeybindingItemEntry>());
readonly onDefineWhenExpression: Event<IKeybindingItemEntry> = this._onDefineWhenExpression.event;
private keybindingsEditorModel: KeybindingsEditorModel;
private headerContainer: HTMLElement;
......@@ -155,16 +160,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
this.showOverlayContainer();
return this.defineKeybindingWidget.define().then(key => {
if (key) {
const currentKey = keybindingEntry.keybindingItem.keybinding ? keybindingEntry.keybindingItem.keybinding.getUserSettingsLabel() : '';
if (currentKey !== key) {
this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_DEFINE, keybindingEntry.keybindingItem.command, key);
return this.keybindingEditingService.editKeybinding(key, keybindingEntry.keybindingItem.keybindingItem)
.then(() => {
if (!keybindingEntry.keybindingItem.keybinding) { // reveal only if keybinding was added to unassinged. Because the entry will be placed in different position after rendering
this.unAssignedKeybindingItemToRevealAndFocus = keybindingEntry;
}
});
}
this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_DEFINE, keybindingEntry.keybindingItem.command, key);
return this.updateKeybinding(keybindingEntry, key, keybindingEntry.keybindingItem.when);
}
return null;
}).then(() => {
......@@ -178,6 +175,24 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
});
}
defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void {
this.selectEntry(keybindingEntry);
this._onDefineWhenExpression.fire(keybindingEntry);
}
updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise<any> {
const currentKey = keybindingEntry.keybindingItem.keybinding ? keybindingEntry.keybindingItem.keybinding.getUserSettingsLabel() : '';
if (currentKey !== key || keybindingEntry.keybindingItem.when !== when) {
return this.keybindingEditingService.editKeybinding(keybindingEntry.keybindingItem.keybindingItem, key, when)
.then(() => {
if (!keybindingEntry.keybindingItem.keybinding) { // reveal only if keybinding was added to unassinged. Because the entry will be placed in different position after rendering
this.unAssignedKeybindingItemToRevealAndFocus = keybindingEntry;
}
});
}
return Promise.resolve();
}
removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise<any> {
this.selectEntry(keybindingEntry);
if (keybindingEntry.keybindingItem.keybinding) { // This should be a pre-condition
......@@ -400,13 +415,13 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
$('.header.actions'),
$('.header.command', undefined, localize('command', "Command")),
$('.header.keybinding', undefined, localize('keybinding', "Keybinding")),
$('.header.source', undefined, localize('source', "Source")),
$('.header.when', undefined, localize('when', "When")));
$('.header.when', undefined, localize('when', "When")),
$('.header.source', undefined, localize('source', "Source")));
}
private createList(parent: HTMLElement): void {
this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container'));
this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.keybindingsService)],
this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)],
{
identityProvider: { getId: e => e.id },
ariaLabel: localize('keybindingsLabel', "Keybindings"),
......@@ -557,6 +572,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
this.keybindingsList.setFocus([currentFocusIndices.length ? currentFocusIndices[0] : 0]);
}
selectKeybinding(keybindingItemEntry: IKeybindingItemEntry): void {
this.selectEntry(keybindingItemEntry);
}
recordSearchKeys(): void {
this.recordKeysAction.checked = true;
}
......@@ -579,6 +598,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
this.createCopyCommandAction(<IKeybindingItemEntry>e.element),
new Separator(),
this.createDefineAction(<IKeybindingItemEntry>e.element),
this.createDefineWhenExpressionAction(<IKeybindingItemEntry>e.element),
this.createRemoveAction(<IKeybindingItemEntry>e.element),
this.createResetAction(<IKeybindingItemEntry>e.element),
new Separator(),
......@@ -607,6 +627,15 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
};
}
private createDefineWhenExpressionAction(keybindingItemEntry: IKeybindingItemEntry): IAction {
return <IAction>{
label: localize('editWhen', "Change When Expression"),
enabled: true,
id: KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN,
run: () => this.defineWhenExpression(keybindingItemEntry)
};
}
private createRemoveAction(keybindingItem: IKeybindingItemEntry): IAction {
return <IAction>{
label: localize('removeLabel', "Remove Keybinding"),
......@@ -722,16 +751,19 @@ class KeybindingItemRenderer implements IListRenderer<IKeybindingItemEntry, Keyb
get templateId(): string { return KEYBINDING_ENTRY_TEMPLATE_ID; }
constructor(private keybindingsEditor: IKeybindingsEditor, private keybindingsService: IKeybindingService) { }
constructor(
private keybindingsEditor: IKeybindingsEditor,
private instantiationService: IInstantiationService
) { }
renderTemplate(container: HTMLElement): KeybindingItemTemplate {
DOM.addClass(container, 'keybinding-item');
const actions = new ActionsColumn(container, this.keybindingsEditor, this.keybindingsService);
const command = new CommandColumn(container, this.keybindingsEditor);
const keybinding = new KeybindingColumn(container, this.keybindingsEditor);
const source = new SourceColumn(container, this.keybindingsEditor);
const when = new WhenColumn(container, this.keybindingsEditor);
container.setAttribute('aria-labelledby', [command.id, keybinding.id, source.id, when.id].join(' '));
const actions = this.instantiationService.createInstance(ActionsColumn, container, this.keybindingsEditor);
const command = this.instantiationService.createInstance(CommandColumn, container, this.keybindingsEditor);
const keybinding = this.instantiationService.createInstance(KeybindingColumn, container, this.keybindingsEditor);
const when = this.instantiationService.createInstance(WhenColumn, container, this.keybindingsEditor);
const source = this.instantiationService.createInstance(SourceColumn, container, this.keybindingsEditor);
container.setAttribute('aria-labelledby', [command.element.getAttribute('id'), keybinding.element.getAttribute('id'), when.element.getAttribute('id'), source.element.getAttribute('id')].join(' '));
return {
parent: container,
actions,
......@@ -753,30 +785,35 @@ class KeybindingItemRenderer implements IListRenderer<IKeybindingItemEntry, Keyb
disposeTemplate(template: KeybindingItemTemplate): void {
template.actions.dispose();
template.command.dispose();
template.keybinding.dispose();
template.source.dispose();
template.when.dispose();
}
}
abstract class Column {
abstract class Column extends Disposable {
static COUNTER = 0;
protected element: HTMLElement;
readonly id: string;
constructor(protected parent: HTMLElement, protected keybindingsEditor: IKeybindingsEditor) {
this.element = this.create(parent);
this.id = this.element.getAttribute('id');
constructor(protected keybindingsEditor: IKeybindingsEditor) {
super();
}
abstract create(parent: HTMLElement): HTMLElement;
}
class ActionsColumn extends Column {
private actionBar: ActionBar;
readonly element: HTMLElement;
constructor(parent: HTMLElement, keybindingsEditor: IKeybindingsEditor, private keybindingsService: IKeybindingService) {
super(parent, keybindingsEditor);
constructor(
parent: HTMLElement,
keybindingsEditor: IKeybindingsEditor,
@IKeybindingService private keybindingsService: IKeybindingService
) {
super(keybindingsEditor);
this.element = this.create(parent);
}
create(parent: HTMLElement): HTMLElement {
......@@ -826,8 +863,17 @@ class ActionsColumn extends Column {
class CommandColumn extends Column {
private commandColumn: HTMLElement;
readonly element: HTMLElement;
create(parent: HTMLElement): HTMLElement {
constructor(
parent: HTMLElement,
keybindingsEditor: IKeybindingsEditor,
) {
super(keybindingsEditor);
this.element = this.create(parent);
}
private create(parent: HTMLElement): HTMLElement {
this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER }));
return this.commandColumn;
}
......@@ -864,18 +910,28 @@ class CommandColumn extends Column {
class KeybindingColumn extends Column {
private keybindingColumn: HTMLElement;
private keybindingLabel: HTMLElement;
readonly element: HTMLElement;
create(parent: HTMLElement): HTMLElement {
this.keybindingColumn = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER }));
return this.keybindingColumn;
constructor(
parent: HTMLElement,
keybindingsEditor: IKeybindingsEditor,
) {
super(keybindingsEditor);
this.element = this.create(parent);
}
private create(parent: HTMLElement): HTMLElement {
const column = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER }));
this.keybindingLabel = DOM.append(column, $('div.keybinding-label'));
return column;
}
render(keybindingItemEntry: IKeybindingItemEntry): void {
DOM.clearNode(this.keybindingColumn);
this.keybindingColumn.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry));
DOM.clearNode(this.keybindingLabel);
this.keybindingLabel.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry));
if (keybindingItemEntry.keybindingItem.keybinding) {
new KeybindingLabel(this.keybindingColumn, OS).set(keybindingItemEntry.keybindingItem.keybinding, keybindingItemEntry.keybindingMatches);
new KeybindingLabel(this.keybindingLabel, OS).set(keybindingItemEntry.keybindingItem.keybinding, keybindingItemEntry.keybindingMatches);
}
}
......@@ -887,6 +943,15 @@ class KeybindingColumn extends Column {
class SourceColumn extends Column {
private sourceColumn: HTMLElement;
readonly element: HTMLElement;
constructor(
parent: HTMLElement,
keybindingsEditor: IKeybindingsEditor,
) {
super(keybindingsEditor);
this.element = this.create(parent);
}
create(parent: HTMLElement): HTMLElement {
this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER }));
......@@ -906,28 +971,117 @@ class SourceColumn extends Column {
class WhenColumn extends Column {
private whenColumn: HTMLElement;
readonly element: HTMLElement;
private whenLabel: HTMLElement;
private whenInput: InputBox;
private disposables: IDisposable[] = [];
create(parent: HTMLElement): HTMLElement {
const column = DOM.append(parent, $('.column.when'));
this.whenColumn = DOM.append(column, $('div', { id: 'when_' + ++Column.COUNTER }));
return this.whenColumn;
private _onDidAccept: Emitter<void> = this._register(new Emitter<void>());
private readonly onDidAccept: Event<void> = this._onDidAccept.event;
private _onDidReject: Emitter<void> = this._register(new Emitter<void>());
private readonly onDidReject: Event<void> = this._onDidReject.event;
constructor(
parent: HTMLElement,
keybindingsEditor: IKeybindingsEditor,
@IContextViewService private readonly contextViewService: IContextViewService,
@IThemeService private readonly themeService: IThemeService
) {
super(keybindingsEditor);
this.element = this.create(parent);
this._register(toDisposable(() => this.disposables = dispose(this.disposables)));
}
private create(parent: HTMLElement): HTMLElement {
const column = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER }));
this.whenLabel = DOM.append(column, $('div.when-label'));
this.whenInput = new InputBox(column, this.contextViewService, {
validationOptions: {
validation: (value) => {
try {
ContextKeyExpr.deserialize(value, true);
} catch (error) {
return {
content: error.message,
formatContent: true,
type: MessageType.ERROR
};
}
return null;
}
},
ariaLabel: localize('whenContextInputAriaLabel', "Type when context. Press Enter to confirm or Escape to cancel.")
});
this._register(attachInputBoxStyler(this.whenInput, this.themeService));
this._register(DOM.addStandardDisposableListener(this.whenInput.inputElement, DOM.EventType.KEY_DOWN, e => this.onInputKeyDown(e)));
this._register(DOM.addDisposableListener(this.whenInput.inputElement, DOM.EventType.BLUR, () => this.cancelEditing()));
return column;
}
private onInputKeyDown(e: IKeyboardEvent): void {
let handled = false;
if (e.equals(KeyCode.Enter)) {
this.finishEditing();
handled = true;
} else if (e.equals(KeyCode.Escape)) {
this.cancelEditing();
handled = true;
}
if (handled) {
e.preventDefault();
e.stopPropagation();
}
}
private startEditing(): void {
DOM.addClass(this.element, 'input-mode');
this.whenInput.focus();
this.whenInput.select();
}
private finishEditing(): void {
DOM.removeClass(this.element, 'input-mode');
this._onDidAccept.fire();
}
private cancelEditing(): void {
DOM.removeClass(this.element, 'input-mode');
this._onDidReject.fire();
}
render(keybindingItemEntry: IKeybindingItemEntry): void {
DOM.clearNode(this.whenColumn);
this.whenColumn.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry));
DOM.toggleClass(this.whenColumn, 'code', !!keybindingItemEntry.keybindingItem.when);
DOM.toggleClass(this.whenColumn, 'empty', !keybindingItemEntry.keybindingItem.when);
this.disposables = dispose(this.disposables);
DOM.clearNode(this.whenLabel);
this.keybindingsEditor.onDefineWhenExpression(e => {
if (keybindingItemEntry === e) {
this.startEditing();
}
}, this, this.disposables);
this.whenInput.value = keybindingItemEntry.keybindingItem.when || '';
this.whenLabel.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry));
DOM.toggleClass(this.whenLabel, 'code', !!keybindingItemEntry.keybindingItem.when);
DOM.toggleClass(this.whenLabel, 'empty', !keybindingItemEntry.keybindingItem.when);
if (keybindingItemEntry.keybindingItem.when) {
const whenLabel = new HighlightedLabel(this.whenColumn, false);
const whenLabel = new HighlightedLabel(this.whenLabel, false);
whenLabel.set(keybindingItemEntry.keybindingItem.when, keybindingItemEntry.whenMatches);
this.whenColumn.title = keybindingItemEntry.keybindingItem.when;
this.element.title = keybindingItemEntry.keybindingItem.when;
whenLabel.element.title = keybindingItemEntry.keybindingItem.when;
} else {
this.whenColumn.textContent = '';
this.whenColumn.title = '';
this.whenLabel.textContent = '';
this.element.title = '';
}
this.onDidAccept(() => {
this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() : '', this.whenInput.value);
this.keybindingsEditor.selectKeybinding(keybindingItemEntry);
}, this, this.disposables);
this.onDidReject(() => {
this.whenInput.value = keybindingItemEntry.keybindingItem.when || '';
this.keybindingsEditor.selectKeybinding(keybindingItemEntry);
}, this, this.disposables);
}
private getAriaLabel(keybindingItemEntry: IKeybindingItemEntry): string {
......
......@@ -45,30 +45,30 @@
margin-right: 4px;
}
.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence {
.keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence {
background: url('sort_precedence.svg') center center no-repeat;
}
.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence,
.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence {
.hc-black .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence,
.vs-dark .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence {
background: url('sort_precedence_inverse.svg') center center no-repeat;
}
.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys {
.keybindings-editor .monaco-action-bar .action-item > .record-keys {
background: url('record-keys.svg') center center no-repeat;
}
.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys,
.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys {
.hc-black .keybindings-editor .monaco-action-bar .action-item > .record-keys,
.vs-dark .keybindings-editor .monaco-action-bar .action-item > .record-keys {
background: url('record-keys-inverse.svg') center center no-repeat;
}
.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input {
.keybindings-editor .monaco-action-bar .action-item > .clear-input {
background: url('clear.svg') center center no-repeat;
}
.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input,
.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input {
.hc-black .keybindings-editor .monaco-action-bar .action-item > .clear-input,
.vs-dark .keybindings-editor .monaco-action-bar .action-item > .clear-input {
background: url('clear-inverse.svg') center center no-repeat;
}
......@@ -171,6 +171,21 @@
padding-left: 4px;
}
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when:not(.input-mode) .monaco-inputbox,
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when.input-mode .when-label {
display: none;
}
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox {
width: 100%;
line-height: normal;
}
.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox,
.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox {
height: 24px;
}
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command .monaco-highlighted-label,
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .source .monaco-highlighted-label,
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .when .monaco-highlighted-label {
......@@ -201,7 +216,7 @@
color: inherit;
}
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar {
.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column.actions .monaco-action-bar {
display: none;
flex: 1;
}
......
......@@ -10,6 +10,7 @@ import { ISettingsEditorModel, ISearchResult } from 'vs/workbench/services/prefe
import { IEditor } from 'vs/workbench/common/editor';
import { IKeybindingItemEntry } from 'vs/workbench/services/preferences/common/keybindingsEditorModel';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Event } from 'vs/base/common/event';
export interface IWorkbenchSettingsConfiguration {
workbench: {
......@@ -45,7 +46,8 @@ export interface ISearchProvider {
export interface IKeybindingsEditor extends IEditor {
activeKeybindingEntry: IKeybindingItemEntry;
readonly activeKeybindingEntry: IKeybindingItemEntry;
readonly onDefineWhenExpression: Event<IKeybindingItemEntry>;
search(filter: string): void;
focusSearch(): void;
......@@ -53,7 +55,10 @@ export interface IKeybindingsEditor extends IEditor {
focusKeybindings(): void;
recordSearchKeys(): void;
toggleSortByPrecedence(): void;
defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise<any>;
selectKeybinding(keybindingEntry: IKeybindingItemEntry): void;
defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise<void>;
defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void;
updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise<any>;
removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise<any>;
resetKeybinding(keybindingEntry: IKeybindingItemEntry): Promise<any>;
copyKeybinding(keybindingEntry: IKeybindingItemEntry): void;
......@@ -88,6 +93,7 @@ export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.edit
export const KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS = 'keybindings.editor.recordSearchKeys';
export const KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE = 'keybindings.editor.toggleSortByPrecedence';
export const KEYBINDINGS_EDITOR_COMMAND_DEFINE = 'keybindings.editor.defineKeybinding';
export const KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN = 'keybindings.editor.defineWhenExpression';
export const KEYBINDINGS_EDITOR_COMMAND_REMOVE = 'keybindings.editor.removeKeybinding';
export const KEYBINDINGS_EDITOR_COMMAND_RESET = 'keybindings.editor.resetKeybinding';
export const KEYBINDINGS_EDITOR_COMMAND_COPY = 'keybindings.editor.copyKeybindingEntry';
......
......@@ -29,7 +29,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor';
import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor';
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS } from 'vs/workbench/contrib/preferences/common/preferences';
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution';
import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch';
import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/electron-browser/settingsEditor2';
......@@ -231,6 +231,19 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN,
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_E),
handler: (accessor, args: any) => {
const control = accessor.get(IEditorService).activeControl as IKeybindingsEditor;
if (control && control instanceof KeybindingsEditor) {
control.defineWhenExpression(control.activeKeybindingEntry);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: KEYBINDINGS_EDITOR_COMMAND_REMOVE,
weight: KeybindingWeight.WorkbenchContrib,
......
......@@ -32,7 +32,7 @@ export interface IKeybindingEditingService {
_serviceBrand: ServiceIdentifier<any>;
editKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise<void>;
editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise<void>;
removeKeybinding(keybindingItem: ResolvedKeybindingItem): Promise<void>;
......@@ -57,8 +57,8 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
this.queue = new Queue<void>();
}
editKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise<void> {
return this.queue.queue(() => this.doEditKeybinding(key, keybindingItem)); // queue up writes to prevent race conditions
editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise<void> {
return this.queue.queue(() => this.doEditKeybinding(keybindingItem, key, when)); // queue up writes to prevent race conditions
}
resetKeybinding(keybindingItem: ResolvedKeybindingItem): Promise<void> {
......@@ -69,13 +69,13 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
return this.queue.queue(() => this.doRemoveKeybinding(keybindingItem)); // queue up writes to prevent race conditions
}
private doEditKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise<void> {
private doEditKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise<void> {
return this.resolveAndValidate()
.then(reference => {
const model = reference.object.textEditorModel;
const userKeybindingEntries = <IUserFriendlyKeybinding[]>json.parse(model.getValue());
const userKeybindingEntryIndex = this.findUserKeybindingEntryIndex(keybindingItem, userKeybindingEntries);
this.updateKeybinding(key, keybindingItem, model, userKeybindingEntryIndex);
this.updateKeybinding(keybindingItem, key, when, model, userKeybindingEntryIndex);
if (keybindingItem.isDefault && keybindingItem.resolvedKeybinding) {
this.removeDefaultKeybinding(keybindingItem, model);
}
......@@ -112,15 +112,16 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
return this.textFileService.save(this.resource);
}
private updateKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: ITextModel, userKeybindingEntryIndex: number): void {
private updateKeybinding(keybindingItem: ResolvedKeybindingItem, newKey: string, when: string, model: ITextModel, userKeybindingEntryIndex: number): void {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
if (userKeybindingEntryIndex !== -1) {
// Update the keybinding with new key
this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'key'], newKey, { tabSize, insertSpaces, eol })[0], model);
this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'when'], when, { tabSize, insertSpaces, eol })[0], model);
} else {
// Add the new keybinding with new key
this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(newKey, keybindingItem.command, keybindingItem.when, false), { tabSize, insertSpaces, eol })[0], model);
this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(newKey, keybindingItem.command, when, false), { tabSize, insertSpaces, eol })[0], model);
}
}
......@@ -137,7 +138,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
private removeDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when, true), { tabSize, insertSpaces, eol })[0], model);
this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when.serialize(), true), { tabSize, insertSpaces, eol })[0], model);
}
private removeUnassignedDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
......@@ -177,11 +178,11 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
return indices;
}
private asObject(key: string, command: string, when: ContextKeyExpr, negate: boolean): any {
private asObject(key: string, command: string, when: string, negate: boolean): any {
const object = { key };
object['command'] = negate ? `-${command}` : command;
if (when) {
object['when'] = when.serialize();
object['when'] = when;
}
return object;
}
......
......@@ -120,28 +120,28 @@ suite('KeybindingsEditing', () => {
test('errors cases - parse errors', () => {
fs.writeFileSync(keybindingsFile, ',,,,,,,,,,,,,,');
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '')
.then(() => assert.fail('Should fail with parse errors'),
error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.'));
});
test('errors cases - parse errors 2', () => {
fs.writeFileSync(keybindingsFile, '[{"key": }]');
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '')
.then(() => assert.fail('Should fail with parse errors'),
error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.'));
});
test('errors cases - dirty', () => {
instantiationService.stub(ITextFileService, 'isDirty', true);
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '')
.then(() => assert.fail('Should fail with dirty error'),
error => assert.equal(error.message, 'Unable to write because the keybindings configuration file is dirty. Please save it first and then try again.'));
});
test('errors cases - did not find an array', () => {
fs.writeFileSync(keybindingsFile, '{"key": "alt+c", "command": "hello"}');
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '')
.then(() => assert.fail('Should fail with dirty error'),
error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. It has an object which is not of type Array. Please open the file to clean up and try again.'));
});
......@@ -149,7 +149,7 @@ suite('KeybindingsEditing', () => {
test('edit a default keybinding to an empty file', () => {
fs.writeFileSync(keybindingsFile, '');
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
......@@ -159,41 +159,41 @@ suite('KeybindingsEditing', () => {
testObject = instantiationService.createInstance(KeybindingsEditingService);
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
test('edit a default keybinding to an empty array', () => {
writeToKeybindingsFile();
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
test('edit a default keybinding in an existing array', () => {
writeToKeybindingsFile({ command: 'b', key: 'shift+c' });
const expected: IUserFriendlyKeybinding[] = [{ key: 'shift+c', command: 'b' }, { key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
test('add a new default keybinding', () => {
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ command: 'a' }))
return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a' }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
test('edit an user keybinding', () => {
writeToKeybindingsFile({ key: 'escape', command: 'b' });
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
test('edit an user keybinding with more than one element', () => {
writeToKeybindingsFile({ key: 'escape', command: 'b' }, { key: 'alt+shift+g', command: 'c' });
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }, { key: 'alt+shift+g', command: 'c' }];
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }))
return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
......@@ -232,7 +232,7 @@ suite('KeybindingsEditing', () => {
test('add a new keybinding to unassigned keybinding', () => {
writeToKeybindingsFile({ key: 'alt+c', command: '-a' });
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }, { key: 'shift+alt+c', command: 'a' }];
return testObject.editKeybinding('shift+alt+c', aResolvedKeybindingItem({ command: 'a', isDefault: false }))
return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', '')
.then(() => assert.deepEqual(getUserKeybindings(), expected));
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册