mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 03:58:33 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -14,7 +14,6 @@ import { Edit } from 'vs/base/common/jsonFormatter';
|
||||
import { setProperty } from 'vs/base/common/jsonEdit';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
@@ -25,6 +24,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
|
||||
|
||||
export const IKeybindingEditingService = createDecorator<IKeybindingEditingService>('keybindingEditingService');
|
||||
@@ -112,7 +112,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
return this.textFileService.save(this.resource);
|
||||
}
|
||||
|
||||
private updateUserKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: editorCommon.IModel): void {
|
||||
private updateUserKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
|
||||
const { tabSize, insertSpaces } = model.getOptions();
|
||||
const eol = model.getEOL();
|
||||
const userKeybindingEntries = <IUserFriendlyKeybinding[]>json.parse(model.getValue());
|
||||
@@ -122,7 +122,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
}
|
||||
}
|
||||
|
||||
private updateDefaultKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: editorCommon.IModel): void {
|
||||
private updateDefaultKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
|
||||
const { tabSize, insertSpaces } = model.getOptions();
|
||||
const eol = model.getEOL();
|
||||
const userKeybindingEntries = <IUserFriendlyKeybinding[]>json.parse(model.getValue());
|
||||
@@ -140,7 +140,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
}
|
||||
}
|
||||
|
||||
private removeUserKeybinding(keybindingItem: ResolvedKeybindingItem, model: editorCommon.IModel): void {
|
||||
private removeUserKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
|
||||
const { tabSize, insertSpaces } = model.getOptions();
|
||||
const eol = model.getEOL();
|
||||
const userKeybindingEntries = <IUserFriendlyKeybinding[]>json.parse(model.getValue());
|
||||
@@ -150,13 +150,13 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
}
|
||||
}
|
||||
|
||||
private removeDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: editorCommon.IModel): void {
|
||||
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);
|
||||
}
|
||||
|
||||
private removeUnassignedDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: editorCommon.IModel): void {
|
||||
private removeUnassignedDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void {
|
||||
const { tabSize, insertSpaces } = model.getOptions();
|
||||
const eol = model.getEOL();
|
||||
const userKeybindingEntries = <IUserFriendlyKeybinding[]>json.parse(model.getValue());
|
||||
@@ -202,7 +202,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
}
|
||||
|
||||
|
||||
private applyEditsToBuffer(edit: Edit, model: editorCommon.IModel): void {
|
||||
private applyEditsToBuffer(edit: Edit, model: ITextModel): void {
|
||||
const startPosition = model.getPositionAt(edit.offset);
|
||||
const endPosition = model.getPositionAt(edit.offset + edit.length);
|
||||
const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
|
||||
@@ -225,7 +225,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
|
||||
// Target cannot be dirty if not writing into buffer
|
||||
if (this.textFileService.isDirty(this.resource)) {
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('errorKeybindingsFileDirty', "Unable to write because the file is dirty. Please save the **Keybindings** file and try again.")));
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('errorKeybindingsFileDirty', "Unable to write because the keybindings configuration file is dirty. Please save it first and then try again.")));
|
||||
}
|
||||
|
||||
return this.resolveModelReference()
|
||||
@@ -235,11 +235,11 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
if (model.getValue()) {
|
||||
const parsed = this.parse(model);
|
||||
if (parsed.parseErrors.length) {
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('parseErrors', "Unable to write keybindings. Please open **Keybindings file** to correct errors/warnings in the file and try again.")));
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('parseErrors', "Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.")));
|
||||
}
|
||||
if (parsed.result) {
|
||||
if (!isArray(parsed.result)) {
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('errorInvalidConfiguration', "Unable to write keybindings. **Keybindings file** has an object which is not of type Array. Please open the file to clean up and try again.")));
|
||||
return TPromise.wrapError<IReference<ITextEditorModel>>(new Error(localize('errorInvalidConfiguration', "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.")));
|
||||
}
|
||||
} else {
|
||||
const content = EOL + '[]';
|
||||
@@ -253,7 +253,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding
|
||||
});
|
||||
}
|
||||
|
||||
private parse(model: editorCommon.IModel): { result: IUserFriendlyKeybinding[], parseErrors: json.ParseError[] } {
|
||||
private parse(model: ITextModel): { result: IUserFriendlyKeybinding[], parseErrors: json.ParseError[] } {
|
||||
const parseErrors: json.ParseError[] = [];
|
||||
const result = json.parse(model.getValue(), parseErrors, { allowTrailingComma: true });
|
||||
return { result, parseErrors };
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keyCodes';
|
||||
import { OS, OperatingSystem } from 'vs/base/common/platform';
|
||||
import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
@@ -16,11 +16,10 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IKeybindingEvent, IUserFriendlyKeybinding, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindingItem, KeybindingsRegistry, IKeybindingRule2 } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IKeybindingItem, KeybindingsRegistry, IKeybindingRule2, KeybindingRuleSource } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { ConfigWatcher } from 'vs/base/node/config';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
@@ -36,6 +35,8 @@ import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Extensions as ConfigExtensions, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { release } from 'os';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export class KeyboardMapperFactory {
|
||||
public static readonly INSTANCE = new KeyboardMapperFactory();
|
||||
@@ -262,12 +263,12 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IMessageService messageService: IMessageService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IStatusbarService statusBarService: IStatusbarService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
super(contextKeyService, commandService, telemetryService, messageService, statusBarService);
|
||||
super(contextKeyService, commandService, telemetryService, notificationService, statusBarService);
|
||||
|
||||
let dispatchConfig = getDispatchConfig(configurationService);
|
||||
configurationService.onDidChangeConfiguration((e) => {
|
||||
@@ -458,7 +459,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
|
||||
if (isValidContributedKeyBinding(keybindings, rejects)) {
|
||||
let rule = this._asCommandRule(isBuiltin, idx++, keybindings);
|
||||
if (rule) {
|
||||
KeybindingsRegistry.registerKeybindingRule2(rule);
|
||||
KeybindingsRegistry.registerKeybindingRule2(rule, KeybindingRuleSource.Extension);
|
||||
commandAdded = true;
|
||||
}
|
||||
}
|
||||
@@ -583,6 +584,12 @@ const keyboardConfiguration: IConfigurationNode = {
|
||||
'default': 'code',
|
||||
'description': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`."),
|
||||
'included': OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux
|
||||
},
|
||||
'keyboard.touchbar.enabled': {
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': nls.localize('touchbar.enabled', "Enables the macOS touchbar buttons on the keyboard if available."),
|
||||
'included': OS === OperatingSystem.Macintosh && parseFloat(release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,6 +13,151 @@ import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayo
|
||||
import { ScanCodeBinding, ScanCode } from 'vs/workbench/services/keybinding/common/scanCode';
|
||||
|
||||
suite('keybindingIO', () => {
|
||||
|
||||
test('serialize/deserialize', function () {
|
||||
|
||||
function testOneSerialization(keybinding: number, expected: string, msg: string, OS: OperatingSystem): void {
|
||||
let usLayoutResolvedKeybinding = new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS), OS);
|
||||
let actualSerialized = usLayoutResolvedKeybinding.getUserSettingsLabel();
|
||||
assert.equal(actualSerialized, expected, expected + ' - ' + msg);
|
||||
}
|
||||
function testSerialization(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {
|
||||
testOneSerialization(keybinding, expectedWin, 'win', OperatingSystem.Windows);
|
||||
testOneSerialization(keybinding, expectedMac, 'mac', OperatingSystem.Macintosh);
|
||||
testOneSerialization(keybinding, expectedLinux, 'linux', OperatingSystem.Linux);
|
||||
}
|
||||
|
||||
function testOneDeserialization(keybinding: string, _expected: number, msg: string, OS: OperatingSystem): void {
|
||||
let actualDeserialized = KeybindingIO.readKeybinding(keybinding, OS);
|
||||
let expected = createKeybinding(_expected, OS);
|
||||
assert.deepEqual(actualDeserialized, expected, keybinding + ' - ' + msg);
|
||||
}
|
||||
function testDeserialization(inWin: string, inMac: string, inLinux: string, expected: number): void {
|
||||
testOneDeserialization(inWin, expected, 'win', OperatingSystem.Windows);
|
||||
testOneDeserialization(inMac, expected, 'mac', OperatingSystem.Macintosh);
|
||||
testOneDeserialization(inLinux, expected, 'linux', OperatingSystem.Linux);
|
||||
}
|
||||
|
||||
function testRoundtrip(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {
|
||||
testSerialization(keybinding, expectedWin, expectedMac, expectedLinux);
|
||||
testDeserialization(expectedWin, expectedMac, expectedLinux, keybinding);
|
||||
}
|
||||
|
||||
testRoundtrip(KeyCode.KEY_0, '0', '0', '0');
|
||||
testRoundtrip(KeyCode.KEY_A, 'a', 'a', 'a');
|
||||
testRoundtrip(KeyCode.UpArrow, 'up', 'up', 'up');
|
||||
testRoundtrip(KeyCode.RightArrow, 'right', 'right', 'right');
|
||||
testRoundtrip(KeyCode.DownArrow, 'down', 'down', 'down');
|
||||
testRoundtrip(KeyCode.LeftArrow, 'left', 'left', 'left');
|
||||
|
||||
// one modifier
|
||||
testRoundtrip(KeyMod.Alt | KeyCode.KEY_A, 'alt+a', 'alt+a', 'alt+a');
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyCode.KEY_A, 'ctrl+a', 'cmd+a', 'ctrl+a');
|
||||
testRoundtrip(KeyMod.Shift | KeyCode.KEY_A, 'shift+a', 'shift+a', 'shift+a');
|
||||
testRoundtrip(KeyMod.WinCtrl | KeyCode.KEY_A, 'win+a', 'ctrl+a', 'meta+a');
|
||||
|
||||
// two modifiers
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_A, 'ctrl+alt+a', 'alt+cmd+a', 'ctrl+alt+a');
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_A, 'ctrl+shift+a', 'shift+cmd+a', 'ctrl+shift+a');
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_A, 'ctrl+win+a', 'ctrl+cmd+a', 'ctrl+meta+a');
|
||||
testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_A, 'shift+alt+a', 'shift+alt+a', 'shift+alt+a');
|
||||
testRoundtrip(KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KEY_A, 'shift+win+a', 'ctrl+shift+a', 'shift+meta+a');
|
||||
testRoundtrip(KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A, 'alt+win+a', 'ctrl+alt+a', 'alt+meta+a');
|
||||
|
||||
// three modifiers
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_A, 'ctrl+shift+alt+a', 'shift+alt+cmd+a', 'ctrl+shift+alt+a');
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KEY_A, 'ctrl+shift+win+a', 'ctrl+shift+cmd+a', 'ctrl+shift+meta+a');
|
||||
testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A, 'shift+alt+win+a', 'ctrl+shift+alt+a', 'shift+alt+meta+a');
|
||||
|
||||
// all modifiers
|
||||
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A, 'ctrl+shift+alt+win+a', 'ctrl+shift+alt+cmd+a', 'ctrl+shift+alt+meta+a');
|
||||
|
||||
// chords
|
||||
testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_A, KeyMod.CtrlCmd | KeyCode.KEY_A), 'ctrl+a ctrl+a', 'cmd+a cmd+a', 'ctrl+a ctrl+a');
|
||||
testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.UpArrow, KeyMod.CtrlCmd | KeyCode.UpArrow), 'ctrl+up ctrl+up', 'cmd+up cmd+up', 'ctrl+up ctrl+up');
|
||||
|
||||
// OEM keys
|
||||
testRoundtrip(KeyCode.US_SEMICOLON, ';', ';', ';');
|
||||
testRoundtrip(KeyCode.US_EQUAL, '=', '=', '=');
|
||||
testRoundtrip(KeyCode.US_COMMA, ',', ',', ',');
|
||||
testRoundtrip(KeyCode.US_MINUS, '-', '-', '-');
|
||||
testRoundtrip(KeyCode.US_DOT, '.', '.', '.');
|
||||
testRoundtrip(KeyCode.US_SLASH, '/', '/', '/');
|
||||
testRoundtrip(KeyCode.US_BACKTICK, '`', '`', '`');
|
||||
testRoundtrip(KeyCode.ABNT_C1, 'abnt_c1', 'abnt_c1', 'abnt_c1');
|
||||
testRoundtrip(KeyCode.ABNT_C2, 'abnt_c2', 'abnt_c2', 'abnt_c2');
|
||||
testRoundtrip(KeyCode.US_OPEN_SQUARE_BRACKET, '[', '[', '[');
|
||||
testRoundtrip(KeyCode.US_BACKSLASH, '\\', '\\', '\\');
|
||||
testRoundtrip(KeyCode.US_CLOSE_SQUARE_BRACKET, ']', ']', ']');
|
||||
testRoundtrip(KeyCode.US_QUOTE, '\'', '\'', '\'');
|
||||
testRoundtrip(KeyCode.OEM_8, 'oem_8', 'oem_8', 'oem_8');
|
||||
testRoundtrip(KeyCode.OEM_102, 'oem_102', 'oem_102', 'oem_102');
|
||||
|
||||
// OEM aliases
|
||||
testDeserialization('OEM_1', 'OEM_1', 'OEM_1', KeyCode.US_SEMICOLON);
|
||||
testDeserialization('OEM_PLUS', 'OEM_PLUS', 'OEM_PLUS', KeyCode.US_EQUAL);
|
||||
testDeserialization('OEM_COMMA', 'OEM_COMMA', 'OEM_COMMA', KeyCode.US_COMMA);
|
||||
testDeserialization('OEM_MINUS', 'OEM_MINUS', 'OEM_MINUS', KeyCode.US_MINUS);
|
||||
testDeserialization('OEM_PERIOD', 'OEM_PERIOD', 'OEM_PERIOD', KeyCode.US_DOT);
|
||||
testDeserialization('OEM_2', 'OEM_2', 'OEM_2', KeyCode.US_SLASH);
|
||||
testDeserialization('OEM_3', 'OEM_3', 'OEM_3', KeyCode.US_BACKTICK);
|
||||
testDeserialization('ABNT_C1', 'ABNT_C1', 'ABNT_C1', KeyCode.ABNT_C1);
|
||||
testDeserialization('ABNT_C2', 'ABNT_C2', 'ABNT_C2', KeyCode.ABNT_C2);
|
||||
testDeserialization('OEM_4', 'OEM_4', 'OEM_4', KeyCode.US_OPEN_SQUARE_BRACKET);
|
||||
testDeserialization('OEM_5', 'OEM_5', 'OEM_5', KeyCode.US_BACKSLASH);
|
||||
testDeserialization('OEM_6', 'OEM_6', 'OEM_6', KeyCode.US_CLOSE_SQUARE_BRACKET);
|
||||
testDeserialization('OEM_7', 'OEM_7', 'OEM_7', KeyCode.US_QUOTE);
|
||||
testDeserialization('OEM_8', 'OEM_8', 'OEM_8', KeyCode.OEM_8);
|
||||
testDeserialization('OEM_102', 'OEM_102', 'OEM_102', KeyCode.OEM_102);
|
||||
|
||||
// accepts '-' as separator
|
||||
testDeserialization('ctrl-shift-alt-win-a', 'ctrl-shift-alt-cmd-a', 'ctrl-shift-alt-meta-a', KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A);
|
||||
|
||||
// various input mistakes
|
||||
testDeserialization(' ctrl-shift-alt-win-A ', ' shift-alt-cmd-Ctrl-A ', ' ctrl-shift-alt-META-A ', KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A);
|
||||
});
|
||||
|
||||
test('deserialize scan codes', () => {
|
||||
assert.deepEqual(
|
||||
KeybindingIO._readUserBinding('ctrl+shift+[comma] ctrl+/'),
|
||||
[new ScanCodeBinding(true, true, false, false, ScanCode.Comma), new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH)]
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #10452 - invalid command', () => {
|
||||
let strJSON = `[{ "key": "ctrl+k ctrl+f", "command": ["firstcommand", "seccondcommand"] }]`;
|
||||
let userKeybinding = <IUserFriendlyKeybinding>JSON.parse(strJSON)[0];
|
||||
let keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding, OS);
|
||||
assert.equal(keybindingItem.command, null);
|
||||
});
|
||||
|
||||
test('issue #10452 - invalid when', () => {
|
||||
let strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [] }]`;
|
||||
let userKeybinding = <IUserFriendlyKeybinding>JSON.parse(strJSON)[0];
|
||||
let keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding, OS);
|
||||
assert.equal(keybindingItem.when, null);
|
||||
});
|
||||
|
||||
test('issue #10452 - invalid key', () => {
|
||||
let strJSON = `[{ "key": [], "command": "firstcommand" }]`;
|
||||
let userKeybinding = <IUserFriendlyKeybinding>JSON.parse(strJSON)[0];
|
||||
let keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding, OS);
|
||||
assert.equal(keybindingItem.firstPart, null);
|
||||
assert.equal(keybindingItem.chordPart, null);
|
||||
});
|
||||
|
||||
test('issue #10452 - invalid key 2', () => {
|
||||
let strJSON = `[{ "key": "", "command": "firstcommand" }]`;
|
||||
let userKeybinding = <IUserFriendlyKeybinding>JSON.parse(strJSON)[0];
|
||||
let keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding, OS);
|
||||
assert.equal(keybindingItem.firstPart, null);
|
||||
assert.equal(keybindingItem.chordPart, null);
|
||||
});
|
||||
|
||||
test('test commands args', () => {
|
||||
let strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [], "args": { "text": "theText" } }]`;
|
||||
let userKeybinding = <IUserFriendlyKeybinding>JSON.parse(strJSON)[0];
|
||||
let keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding, OS);
|
||||
assert.equal(keybindingItem.commandArgs.text, 'theText');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ export function assertMapping(writeFileIfDifferent: boolean, mapper: IKeyboardMa
|
||||
writeFile(filePath, actual);
|
||||
}
|
||||
try {
|
||||
assert.deepEqual(actual, expected);
|
||||
assert.deepEqual(actual.split(/\r\n|\n/), expected.split(/\r\n|\n/));
|
||||
} catch (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,222 @@ import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding
|
||||
import { ScanCodeBinding, ScanCode } from 'vs/workbench/services/keybinding/common/scanCode';
|
||||
|
||||
suite('keyboardMapper - MAC fallback', () => {
|
||||
|
||||
let mapper = new MacLinuxFallbackKeyboardMapper(OperatingSystem.Macintosh);
|
||||
|
||||
function _assertResolveKeybinding(k: number, expected: IResolvedKeybinding[]): void {
|
||||
assertResolveKeybinding(mapper, createKeybinding(k, OperatingSystem.Macintosh), expected);
|
||||
}
|
||||
|
||||
test('resolveKeybinding Cmd+Z', () => {
|
||||
_assertResolveKeybinding(
|
||||
KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
[{
|
||||
label: '⌘Z',
|
||||
ariaLabel: 'Command+Z',
|
||||
electronAccelerator: 'Cmd+Z',
|
||||
userSettingsLabel: 'cmd+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['meta+Z', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Cmd+K Cmd+=', () => {
|
||||
_assertResolveKeybinding(
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_EQUAL),
|
||||
[{
|
||||
label: '⌘K ⌘=',
|
||||
ariaLabel: 'Command+K Command+=',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'cmd+k cmd+=',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['meta+K', 'meta+='],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Cmd+Z', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: true,
|
||||
keyCode: KeyCode.KEY_Z,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: '⌘Z',
|
||||
ariaLabel: 'Command+Z',
|
||||
electronAccelerator: 'Cmd+Z',
|
||||
userSettingsLabel: 'cmd+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['meta+Z', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Cmd+[Comma] Cmd+/', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(false, false, false, true, ScanCode.Comma),
|
||||
new SimpleKeybinding(false, false, false, true, KeyCode.US_SLASH),
|
||||
[{
|
||||
label: '⌘, ⌘/',
|
||||
ariaLabel: 'Command+, Command+/',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'cmd+, cmd+/',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['meta+,', 'meta+/'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Modifier only Meta+', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: true,
|
||||
keyCode: KeyCode.Meta,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: '⌘',
|
||||
ariaLabel: 'Command+',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'cmd+',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: [null, null],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('keyboardMapper - LINUX fallback', () => {
|
||||
|
||||
let mapper = new MacLinuxFallbackKeyboardMapper(OperatingSystem.Linux);
|
||||
|
||||
function _assertResolveKeybinding(k: number, expected: IResolvedKeybinding[]): void {
|
||||
assertResolveKeybinding(mapper, createKeybinding(k, OperatingSystem.Linux), expected);
|
||||
}
|
||||
|
||||
test('resolveKeybinding Ctrl+Z', () => {
|
||||
_assertResolveKeybinding(
|
||||
KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
[{
|
||||
label: 'Ctrl+Z',
|
||||
ariaLabel: 'Control+Z',
|
||||
electronAccelerator: 'Ctrl+Z',
|
||||
userSettingsLabel: 'ctrl+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Z', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+K Ctrl+=', () => {
|
||||
_assertResolveKeybinding(
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_EQUAL),
|
||||
[{
|
||||
label: 'Ctrl+K Ctrl+=',
|
||||
ariaLabel: 'Control+K Control+=',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+k ctrl+=',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+K', 'ctrl+='],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+Z', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.KEY_Z,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+Z',
|
||||
ariaLabel: 'Control+Z',
|
||||
electronAccelerator: 'Ctrl+Z',
|
||||
userSettingsLabel: 'ctrl+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Z', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(true, false, false, false, ScanCode.Comma),
|
||||
new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH),
|
||||
[{
|
||||
label: 'Ctrl+, Ctrl+/',
|
||||
ariaLabel: 'Control+, Control+/',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+, ctrl+/',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+,', 'ctrl+/'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Ctrl+[Comma]', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(true, false, false, false, ScanCode.Comma),
|
||||
null,
|
||||
[{
|
||||
label: 'Ctrl+,',
|
||||
ariaLabel: 'Control+,',
|
||||
electronAccelerator: 'Ctrl+,',
|
||||
userSettingsLabel: 'ctrl+,',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+,', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Modifier only Ctrl+', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.Ctrl,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+',
|
||||
ariaLabel: 'Control+',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: [null, null],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { KeyCode, SimpleKeybinding, ChordKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import extfs = require('vs/base/node/extfs');
|
||||
import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService, TestHashService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService, TestHashService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||
import uuid = require('vs/base/common/uuid');
|
||||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||
@@ -37,13 +37,14 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||
import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
|
||||
import { mkdirp } from 'vs/base/node/pfs';
|
||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
|
||||
interface Modifiers {
|
||||
metaKey?: boolean;
|
||||
@@ -53,6 +54,175 @@ interface Modifiers {
|
||||
}
|
||||
|
||||
suite('Keybindings Editing', () => {
|
||||
test('errors cases - parse errors', () => {
|
||||
|
||||
let instantiationService: TestInstantiationService;
|
||||
let testObject: KeybindingsEditingService;
|
||||
let testDir: string;
|
||||
let keybindingsFile: string;
|
||||
|
||||
setup(() => {
|
||||
return setUpWorkspace().then(() => {
|
||||
keybindingsFile = path.join(testDir, 'keybindings.json');
|
||||
|
||||
instantiationService = new TestInstantiationService();
|
||||
|
||||
instantiationService.stub(IEnvironmentService, { appKeybindingsPath: keybindingsFile });
|
||||
instantiationService.stub(IConfigurationService, ConfigurationService);
|
||||
instantiationService.stub(IConfigurationService, 'getValue', { 'eol': '\n' });
|
||||
instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { });
|
||||
instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { });
|
||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||
const lifecycleService = new TestLifecycleService();
|
||||
instantiationService.stub(ILifecycleService, lifecycleService);
|
||||
instantiationService.stub(IContextKeyService, <IContextKeyService>instantiationService.createInstance(MockContextKeyService));
|
||||
instantiationService.stub(IHashService, new TestHashService());
|
||||
instantiationService.stub(IEditorGroupService, new TestEditorGroupService());
|
||||
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
||||
instantiationService.stub(IModeService, ModeServiceImpl);
|
||||
instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl));
|
||||
instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, toWorkspaceFolders([{ path: testDir }]))), TestEnvironmentService, new TestTextResourceConfigurationService(), new TestConfigurationService(), lifecycleService, { disableWatcher: true }));
|
||||
instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService));
|
||||
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
|
||||
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
|
||||
instantiationService.stub(IBackupFileService, new TestBackupFileService());
|
||||
|
||||
testObject = instantiationService.createInstance(KeybindingsEditingService);
|
||||
});
|
||||
});
|
||||
|
||||
function setUpWorkspace(): TPromise<boolean> {
|
||||
testDir = path.join(os.tmpdir(), 'vsctests', uuid.generateUuid());
|
||||
return mkdirp(testDir, 493);
|
||||
}
|
||||
|
||||
teardown(() => {
|
||||
return new TPromise<void>((c, e) => {
|
||||
if (testDir) {
|
||||
extfs.del(testDir, os.tmpdir(), () => c(null), () => c(null));
|
||||
} else {
|
||||
c(null);
|
||||
}
|
||||
}).then(() => testDir = null);
|
||||
});
|
||||
|
||||
test('errors cases - parse errors', () => {
|
||||
fs.writeFileSync(keybindingsFile, ',,,,,,,,,,,,,,');
|
||||
return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }))
|
||||
.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 } }))
|
||||
.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 } }))
|
||||
.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 } }))
|
||||
.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.'));
|
||||
});
|
||||
|
||||
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' }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), expected));
|
||||
});
|
||||
|
||||
test('edit a default keybinding to a non existing keybindings file', () => {
|
||||
keybindingsFile = path.join(testDir, 'nonExistingFile.json');
|
||||
instantiationService.get(IEnvironmentService).appKeybindingsPath = keybindingsFile;
|
||||
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' }))
|
||||
.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' }))
|
||||
.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' }))
|
||||
.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' }))
|
||||
.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 }))
|
||||
.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 }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), expected));
|
||||
});
|
||||
|
||||
test('remove a default keybinding', () => {
|
||||
const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }];
|
||||
return testObject.removeKeybinding(aResolvedKeybindingItem({ command: 'a', firstPart: { keyCode: KeyCode.KEY_C, modifiers: { altKey: true } } }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), expected));
|
||||
});
|
||||
|
||||
test('remove a user keybinding', () => {
|
||||
writeToKeybindingsFile({ key: 'alt+c', command: 'b' });
|
||||
return testObject.removeKeybinding(aResolvedKeybindingItem({ command: 'b', firstPart: { keyCode: KeyCode.KEY_C, modifiers: { altKey: true } }, isDefault: false }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), []));
|
||||
});
|
||||
|
||||
test('reset an edited keybinding', () => {
|
||||
writeToKeybindingsFile({ key: 'alt+c', command: 'b' });
|
||||
return testObject.resetKeybinding(aResolvedKeybindingItem({ command: 'b', firstPart: { keyCode: KeyCode.KEY_C, modifiers: { altKey: true } }, isDefault: false }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), []));
|
||||
});
|
||||
|
||||
test('reset a removed keybinding', () => {
|
||||
writeToKeybindingsFile({ key: 'alt+c', command: '-b' });
|
||||
return testObject.resetKeybinding(aResolvedKeybindingItem({ command: 'b', isDefault: false }))
|
||||
.then(() => assert.deepEqual(getUserKeybindings(), []));
|
||||
});
|
||||
|
||||
function writeToKeybindingsFile(...keybindings: IUserFriendlyKeybinding[]) {
|
||||
fs.writeFileSync(keybindingsFile, JSON.stringify(keybindings || []));
|
||||
}
|
||||
|
||||
function getUserKeybindings(): IUserFriendlyKeybinding[] {
|
||||
return json.parse(fs.readFileSync(keybindingsFile).toString('utf8'));
|
||||
}
|
||||
|
||||
function aResolvedKeybindingItem({ command, when, isDefault, firstPart, chordPart }: { command?: string, when?: string, isDefault?: boolean, firstPart?: { keyCode: KeyCode, modifiers?: Modifiers }, chordPart?: { keyCode: KeyCode, modifiers?: Modifiers } }): ResolvedKeybindingItem {
|
||||
const aSimpleKeybinding = function (part: { keyCode: KeyCode, modifiers?: Modifiers }): SimpleKeybinding {
|
||||
const { ctrlKey, shiftKey, altKey, metaKey } = part.modifiers || { ctrlKey: false, shiftKey: false, altKey: false, metaKey: false };
|
||||
return new SimpleKeybinding(ctrlKey, shiftKey, altKey, metaKey, part.keyCode);
|
||||
};
|
||||
const keybinding = firstPart ? chordPart ? new ChordKeybinding(aSimpleKeybinding(firstPart), aSimpleKeybinding(chordPart)) : aSimpleKeybinding(firstPart) : null;
|
||||
return new ResolvedKeybindingItem(keybinding ? new USLayoutResolvedKeybinding(keybinding, OS) : null, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : null, isDefault === void 0 ? true : isDefault);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -14,8 +14,523 @@ import { ScanCodeBinding, ScanCode } from 'vs/workbench/services/keybinding/comm
|
||||
|
||||
const WRITE_FILE_IF_DIFFERENT = false;
|
||||
|
||||
function createKeyboardMapper(isUSStandard: boolean, file: string): TPromise<WindowsKeyboardMapper> {
|
||||
return readRawMapping<IWindowsKeyboardMapping>(file).then((rawMappings) => {
|
||||
return new WindowsKeyboardMapper(isUSStandard, rawMappings);
|
||||
});
|
||||
}
|
||||
|
||||
function _assertResolveKeybinding(mapper: WindowsKeyboardMapper, k: number, expected: IResolvedKeybinding[]): void {
|
||||
assertResolveKeybinding(mapper, createKeybinding(k, OperatingSystem.Windows), expected);
|
||||
}
|
||||
|
||||
suite('keyboardMapper - WINDOWS de_ch', () => {
|
||||
|
||||
let mapper: WindowsKeyboardMapper;
|
||||
|
||||
suiteSetup((done) => {
|
||||
createKeyboardMapper(false, 'win_de_ch').then((_mapper) => {
|
||||
mapper = _mapper;
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
test('mapping', (done) => {
|
||||
done();
|
||||
assertMapping(WRITE_FILE_IF_DIFFERENT, mapper, 'win_de_ch.txt', done);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+A', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.KEY_A,
|
||||
[{
|
||||
label: 'Ctrl+A',
|
||||
ariaLabel: 'Control+A',
|
||||
electronAccelerator: 'Ctrl+A',
|
||||
userSettingsLabel: 'ctrl+a',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+A', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+Z', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
[{
|
||||
label: 'Ctrl+Z',
|
||||
ariaLabel: 'Control+Z',
|
||||
electronAccelerator: 'Ctrl+Z',
|
||||
userSettingsLabel: 'ctrl+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Z', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+Z', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.KEY_Z,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+Z',
|
||||
ariaLabel: 'Control+Z',
|
||||
electronAccelerator: 'Ctrl+Z',
|
||||
userSettingsLabel: 'ctrl+z',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Z', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+]', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET,
|
||||
[{
|
||||
label: 'Ctrl+^',
|
||||
ariaLabel: 'Control+^',
|
||||
electronAccelerator: 'Ctrl+]',
|
||||
userSettingsLabel: 'ctrl+oem_6',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+]', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+]', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.US_CLOSE_SQUARE_BRACKET,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+^',
|
||||
ariaLabel: 'Control+^',
|
||||
electronAccelerator: 'Ctrl+]',
|
||||
userSettingsLabel: 'ctrl+oem_6',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+]', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Shift+]', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET,
|
||||
[{
|
||||
label: 'Shift+^',
|
||||
ariaLabel: 'Shift+^',
|
||||
electronAccelerator: 'Shift+]',
|
||||
userSettingsLabel: 'shift+oem_6',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['shift+]', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+/', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.US_SLASH,
|
||||
[{
|
||||
label: 'Ctrl+§',
|
||||
ariaLabel: 'Control+§',
|
||||
electronAccelerator: 'Ctrl+/',
|
||||
userSettingsLabel: 'ctrl+oem_2',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+/', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+Shift+/', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_SLASH,
|
||||
[{
|
||||
label: 'Ctrl+Shift+§',
|
||||
ariaLabel: 'Control+Shift+§',
|
||||
electronAccelerator: 'Ctrl+Shift+/',
|
||||
userSettingsLabel: 'ctrl+shift+oem_2',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+shift+/', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+K Ctrl+\\', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_BACKSLASH),
|
||||
[{
|
||||
label: 'Ctrl+K Ctrl+ä',
|
||||
ariaLabel: 'Control+K Control+ä',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+k ctrl+oem_5',
|
||||
isWYSIWYG: false,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+K', 'ctrl+\\'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+K Ctrl+=', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_EQUAL),
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+DownArrow', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.DownArrow,
|
||||
[{
|
||||
label: 'Ctrl+DownArrow',
|
||||
ariaLabel: 'Control+DownArrow',
|
||||
electronAccelerator: 'Ctrl+Down',
|
||||
userSettingsLabel: 'ctrl+down',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+DownArrow', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+NUMPAD_0', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.NUMPAD_0,
|
||||
[{
|
||||
label: 'Ctrl+NumPad0',
|
||||
ariaLabel: 'Control+NumPad0',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+numpad0',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+NumPad0', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+Home', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.Home,
|
||||
[{
|
||||
label: 'Ctrl+Home',
|
||||
ariaLabel: 'Control+Home',
|
||||
electronAccelerator: 'Ctrl+Home',
|
||||
userSettingsLabel: 'ctrl+home',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Home', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+Home', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.Home,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+Home',
|
||||
ariaLabel: 'Control+Home',
|
||||
electronAccelerator: 'Ctrl+Home',
|
||||
userSettingsLabel: 'ctrl+home',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+Home', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(true, false, false, false, ScanCode.Comma),
|
||||
new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH),
|
||||
[{
|
||||
label: 'Ctrl+, Ctrl+§',
|
||||
ariaLabel: 'Control+, Control+§',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+oem_comma ctrl+oem_2',
|
||||
isWYSIWYG: false,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+,', 'ctrl+/'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Modifier only Ctrl+', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.Ctrl,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+',
|
||||
ariaLabel: 'Control+',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: [null, null],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('keyboardMapper - WINDOWS en_us', () => {
|
||||
|
||||
let mapper: WindowsKeyboardMapper;
|
||||
|
||||
suiteSetup((done) => {
|
||||
createKeyboardMapper(true, 'win_en_us').then((_mapper) => {
|
||||
mapper = _mapper;
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
test('mapping', (done) => {
|
||||
assertMapping(WRITE_FILE_IF_DIFFERENT, mapper, 'win_en_us.txt', done);
|
||||
});
|
||||
|
||||
test('resolveKeybinding Ctrl+K Ctrl+\\', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_BACKSLASH),
|
||||
[{
|
||||
label: 'Ctrl+K Ctrl+\\',
|
||||
ariaLabel: 'Control+K Control+\\',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+k ctrl+\\',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+K', 'ctrl+\\'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Ctrl+[Comma] Ctrl+/', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(true, false, false, false, ScanCode.Comma),
|
||||
new SimpleKeybinding(true, false, false, false, KeyCode.US_SLASH),
|
||||
[{
|
||||
label: 'Ctrl+, Ctrl+/',
|
||||
ariaLabel: 'Control+, Control+/',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+, ctrl+/',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+,', 'ctrl+/'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveUserBinding Ctrl+[Comma]', () => {
|
||||
assertResolveUserBinding(
|
||||
mapper,
|
||||
new ScanCodeBinding(true, false, false, false, ScanCode.Comma),
|
||||
null,
|
||||
[{
|
||||
label: 'Ctrl+,',
|
||||
ariaLabel: 'Control+,',
|
||||
electronAccelerator: 'Ctrl+,',
|
||||
userSettingsLabel: 'ctrl+,',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+,', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Modifier only Ctrl+', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.Ctrl,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+',
|
||||
ariaLabel: 'Control+',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: [null, null],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('keyboardMapper - WINDOWS por_ptb', () => {
|
||||
|
||||
let mapper: WindowsKeyboardMapper;
|
||||
|
||||
suiteSetup((done) => {
|
||||
createKeyboardMapper(false, 'win_por_ptb').then((_mapper) => {
|
||||
mapper = _mapper;
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
test('mapping', (done) => {
|
||||
assertMapping(WRITE_FILE_IF_DIFFERENT, mapper, 'win_por_ptb.txt', done);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+[IntlRo]', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.ABNT_C1,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+/',
|
||||
ariaLabel: 'Control+/',
|
||||
electronAccelerator: 'Ctrl+ABNT_C1',
|
||||
userSettingsLabel: 'ctrl+abnt_c1',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+ABNT_C1', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('resolveKeyboardEvent Ctrl+[NumpadComma]', () => {
|
||||
assertResolveKeyboardEvent(
|
||||
mapper,
|
||||
{
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
metaKey: false,
|
||||
keyCode: KeyCode.ABNT_C2,
|
||||
code: null
|
||||
},
|
||||
{
|
||||
label: 'Ctrl+.',
|
||||
ariaLabel: 'Control+.',
|
||||
electronAccelerator: 'Ctrl+ABNT_C2',
|
||||
userSettingsLabel: 'ctrl+abnt_c2',
|
||||
isWYSIWYG: false,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+ABNT_C2', null],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('keyboardMapper - WINDOWS ru', () => {
|
||||
|
||||
let mapper: WindowsKeyboardMapper;
|
||||
|
||||
suiteSetup((done) => {
|
||||
createKeyboardMapper(false, 'win_ru').then((_mapper) => {
|
||||
mapper = _mapper;
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
test('mapping', (done) => {
|
||||
assertMapping(WRITE_FILE_IF_DIFFERENT, mapper, 'win_ru.txt', done);
|
||||
});
|
||||
|
||||
test('issue ##24361: resolveKeybinding Ctrl+K Ctrl+K', () => {
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K),
|
||||
[{
|
||||
label: 'Ctrl+K Ctrl+K',
|
||||
ariaLabel: 'Control+K Control+K',
|
||||
electronAccelerator: null,
|
||||
userSettingsLabel: 'ctrl+k ctrl+k',
|
||||
isWYSIWYG: true,
|
||||
isChord: true,
|
||||
dispatchParts: ['ctrl+K', 'ctrl+K'],
|
||||
}]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('keyboardMapper - misc', () => {
|
||||
test('issue #23513: Toggle Sidebar Visibility and Go to Line display same key mapping in Arabic keyboard', () => {
|
||||
const mapper = new WindowsKeyboardMapper(false, {
|
||||
'KeyB': {
|
||||
'vkey': 'VK_B',
|
||||
'value': 'لا',
|
||||
'withShift': 'لآ',
|
||||
'withAltGr': '',
|
||||
'withShiftAltGr': ''
|
||||
},
|
||||
'KeyG': {
|
||||
'vkey': 'VK_G',
|
||||
'value': 'ل',
|
||||
'withShift': 'لأ',
|
||||
'withAltGr': '',
|
||||
'withShiftAltGr': ''
|
||||
}
|
||||
});
|
||||
|
||||
_assertResolveKeybinding(
|
||||
mapper,
|
||||
KeyMod.CtrlCmd | KeyCode.KEY_B,
|
||||
[{
|
||||
label: 'Ctrl+B',
|
||||
ariaLabel: 'Control+B',
|
||||
electronAccelerator: 'Ctrl+B',
|
||||
userSettingsLabel: 'ctrl+b',
|
||||
isWYSIWYG: true,
|
||||
isChord: false,
|
||||
dispatchParts: ['ctrl+B', null],
|
||||
}]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user