Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { decodeKeybinding, createSimpleKeybinding, KeyCodeChord } from '../../../../base/common/keybindings.js';
8
import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
9
import { OS } from '../../../../base/common/platform.js';
10
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
11
import { ContextKeyExpr, ContextKeyExpression, IContext } from '../../../contextkey/common/contextkey.js';
12
import { KeybindingResolver, ResultKind } from '../../common/keybindingResolver.js';
13
import { ResolvedKeybindingItem } from '../../common/resolvedKeybindingItem.js';
14
import { USLayoutResolvedKeybinding } from '../../common/usLayoutResolvedKeybinding.js';
15
import { createUSLayoutResolvedKeybinding } from './keybindingsTestUtils.js';
16
17
function createContext(ctx: any) {
18
return {
19
getValue: (key: string) => {
20
return ctx[key];
21
}
22
};
23
}
24
25
suite('KeybindingResolver', () => {
26
27
ensureNoDisposablesAreLeakedInTestSuite();
28
29
function kbItem(keybinding: number | number[], command: string, commandArgs: any, when: ContextKeyExpression | undefined, isDefault: boolean): ResolvedKeybindingItem {
30
const resolvedKeybinding = createUSLayoutResolvedKeybinding(keybinding, OS);
31
return new ResolvedKeybindingItem(
32
resolvedKeybinding,
33
command,
34
commandArgs,
35
when,
36
isDefault,
37
null,
38
false
39
);
40
}
41
42
function getDispatchStr(chord: KeyCodeChord): string {
43
return USLayoutResolvedKeybinding.getDispatchStr(chord)!;
44
}
45
46
test('resolve key', () => {
47
const keybinding = KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ;
48
const runtimeKeybinding = createSimpleKeybinding(keybinding, OS);
49
const contextRules = ContextKeyExpr.equals('bar', 'baz');
50
const keybindingItem = kbItem(keybinding, 'yes', null, contextRules, true);
51
52
assert.strictEqual(contextRules.evaluate(createContext({ bar: 'baz' })), true);
53
assert.strictEqual(contextRules.evaluate(createContext({ bar: 'bz' })), false);
54
55
const resolver = new KeybindingResolver([keybindingItem], [], () => { });
56
57
const r1 = resolver.resolve(createContext({ bar: 'baz' }), [], getDispatchStr(runtimeKeybinding));
58
assert.ok(r1.kind === ResultKind.KbFound);
59
assert.strictEqual(r1.commandId, 'yes');
60
61
const r2 = resolver.resolve(createContext({ bar: 'bz' }), [], getDispatchStr(runtimeKeybinding));
62
assert.strictEqual(r2.kind, ResultKind.NoMatchingKb);
63
});
64
65
test('resolve key with arguments', () => {
66
const commandArgs = { text: 'no' };
67
const keybinding = KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ;
68
const runtimeKeybinding = createSimpleKeybinding(keybinding, OS);
69
const contextRules = ContextKeyExpr.equals('bar', 'baz');
70
const keybindingItem = kbItem(keybinding, 'yes', commandArgs, contextRules, true);
71
72
const resolver = new KeybindingResolver([keybindingItem], [], () => { });
73
74
const r = resolver.resolve(createContext({ bar: 'baz' }), [], getDispatchStr(runtimeKeybinding));
75
assert.ok(r.kind === ResultKind.KbFound);
76
assert.strictEqual(r.commandArgs, commandArgs);
77
});
78
79
suite('handle keybinding removals', () => {
80
81
test('simple 1', () => {
82
const defaults = [
83
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true)
84
];
85
const overrides = [
86
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false)
87
];
88
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
89
assert.deepStrictEqual(actual, [
90
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
91
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false),
92
]);
93
});
94
95
test('simple 2', () => {
96
const defaults = [
97
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
98
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
99
];
100
const overrides = [
101
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false)
102
];
103
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
104
assert.deepStrictEqual(actual, [
105
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
106
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true),
107
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false),
108
]);
109
});
110
111
test('removal with not matching when', () => {
112
const defaults = [
113
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
114
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
115
];
116
const overrides = [
117
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'b'), false)
118
];
119
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
120
assert.deepStrictEqual(actual, [
121
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
122
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
123
]);
124
});
125
126
test('removal with not matching keybinding', () => {
127
const defaults = [
128
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
129
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
130
];
131
const overrides = [
132
kbItem(KeyCode.KeyB, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
133
];
134
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
135
assert.deepStrictEqual(actual, [
136
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
137
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
138
]);
139
});
140
141
test('removal with matching keybinding and when', () => {
142
const defaults = [
143
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
144
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
145
];
146
const overrides = [
147
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
148
];
149
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
150
assert.deepStrictEqual(actual, [
151
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
152
]);
153
});
154
155
test('removal with unspecified keybinding', () => {
156
const defaults = [
157
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
158
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
159
];
160
const overrides = [
161
kbItem(0, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
162
];
163
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
164
assert.deepStrictEqual(actual, [
165
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
166
]);
167
});
168
169
test('removal with unspecified when', () => {
170
const defaults = [
171
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
172
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
173
];
174
const overrides = [
175
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
176
];
177
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
178
assert.deepStrictEqual(actual, [
179
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
180
]);
181
});
182
183
test('removal with unspecified when and unspecified keybinding', () => {
184
const defaults = [
185
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
186
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
187
];
188
const overrides = [
189
kbItem(0, '-yes1', null, undefined, false)
190
];
191
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
192
assert.deepStrictEqual(actual, [
193
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
194
]);
195
});
196
197
test('issue #138997 - removal in default list', () => {
198
const defaults = [
199
kbItem(KeyCode.KeyA, 'yes1', null, undefined, true),
200
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true),
201
kbItem(0, '-yes1', null, undefined, false)
202
];
203
const overrides: ResolvedKeybindingItem[] = [];
204
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
205
assert.deepStrictEqual(actual, [
206
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true)
207
]);
208
});
209
210
test('issue #612#issuecomment-222109084 cannot remove keybindings for commands with ^', () => {
211
const defaults = [
212
kbItem(KeyCode.KeyA, '^yes1', null, ContextKeyExpr.equals('1', 'a'), true),
213
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
214
];
215
const overrides = [
216
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
217
];
218
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
219
assert.deepStrictEqual(actual, [
220
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
221
]);
222
});
223
224
test('issue #140884 Unable to reassign F1 as keybinding for Show All Commands', () => {
225
const defaults = [
226
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
227
];
228
const overrides = [
229
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
230
kbItem(KeyCode.KeyA, 'command1', null, undefined, false),
231
];
232
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
233
assert.deepStrictEqual(actual, [
234
kbItem(KeyCode.KeyA, 'command1', null, undefined, false)
235
]);
236
});
237
238
test('issue #141638: Keyboard Shortcuts: Change When Expression might actually remove keybinding in Insiders', () => {
239
const defaults = [
240
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
241
];
242
const overrides = [
243
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false),
244
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
245
];
246
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
247
assert.deepStrictEqual(actual, [
248
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false)
249
]);
250
});
251
252
test('issue #157751: Auto-quoting of context keys prevents removal of keybindings via UI', () => {
253
const defaults = [
254
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != workbench.editor.notebook && editorLangId in julia.supportedLanguageIds`), true),
255
];
256
const overrides = [
257
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != 'workbench.editor.notebook' && editorLangId in 'julia.supportedLanguageIds'`), false),
258
];
259
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
260
assert.deepStrictEqual(actual, []);
261
});
262
263
test('issue #160604: Remove keybindings with when clause does not work', () => {
264
const defaults = [
265
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
266
];
267
const overrides = [
268
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.true(), false),
269
];
270
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
271
assert.deepStrictEqual(actual, []);
272
});
273
274
test('contextIsEntirelyIncluded', () => {
275
const toContextKeyExpression = (expr: ContextKeyExpression | string | null) => {
276
if (typeof expr === 'string' || !expr) {
277
return ContextKeyExpr.deserialize(expr);
278
}
279
return expr;
280
};
281
const assertIsIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
282
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), true);
283
};
284
const assertIsNotIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
285
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), false);
286
};
287
288
assertIsIncluded(null, null);
289
assertIsIncluded(null, ContextKeyExpr.true());
290
assertIsIncluded(ContextKeyExpr.true(), null);
291
assertIsIncluded(ContextKeyExpr.true(), ContextKeyExpr.true());
292
assertIsIncluded('key1', null);
293
assertIsIncluded('key1', '');
294
assertIsIncluded('key1', 'key1');
295
assertIsIncluded('key1', ContextKeyExpr.true());
296
assertIsIncluded('!key1', '');
297
assertIsIncluded('!key1', '!key1');
298
assertIsIncluded('key2', '');
299
assertIsIncluded('key2', 'key2');
300
assertIsIncluded('key1 && key1 && key2 && key2', 'key2');
301
assertIsIncluded('key1 && key2', 'key2');
302
assertIsIncluded('key1 && key2', 'key1');
303
assertIsIncluded('key1 && key2', '');
304
assertIsIncluded('key1', 'key1 || key2');
305
assertIsIncluded('key1 || !key1', 'key2 || !key2');
306
assertIsIncluded('key1', 'key1 || key2 && key3');
307
308
assertIsNotIncluded('key1', '!key1');
309
assertIsNotIncluded('!key1', 'key1');
310
assertIsNotIncluded('key1 && key2', 'key3');
311
assertIsNotIncluded('key1 && key2', 'key4');
312
assertIsNotIncluded('key1', 'key2');
313
assertIsNotIncluded('key1 || key2', 'key2');
314
assertIsNotIncluded('', 'key2');
315
assertIsNotIncluded(null, 'key2');
316
});
317
});
318
319
suite('resolve command', () => {
320
321
function _kbItem(keybinding: number | number[], command: string, when: ContextKeyExpression | undefined): ResolvedKeybindingItem {
322
return kbItem(keybinding, command, null, when, true);
323
}
324
325
const items = [
326
// This one will never match because its "when" is always overwritten by another one
327
_kbItem(
328
KeyCode.KeyX,
329
'first',
330
ContextKeyExpr.and(
331
ContextKeyExpr.equals('key1', true),
332
ContextKeyExpr.notEquals('key2', false)
333
)
334
),
335
// This one always overwrites first
336
_kbItem(
337
KeyCode.KeyX,
338
'second',
339
ContextKeyExpr.equals('key2', true)
340
),
341
// This one is a secondary mapping for `second`
342
_kbItem(
343
KeyCode.KeyZ,
344
'second',
345
undefined
346
),
347
// This one sometimes overwrites first
348
_kbItem(
349
KeyCode.KeyX,
350
'third',
351
ContextKeyExpr.equals('key3', true)
352
),
353
// This one is always overwritten by another one
354
_kbItem(
355
KeyMod.CtrlCmd | KeyCode.KeyY,
356
'fourth',
357
ContextKeyExpr.equals('key4', true)
358
),
359
// This one overwrites with a chord the previous one
360
_kbItem(
361
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ),
362
'fifth',
363
undefined
364
),
365
// This one has no keybinding
366
_kbItem(
367
0,
368
'sixth',
369
undefined
370
),
371
_kbItem(
372
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU),
373
'seventh',
374
undefined
375
),
376
_kbItem(
377
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK),
378
'seventh',
379
undefined
380
),
381
_kbItem(
382
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU),
383
'uncomment lines',
384
undefined
385
),
386
_kbItem(
387
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), // cmd+k cmd+c
388
'comment lines',
389
undefined
390
),
391
_kbItem(
392
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyG, KeyMod.CtrlCmd | KeyCode.KeyC), // cmd+g cmd+c
393
'unreachablechord',
394
undefined
395
),
396
_kbItem(
397
KeyMod.CtrlCmd | KeyCode.KeyG, // cmd+g
398
'eleven',
399
undefined
400
),
401
_kbItem(
402
[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB], // cmd+k a b
403
'long multi chord',
404
undefined
405
),
406
_kbItem(
407
[KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC], // cmd+b cmd+c
408
'shadowed by long-multi-chord-2',
409
undefined
410
),
411
_kbItem(
412
[KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC, KeyCode.KeyI], // cmd+b cmd+c i
413
'long-multi-chord-2',
414
undefined
415
)
416
];
417
418
const resolver = new KeybindingResolver(items, [], () => { });
419
420
const testKbLookupByCommand = (commandId: string, expectedKeys: number[] | number[][]) => {
421
// Test lookup
422
const lookupResult = resolver.lookupKeybindings(commandId);
423
assert.strictEqual(lookupResult.length, expectedKeys.length, 'Length mismatch @ commandId ' + commandId);
424
for (let i = 0, len = lookupResult.length; i < len; i++) {
425
const expected = createUSLayoutResolvedKeybinding(expectedKeys[i], OS)!;
426
427
assert.strictEqual(lookupResult[i].resolvedKeybinding!.getUserSettingsLabel(), expected.getUserSettingsLabel(), 'value mismatch @ commandId ' + commandId);
428
}
429
};
430
431
const testResolve = (ctx: IContext, _expectedKey: number | number[], commandId: string) => {
432
const expectedKeybinding = decodeKeybinding(_expectedKey, OS)!;
433
434
const previousChord: string[] = [];
435
436
for (let i = 0, len = expectedKeybinding.chords.length; i < len; i++) {
437
438
const chord = getDispatchStr(<KeyCodeChord>expectedKeybinding.chords[i]);
439
440
const result = resolver.resolve(ctx, previousChord, chord);
441
442
if (i === len - 1) {
443
// if it's the final chord, then we should find a valid command,
444
// and there should not be a chord.
445
assert.ok(result.kind === ResultKind.KbFound, `Enters multi chord for ${commandId} at chord ${i}`);
446
assert.strictEqual(result.commandId, commandId, `Enters multi chord for ${commandId} at chord ${i}`);
447
} else if (i > 0) {
448
// if this is an intermediate chord, we should not find a valid command,
449
// and there should be an open chord we continue.
450
assert.ok(result.kind === ResultKind.MoreChordsNeeded, `Continues multi chord for ${commandId} at chord ${i}`);
451
} else {
452
// if it's not the final chord and not an intermediate, then we should not
453
// find a valid command, and we should enter a chord.
454
assert.ok(result.kind === ResultKind.MoreChordsNeeded, `Enters multi chord for ${commandId} at chord ${i}`);
455
}
456
previousChord.push(chord);
457
}
458
};
459
460
test('resolve command - 1', () => {
461
testKbLookupByCommand('first', []);
462
});
463
464
test('resolve command - 2', () => {
465
testKbLookupByCommand('second', [KeyCode.KeyZ, KeyCode.KeyX]);
466
testResolve(createContext({ key2: true }), KeyCode.KeyX, 'second');
467
testResolve(createContext({}), KeyCode.KeyZ, 'second');
468
});
469
470
test('resolve command - 3', () => {
471
testKbLookupByCommand('third', [KeyCode.KeyX]);
472
testResolve(createContext({ key3: true }), KeyCode.KeyX, 'third');
473
});
474
475
test('resolve command - 4', () => {
476
testKbLookupByCommand('fourth', []);
477
});
478
479
test('resolve command - 5', () => {
480
testKbLookupByCommand('fifth', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ)]);
481
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ), 'fifth');
482
});
483
484
test('resolve command - 6', () => {
485
testKbLookupByCommand('seventh', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK)]);
486
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK), 'seventh');
487
});
488
489
test('resolve command - 7', () => {
490
testKbLookupByCommand('uncomment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU)]);
491
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU), 'uncomment lines');
492
});
493
494
test('resolve command - 8', () => {
495
testKbLookupByCommand('comment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC)]);
496
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), 'comment lines');
497
});
498
499
test('resolve command - 9', () => {
500
testKbLookupByCommand('unreachablechord', []);
501
});
502
503
test('resolve command - 10', () => {
504
testKbLookupByCommand('eleven', [KeyMod.CtrlCmd | KeyCode.KeyG]);
505
testResolve(createContext({}), KeyMod.CtrlCmd | KeyCode.KeyG, 'eleven');
506
});
507
508
test('resolve command - 11', () => {
509
testKbLookupByCommand('sixth', []);
510
});
511
512
test('resolve command - 12', () => {
513
testKbLookupByCommand('long multi chord', [[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB]]);
514
testResolve(createContext({}), [KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB], 'long multi chord');
515
});
516
517
const emptyContext = createContext({});
518
519
test('KBs having common prefix - the one defined later is returned', () => {
520
testResolve(emptyContext, [KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC, KeyCode.KeyI], 'long-multi-chord-2');
521
});
522
});
523
});
524
525