Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts
5237 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
import assert from 'assert';
6
import { KeyChord, KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
7
import { createSimpleKeybinding, ResolvedKeybinding, KeyCodeChord, Keybinding } from '../../../../base/common/keybindings.js';
8
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
9
import { OS } from '../../../../base/common/platform.js';
10
import Severity from '../../../../base/common/severity.js';
11
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
12
import { ICommandService } from '../../../commands/common/commands.js';
13
import { ContextKeyExpr, ContextKeyExpression, IContext, IContextKeyService, IContextKeyServiceTarget } from '../../../contextkey/common/contextkey.js';
14
import { AbstractKeybindingService } from '../../common/abstractKeybindingService.js';
15
import { IKeyboardEvent } from '../../common/keybinding.js';
16
import { KeybindingResolver } from '../../common/keybindingResolver.js';
17
import { ResolvedKeybindingItem } from '../../common/resolvedKeybindingItem.js';
18
import { USLayoutResolvedKeybinding } from '../../common/usLayoutResolvedKeybinding.js';
19
import { createUSLayoutResolvedKeybinding } from './keybindingsTestUtils.js';
20
import { NullLogService } from '../../../log/common/log.js';
21
import { INotification, INotificationService, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification } from '../../../notification/common/notification.js';
22
import { NullTelemetryService } from '../../../telemetry/common/telemetryUtils.js';
23
24
function createContext(ctx: any) {
25
return {
26
getValue: (key: string) => {
27
return ctx[key];
28
}
29
};
30
}
31
32
suite('AbstractKeybindingService', () => {
33
34
class TestKeybindingService extends AbstractKeybindingService {
35
private _resolver: KeybindingResolver;
36
37
constructor(
38
resolver: KeybindingResolver,
39
contextKeyService: IContextKeyService,
40
commandService: ICommandService,
41
notificationService: INotificationService
42
) {
43
super(contextKeyService, commandService, NullTelemetryService, notificationService, new NullLogService());
44
this._resolver = resolver;
45
}
46
47
protected _getResolver(): KeybindingResolver {
48
return this._resolver;
49
}
50
51
protected _documentHasFocus(): boolean {
52
return true;
53
}
54
55
public resolveKeybinding(kb: Keybinding): ResolvedKeybinding[] {
56
return USLayoutResolvedKeybinding.resolveKeybinding(kb, OS);
57
}
58
59
public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding {
60
const chord = new KeyCodeChord(
61
keyboardEvent.ctrlKey,
62
keyboardEvent.shiftKey,
63
keyboardEvent.altKey,
64
keyboardEvent.metaKey,
65
keyboardEvent.keyCode
66
).toKeybinding();
67
return this.resolveKeybinding(chord)[0];
68
}
69
70
public resolveUserBinding(userBinding: string): ResolvedKeybinding[] {
71
return [];
72
}
73
74
public testDispatch(kb: number): boolean {
75
const keybinding = createSimpleKeybinding(kb, OS);
76
return this._dispatch({
77
_standardKeyboardEventBrand: true,
78
ctrlKey: keybinding.ctrlKey,
79
shiftKey: keybinding.shiftKey,
80
altKey: keybinding.altKey,
81
metaKey: keybinding.metaKey,
82
altGraphKey: false,
83
keyCode: keybinding.keyCode,
84
code: null!
85
}, null!);
86
}
87
88
public _dumpDebugInfo(): string {
89
return '';
90
}
91
92
public _dumpDebugInfoJSON(): string {
93
return '';
94
}
95
96
public registerSchemaContribution(): IDisposable {
97
return Disposable.None;
98
}
99
100
public enableKeybindingHoldMode() {
101
return undefined;
102
}
103
}
104
105
let createTestKeybindingService: (items: ResolvedKeybindingItem[], contextValue?: any) => TestKeybindingService = null!;
106
let currentContextValue: IContext | null = null;
107
let executeCommandCalls: { commandId: string; args: unknown[] }[] = null!;
108
let showMessageCalls: { sev: Severity; message: any }[] = null!;
109
let statusMessageCalls: string[] | null = null;
110
let statusMessageCallsDisposed: string[] | null = null;
111
112
113
teardown(() => {
114
currentContextValue = null;
115
executeCommandCalls = null!;
116
showMessageCalls = null!;
117
createTestKeybindingService = null!;
118
statusMessageCalls = null;
119
statusMessageCallsDisposed = null;
120
});
121
122
ensureNoDisposablesAreLeakedInTestSuite();
123
124
setup(() => {
125
executeCommandCalls = [];
126
showMessageCalls = [];
127
statusMessageCalls = [];
128
statusMessageCallsDisposed = [];
129
130
createTestKeybindingService = (items: ResolvedKeybindingItem[]): TestKeybindingService => {
131
132
const contextKeyService: IContextKeyService = {
133
_serviceBrand: undefined,
134
onDidChangeContext: undefined!,
135
bufferChangeEvents() { },
136
createKey: undefined!,
137
contextMatchesRules: (rules: ContextKeyExpression | null | undefined) => {
138
if (!rules) {
139
return true;
140
}
141
if (!currentContextValue) {
142
return false;
143
}
144
return rules.evaluate(currentContextValue);
145
},
146
getContextKeyValue: undefined!,
147
createScoped: undefined!,
148
createOverlay: undefined!,
149
getContext: (target: IContextKeyServiceTarget): any => {
150
return currentContextValue;
151
},
152
updateParent: () => { }
153
};
154
155
const commandService: ICommandService = {
156
_serviceBrand: undefined,
157
onWillExecuteCommand: () => Disposable.None,
158
onDidExecuteCommand: () => Disposable.None,
159
executeCommand: (commandId: string, ...args: unknown[]): Promise<any> => {
160
executeCommandCalls.push({
161
commandId: commandId,
162
args: args
163
});
164
return Promise.resolve(undefined);
165
}
166
};
167
168
const notificationService: INotificationService = {
169
_serviceBrand: undefined,
170
onDidChangeFilter: undefined!,
171
notify: (notification: INotification) => {
172
showMessageCalls.push({ sev: notification.severity, message: notification.message });
173
return new NoOpNotification();
174
},
175
info: (message: any) => {
176
showMessageCalls.push({ sev: Severity.Info, message });
177
return new NoOpNotification();
178
},
179
warn: (message: any) => {
180
showMessageCalls.push({ sev: Severity.Warning, message });
181
return new NoOpNotification();
182
},
183
error: (message: any) => {
184
showMessageCalls.push({ sev: Severity.Error, message });
185
return new NoOpNotification();
186
},
187
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions) {
188
throw new Error('not implemented');
189
},
190
status(message: string, options?: IStatusMessageOptions) {
191
statusMessageCalls!.push(message);
192
return {
193
close: () => {
194
statusMessageCallsDisposed!.push(message);
195
}
196
};
197
},
198
setFilter() {
199
throw new Error('not implemented');
200
},
201
getFilter() {
202
throw new Error('not implemented');
203
},
204
getFilters() {
205
throw new Error('not implemented');
206
},
207
removeFilter() {
208
throw new Error('not implemented');
209
}
210
};
211
212
const resolver = new KeybindingResolver(items, [], () => { });
213
214
return new TestKeybindingService(resolver, contextKeyService, commandService, notificationService);
215
};
216
});
217
218
function kbItem(keybinding: number | number[], command: string | null, when?: ContextKeyExpression): ResolvedKeybindingItem {
219
return new ResolvedKeybindingItem(
220
createUSLayoutResolvedKeybinding(keybinding, OS),
221
command,
222
null,
223
when,
224
true,
225
null,
226
false
227
);
228
}
229
230
function toUsLabel(keybinding: number): string {
231
return createUSLayoutResolvedKeybinding(keybinding, OS)!.getLabel()!;
232
}
233
234
suite('simple tests: single- and multi-chord keybindings are dispatched', () => {
235
236
test('a single-chord keybinding is dispatched correctly; this test makes sure the dispatch in general works before we test empty-string/null command ID', () => {
237
238
const key = KeyMod.CtrlCmd | KeyCode.KeyK;
239
const kbService = createTestKeybindingService([
240
kbItem(key, 'myCommand'),
241
]);
242
243
currentContextValue = createContext({});
244
const shouldPreventDefault = kbService.testDispatch(key);
245
assert.deepStrictEqual(shouldPreventDefault, true);
246
assert.deepStrictEqual(executeCommandCalls, ([{ commandId: 'myCommand', args: [null] }]));
247
assert.deepStrictEqual(showMessageCalls, []);
248
assert.deepStrictEqual(statusMessageCalls, []);
249
assert.deepStrictEqual(statusMessageCallsDisposed, []);
250
251
kbService.dispose();
252
});
253
254
test('a multi-chord keybinding is dispatched correctly', () => {
255
256
const chord0 = KeyMod.CtrlCmd | KeyCode.KeyK;
257
const chord1 = KeyMod.CtrlCmd | KeyCode.KeyI;
258
const key = [chord0, chord1];
259
const kbService = createTestKeybindingService([
260
kbItem(key, 'myCommand'),
261
]);
262
263
currentContextValue = createContext({});
264
265
let shouldPreventDefault = kbService.testDispatch(chord0);
266
assert.deepStrictEqual(shouldPreventDefault, true);
267
assert.deepStrictEqual(executeCommandCalls, []);
268
assert.deepStrictEqual(showMessageCalls, []);
269
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
270
assert.deepStrictEqual(statusMessageCallsDisposed, []);
271
272
shouldPreventDefault = kbService.testDispatch(chord1);
273
assert.deepStrictEqual(shouldPreventDefault, true);
274
assert.deepStrictEqual(executeCommandCalls, ([{ commandId: 'myCommand', args: [null] }]));
275
assert.deepStrictEqual(showMessageCalls, []);
276
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
277
assert.deepStrictEqual(statusMessageCallsDisposed, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
278
279
kbService.dispose();
280
});
281
});
282
283
suite('keybindings with empty-string/null command ID', () => {
284
285
test('a single-chord keybinding with an empty string command ID unbinds the keybinding (shouldPreventDefault = false)', () => {
286
287
const kbService = createTestKeybindingService([
288
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
289
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, ''),
290
]);
291
292
// send Ctrl/Cmd + K
293
currentContextValue = createContext({});
294
const shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
295
assert.deepStrictEqual(shouldPreventDefault, false);
296
assert.deepStrictEqual(executeCommandCalls, []);
297
assert.deepStrictEqual(showMessageCalls, []);
298
assert.deepStrictEqual(statusMessageCalls, []);
299
assert.deepStrictEqual(statusMessageCallsDisposed, []);
300
301
kbService.dispose();
302
});
303
304
test('a single-chord keybinding with a null command ID unbinds the keybinding (shouldPreventDefault = false)', () => {
305
306
const kbService = createTestKeybindingService([
307
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
308
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, null),
309
]);
310
311
// send Ctrl/Cmd + K
312
currentContextValue = createContext({});
313
const shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
314
assert.deepStrictEqual(shouldPreventDefault, false);
315
assert.deepStrictEqual(executeCommandCalls, []);
316
assert.deepStrictEqual(showMessageCalls, []);
317
assert.deepStrictEqual(statusMessageCalls, []);
318
assert.deepStrictEqual(statusMessageCallsDisposed, []);
319
320
kbService.dispose();
321
});
322
323
test('a multi-chord keybinding with an empty-string command ID keeps the keybinding (shouldPreventDefault = true)', () => {
324
325
const chord0 = KeyMod.CtrlCmd | KeyCode.KeyK;
326
const chord1 = KeyMod.CtrlCmd | KeyCode.KeyI;
327
const key = [chord0, chord1];
328
const kbService = createTestKeybindingService([
329
kbItem(key, 'myCommand'),
330
kbItem(key, ''),
331
]);
332
333
currentContextValue = createContext({});
334
335
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
336
assert.deepStrictEqual(shouldPreventDefault, true);
337
assert.deepStrictEqual(executeCommandCalls, []);
338
assert.deepStrictEqual(showMessageCalls, []);
339
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
340
assert.deepStrictEqual(statusMessageCallsDisposed, []);
341
342
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyI);
343
assert.deepStrictEqual(shouldPreventDefault, true);
344
assert.deepStrictEqual(executeCommandCalls, []);
345
assert.deepStrictEqual(showMessageCalls, []);
346
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`, `The key combination (${toUsLabel(chord0)}, ${toUsLabel(chord1)}) is not a command.`]));
347
assert.deepStrictEqual(statusMessageCallsDisposed, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
348
349
kbService.dispose();
350
});
351
352
test('a multi-chord keybinding with a null command ID keeps the keybinding (shouldPreventDefault = true)', () => {
353
354
const chord0 = KeyMod.CtrlCmd | KeyCode.KeyK;
355
const chord1 = KeyMod.CtrlCmd | KeyCode.KeyI;
356
const key = [chord0, chord1];
357
const kbService = createTestKeybindingService([
358
kbItem(key, 'myCommand'),
359
kbItem(key, null),
360
]);
361
362
currentContextValue = createContext({});
363
364
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
365
assert.deepStrictEqual(shouldPreventDefault, true);
366
assert.deepStrictEqual(executeCommandCalls, []);
367
assert.deepStrictEqual(showMessageCalls, []);
368
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
369
assert.deepStrictEqual(statusMessageCallsDisposed, []);
370
371
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyI);
372
assert.deepStrictEqual(shouldPreventDefault, true);
373
assert.deepStrictEqual(executeCommandCalls, []);
374
assert.deepStrictEqual(showMessageCalls, []);
375
assert.deepStrictEqual(statusMessageCalls, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`, `The key combination (${toUsLabel(chord0)}, ${toUsLabel(chord1)}) is not a command.`]));
376
assert.deepStrictEqual(statusMessageCallsDisposed, ([`(${toUsLabel(chord0)}) was pressed. Waiting for second key of chord...`]));
377
378
kbService.dispose();
379
});
380
381
});
382
383
test('issue #16498: chord mode is quit for invalid chords', () => {
384
385
const kbService = createTestKeybindingService([
386
kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyX), 'chordCommand'),
387
kbItem(KeyCode.Backspace, 'simpleCommand'),
388
]);
389
390
// send Ctrl/Cmd + K
391
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
392
assert.strictEqual(shouldPreventDefault, true);
393
assert.deepStrictEqual(executeCommandCalls, []);
394
assert.deepStrictEqual(showMessageCalls, []);
395
assert.deepStrictEqual(statusMessageCalls, [
396
`(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK)}) was pressed. Waiting for second key of chord...`
397
]);
398
assert.deepStrictEqual(statusMessageCallsDisposed, []);
399
executeCommandCalls = [];
400
showMessageCalls = [];
401
statusMessageCalls = [];
402
statusMessageCallsDisposed = [];
403
404
// send backspace
405
shouldPreventDefault = kbService.testDispatch(KeyCode.Backspace);
406
assert.strictEqual(shouldPreventDefault, true);
407
assert.deepStrictEqual(executeCommandCalls, []);
408
assert.deepStrictEqual(showMessageCalls, []);
409
assert.deepStrictEqual(statusMessageCalls, [
410
`The key combination (${toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK)}, ${toUsLabel(KeyCode.Backspace)}) is not a command.`
411
]);
412
assert.deepStrictEqual(statusMessageCallsDisposed, [
413
`(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK)}) was pressed. Waiting for second key of chord...`
414
]);
415
executeCommandCalls = [];
416
showMessageCalls = [];
417
statusMessageCalls = [];
418
statusMessageCallsDisposed = [];
419
420
// send backspace
421
shouldPreventDefault = kbService.testDispatch(KeyCode.Backspace);
422
assert.strictEqual(shouldPreventDefault, true);
423
assert.deepStrictEqual(executeCommandCalls, [{
424
commandId: 'simpleCommand',
425
args: [null]
426
}]);
427
assert.deepStrictEqual(showMessageCalls, []);
428
assert.deepStrictEqual(statusMessageCalls, []);
429
assert.deepStrictEqual(statusMessageCallsDisposed, []);
430
executeCommandCalls = [];
431
showMessageCalls = [];
432
statusMessageCalls = [];
433
statusMessageCallsDisposed = [];
434
435
kbService.dispose();
436
});
437
438
test('issue #16833: Keybinding service should not testDispatch on modifier keys', () => {
439
440
const kbService = createTestKeybindingService([
441
kbItem(KeyCode.Ctrl, 'nope'),
442
kbItem(KeyCode.Meta, 'nope'),
443
kbItem(KeyCode.Alt, 'nope'),
444
kbItem(KeyCode.Shift, 'nope'),
445
446
kbItem(KeyMod.CtrlCmd, 'nope'),
447
kbItem(KeyMod.WinCtrl, 'nope'),
448
kbItem(KeyMod.Alt, 'nope'),
449
kbItem(KeyMod.Shift, 'nope'),
450
]);
451
452
function assertIsIgnored(keybinding: number): void {
453
const shouldPreventDefault = kbService.testDispatch(keybinding);
454
assert.strictEqual(shouldPreventDefault, false);
455
assert.deepStrictEqual(executeCommandCalls, []);
456
assert.deepStrictEqual(showMessageCalls, []);
457
assert.deepStrictEqual(statusMessageCalls, []);
458
assert.deepStrictEqual(statusMessageCallsDisposed, []);
459
executeCommandCalls = [];
460
showMessageCalls = [];
461
statusMessageCalls = [];
462
statusMessageCallsDisposed = [];
463
}
464
465
assertIsIgnored(KeyCode.Ctrl);
466
assertIsIgnored(KeyCode.Meta);
467
assertIsIgnored(KeyCode.Alt);
468
assertIsIgnored(KeyCode.Shift);
469
470
assertIsIgnored(KeyMod.CtrlCmd);
471
assertIsIgnored(KeyMod.WinCtrl);
472
assertIsIgnored(KeyMod.Alt);
473
assertIsIgnored(KeyMod.Shift);
474
475
kbService.dispose();
476
});
477
478
test('can trigger command that is sharing keybinding with chord', () => {
479
480
const kbService = createTestKeybindingService([
481
kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyX), 'chordCommand'),
482
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'simpleCommand', ContextKeyExpr.has('key1')),
483
]);
484
485
486
// send Ctrl/Cmd + K
487
currentContextValue = createContext({
488
key1: true
489
});
490
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
491
assert.strictEqual(shouldPreventDefault, true);
492
assert.deepStrictEqual(executeCommandCalls, [{
493
commandId: 'simpleCommand',
494
args: [null]
495
}]);
496
assert.deepStrictEqual(showMessageCalls, []);
497
assert.deepStrictEqual(statusMessageCalls, []);
498
assert.deepStrictEqual(statusMessageCallsDisposed, []);
499
executeCommandCalls = [];
500
showMessageCalls = [];
501
statusMessageCalls = [];
502
statusMessageCallsDisposed = [];
503
504
// send Ctrl/Cmd + K
505
currentContextValue = createContext({});
506
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
507
assert.strictEqual(shouldPreventDefault, true);
508
assert.deepStrictEqual(executeCommandCalls, []);
509
assert.deepStrictEqual(showMessageCalls, []);
510
assert.deepStrictEqual(statusMessageCalls, [
511
`(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK)}) was pressed. Waiting for second key of chord...`
512
]);
513
assert.deepStrictEqual(statusMessageCallsDisposed, []);
514
executeCommandCalls = [];
515
showMessageCalls = [];
516
statusMessageCalls = [];
517
statusMessageCallsDisposed = [];
518
519
// send Ctrl/Cmd + X
520
currentContextValue = createContext({});
521
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyX);
522
assert.strictEqual(shouldPreventDefault, true);
523
assert.deepStrictEqual(executeCommandCalls, [{
524
commandId: 'chordCommand',
525
args: [null]
526
}]);
527
assert.deepStrictEqual(showMessageCalls, []);
528
assert.deepStrictEqual(statusMessageCalls, []);
529
assert.deepStrictEqual(statusMessageCallsDisposed, [
530
`(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK)}) was pressed. Waiting for second key of chord...`
531
]);
532
executeCommandCalls = [];
533
showMessageCalls = [];
534
statusMessageCalls = [];
535
statusMessageCallsDisposed = [];
536
537
kbService.dispose();
538
});
539
540
test('cannot trigger chord if command is overwriting', () => {
541
542
const kbService = createTestKeybindingService([
543
kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyX), 'chordCommand', ContextKeyExpr.has('key1')),
544
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'simpleCommand'),
545
]);
546
547
548
// send Ctrl/Cmd + K
549
currentContextValue = createContext({});
550
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
551
assert.strictEqual(shouldPreventDefault, true);
552
assert.deepStrictEqual(executeCommandCalls, [{
553
commandId: 'simpleCommand',
554
args: [null]
555
}]);
556
assert.deepStrictEqual(showMessageCalls, []);
557
assert.deepStrictEqual(statusMessageCalls, []);
558
assert.deepStrictEqual(statusMessageCallsDisposed, []);
559
executeCommandCalls = [];
560
showMessageCalls = [];
561
statusMessageCalls = [];
562
statusMessageCallsDisposed = [];
563
564
// send Ctrl/Cmd + K
565
currentContextValue = createContext({
566
key1: true
567
});
568
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
569
assert.strictEqual(shouldPreventDefault, true);
570
assert.deepStrictEqual(executeCommandCalls, [{
571
commandId: 'simpleCommand',
572
args: [null]
573
}]);
574
assert.deepStrictEqual(showMessageCalls, []);
575
assert.deepStrictEqual(statusMessageCalls, []);
576
assert.deepStrictEqual(statusMessageCallsDisposed, []);
577
executeCommandCalls = [];
578
showMessageCalls = [];
579
statusMessageCalls = [];
580
statusMessageCallsDisposed = [];
581
582
// send Ctrl/Cmd + X
583
currentContextValue = createContext({
584
key1: true
585
});
586
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyX);
587
assert.strictEqual(shouldPreventDefault, false);
588
assert.deepStrictEqual(executeCommandCalls, []);
589
assert.deepStrictEqual(showMessageCalls, []);
590
assert.deepStrictEqual(statusMessageCalls, []);
591
assert.deepStrictEqual(statusMessageCallsDisposed, []);
592
executeCommandCalls = [];
593
showMessageCalls = [];
594
statusMessageCalls = [];
595
statusMessageCallsDisposed = [];
596
597
kbService.dispose();
598
});
599
600
test('can have spying command', () => {
601
602
const kbService = createTestKeybindingService([
603
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, '^simpleCommand'),
604
]);
605
606
// send Ctrl/Cmd + K
607
currentContextValue = createContext({});
608
const shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KeyK);
609
assert.strictEqual(shouldPreventDefault, false);
610
assert.deepStrictEqual(executeCommandCalls, [{
611
commandId: 'simpleCommand',
612
args: [null]
613
}]);
614
assert.deepStrictEqual(showMessageCalls, []);
615
assert.deepStrictEqual(statusMessageCalls, []);
616
assert.deepStrictEqual(statusMessageCallsDisposed, []);
617
executeCommandCalls = [];
618
showMessageCalls = [];
619
statusMessageCalls = [];
620
statusMessageCallsDisposed = [];
621
622
kbService.dispose();
623
});
624
625
suite('appendKeybinding', () => {
626
test('appends keybinding label when command has a keybinding', () => {
627
const kbService = createTestKeybindingService([
628
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
629
]);
630
631
const result = kbService.appendKeybinding('My Label', 'myCommand');
632
const expectedLabel = toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK);
633
assert.strictEqual(result, `My Label (${expectedLabel})`);
634
635
kbService.dispose();
636
});
637
638
test('returns only label when command has no keybinding', () => {
639
const kbService = createTestKeybindingService([]);
640
641
const result = kbService.appendKeybinding('My Label', 'myCommand');
642
assert.strictEqual(result, 'My Label');
643
644
kbService.dispose();
645
});
646
647
test('returns only label when commandId is null', () => {
648
const kbService = createTestKeybindingService([
649
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
650
]);
651
652
const result = kbService.appendKeybinding('My Label', null);
653
assert.strictEqual(result, 'My Label');
654
655
kbService.dispose();
656
});
657
658
test('returns only label when commandId is undefined', () => {
659
const kbService = createTestKeybindingService([
660
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
661
]);
662
663
const result = kbService.appendKeybinding('My Label', undefined);
664
assert.strictEqual(result, 'My Label');
665
666
kbService.dispose();
667
});
668
669
test('returns only label when commandId is empty string', () => {
670
const kbService = createTestKeybindingService([
671
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
672
]);
673
674
const result = kbService.appendKeybinding('My Label', '');
675
assert.strictEqual(result, 'My Label');
676
677
kbService.dispose();
678
});
679
680
test('appends keybinding for command with context when context matches', () => {
681
const kbService = createTestKeybindingService([
682
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand', ContextKeyExpr.has('key1')),
683
]);
684
685
currentContextValue = createContext({ key1: true });
686
const result = kbService.appendKeybinding('My Label', 'myCommand');
687
const expectedLabel = toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK);
688
assert.strictEqual(result, `My Label (${expectedLabel})`);
689
690
kbService.dispose();
691
});
692
693
test('returns only label when context does not match and enforceContextCheck is true', () => {
694
const kbService = createTestKeybindingService([
695
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand', ContextKeyExpr.has('key1')),
696
]);
697
698
currentContextValue = createContext({});
699
const result = kbService.appendKeybinding('My Label', 'myCommand', undefined, true);
700
assert.strictEqual(result, 'My Label');
701
702
kbService.dispose();
703
});
704
705
test('appends keybinding when context does not match but enforceContextCheck is false', () => {
706
const kbService = createTestKeybindingService([
707
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand', ContextKeyExpr.has('key1')),
708
]);
709
710
currentContextValue = createContext({});
711
const result = kbService.appendKeybinding('My Label', 'myCommand', undefined, false);
712
const expectedLabel = toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK);
713
assert.strictEqual(result, `My Label (${expectedLabel})`);
714
715
kbService.dispose();
716
});
717
718
test('appends keybinding even when label is empty string', () => {
719
const kbService = createTestKeybindingService([
720
kbItem(KeyMod.CtrlCmd | KeyCode.KeyK, 'myCommand'),
721
]);
722
723
const result = kbService.appendKeybinding('', 'myCommand');
724
const expectedLabel = toUsLabel(KeyMod.CtrlCmd | KeyCode.KeyK);
725
assert.strictEqual(result, ` (${expectedLabel})`);
726
727
kbService.dispose();
728
});
729
});
730
});
731
732