UNPKG

22.2 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2017 Ericsson and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16// *****************************************************************************
17Object.defineProperty(exports, "__esModule", { value: true });
18const tslib_1 = require("tslib");
19const jsdom_1 = require("./test/jsdom");
20let disableJSDOM = (0, jsdom_1.enableJSDOM)();
21const frontend_application_config_provider_1 = require("./frontend-application-config-provider");
22frontend_application_config_provider_1.FrontendApplicationConfigProvider.set({});
23const inversify_1 = require("inversify");
24const contribution_provider_1 = require("../common/contribution-provider");
25const keyboard_layout_provider_1 = require("../common/keyboard/keyboard-layout-provider");
26const logger_1 = require("../common/logger");
27const keybinding_1 = require("./keybinding");
28const keys_1 = require("./keyboard/keys");
29const keyboard_layout_service_1 = require("./keyboard/keyboard-layout-service");
30const command_1 = require("../common/command");
31const label_parser_1 = require("./label-parser");
32const mock_logger_1 = require("../common/test/mock-logger");
33const frontend_application_state_1 = require("./frontend-application-state");
34const context_key_service_1 = require("./context-key-service");
35const core_preferences_1 = require("./core-preferences");
36const os = require("../common/os");
37const chai = require("chai");
38const sinon = require("sinon");
39const event_1 = require("../common/event");
40const frontend_application_bindings_1 = require("./frontend-application-bindings");
41const markdown_renderer_1 = require("./markdown-rendering/markdown-renderer");
42const status_bar_1 = require("./status-bar");
43disableJSDOM();
44const expect = chai.expect;
45let keybindingRegistry;
46let commandRegistry;
47let testContainer;
48let stub;
49before(async () => {
50 disableJSDOM = (0, jsdom_1.enableJSDOM)();
51 testContainer = new inversify_1.Container();
52 const module = new inversify_1.ContainerModule((bind, unbind, isBound, rebind) => {
53 /* Mock logger binding*/
54 bind(logger_1.ILogger).to(mock_logger_1.MockLogger);
55 bind(keyboard_layout_service_1.KeyboardLayoutService).toSelf().inSingletonScope();
56 bind(MockKeyboardLayoutProvider).toSelf().inSingletonScope();
57 bind(keyboard_layout_provider_1.KeyboardLayoutProvider).toService(MockKeyboardLayoutProvider);
58 bind(MockKeyboardLayoutChangeNotifier).toSelf().inSingletonScope();
59 bind(keyboard_layout_provider_1.KeyboardLayoutChangeNotifier).toService(MockKeyboardLayoutChangeNotifier);
60 (0, contribution_provider_1.bindContributionProvider)(bind, keybinding_1.KeybindingContext);
61 bind(command_1.CommandRegistry).toSelf().inSingletonScope();
62 (0, contribution_provider_1.bindContributionProvider)(bind, command_1.CommandContribution);
63 bind(keybinding_1.KeybindingRegistry).toSelf();
64 (0, contribution_provider_1.bindContributionProvider)(bind, keybinding_1.KeybindingContribution);
65 bind(TestContribution).toSelf().inSingletonScope();
66 [command_1.CommandContribution, keybinding_1.KeybindingContribution].forEach(serviceIdentifier => bind(serviceIdentifier).toService(TestContribution));
67 bind(keybinding_1.KeybindingContext).toConstantValue({
68 id: 'testContext',
69 isEnabled(arg) {
70 return true;
71 }
72 });
73 bind(status_bar_1.StatusBar).toConstantValue({});
74 bind(markdown_renderer_1.MarkdownRendererImpl).toSelf().inSingletonScope();
75 bind(markdown_renderer_1.MarkdownRenderer).toService(markdown_renderer_1.MarkdownRendererImpl);
76 bind(markdown_renderer_1.MarkdownRendererFactory).toFactory(({ container }) => container.get(markdown_renderer_1.MarkdownRenderer));
77 bind(command_1.CommandService).toService(command_1.CommandRegistry);
78 bind(label_parser_1.LabelParser).toSelf().inSingletonScope();
79 bind(context_key_service_1.ContextKeyService).to(context_key_service_1.ContextKeyServiceDummyImpl).inSingletonScope();
80 bind(frontend_application_state_1.FrontendApplicationStateService).toSelf().inSingletonScope();
81 bind(core_preferences_1.CorePreferences).toConstantValue({});
82 (0, frontend_application_bindings_1.bindPreferenceService)(bind);
83 });
84 testContainer.load(module);
85 commandRegistry = testContainer.get(command_1.CommandRegistry);
86 commandRegistry.onStart();
87});
88after(() => {
89 disableJSDOM();
90});
91beforeEach(async () => {
92 stub = sinon.stub(os, 'isOSX').value(false);
93 keybindingRegistry = testContainer.get(keybinding_1.KeybindingRegistry);
94 await keybindingRegistry.onStart();
95});
96afterEach(() => {
97 stub.restore();
98});
99describe('keybindings', () => {
100 it('should register the default keybindings', () => {
101 const keybinding = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
102 expect(keybinding).is.not.undefined;
103 const keybinding2 = keybindingRegistry.getKeybindingsForCommand('undefined.command');
104 expect(keybinding2.length).is.equal(0);
105 });
106 it('should set a keymap', () => {
107 const keybindings = [{
108 command: TEST_COMMAND.id,
109 keybinding: 'ctrl+c'
110 }];
111 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindings);
112 const bindings = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
113 if (bindings) {
114 const keyCode = keys_1.KeyCode.parse(bindings[0].keybinding);
115 expect(keyCode.key).to.be.equal(keys_1.Key.KEY_C);
116 expect(keyCode.ctrl).to.be.true;
117 }
118 });
119 it('should reset to default in case of invalid keybinding', () => {
120 const keybindings = [{
121 command: TEST_COMMAND.id,
122 keybinding: 'ctrl+invalid'
123 }];
124 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindings);
125 const bindings = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
126 if (bindings) {
127 const keyCode = keys_1.KeyCode.parse(bindings[0].keybinding);
128 expect(keyCode.key).to.be.equal(keys_1.Key.KEY_A);
129 expect(keyCode.ctrl).to.be.true;
130 }
131 });
132 it('should remove all disabled keybindings from a command that has multiple keybindings', () => {
133 const keybindings = [{
134 command: TEST_COMMAND2.id,
135 keybinding: 'F3'
136 },
137 {
138 command: '-' + TEST_COMMAND2.id,
139 context: 'testContext',
140 keybinding: 'ctrl+f1'
141 },
142 ];
143 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindings);
144 const bindings = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND2.id);
145 if (bindings) {
146 // a USER one and a DEFAULT one
147 expect(bindings.length).to.be.equal(2);
148 const keyCode = keys_1.KeyCode.parse(bindings[0].keybinding);
149 expect(keyCode.key).to.be.equal(keys_1.Key.F3);
150 expect(keyCode.ctrl).to.be.false;
151 const keyCode2 = keys_1.KeyCode.parse(bindings[1].keybinding);
152 expect(keyCode2.key).to.be.equal(keys_1.Key.F2);
153 expect(keyCode2.ctrl).to.be.true;
154 }
155 });
156 it('should register a keybinding', () => {
157 const keybinding = {
158 command: TEST_COMMAND2.id,
159 keybinding: 'F5'
160 };
161 expect(isKeyBindingRegistered(keybinding)).to.be.false;
162 keybindingRegistry.registerKeybinding(keybinding);
163 expect(isKeyBindingRegistered(keybinding)).to.be.true;
164 });
165 it('should unregister all keybindings from a specific command', () => {
166 const otherKeybinding = {
167 command: TEST_COMMAND.id,
168 keybinding: 'F4'
169 };
170 keybindingRegistry.registerKeybinding(otherKeybinding);
171 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
172 const keybinding = {
173 command: TEST_COMMAND2.id,
174 keybinding: 'F5'
175 };
176 const keybinding2 = {
177 command: TEST_COMMAND2.id,
178 keybinding: 'F6'
179 };
180 keybindingRegistry.registerKeybinding(keybinding);
181 keybindingRegistry.registerKeybinding(keybinding2);
182 expect(isKeyBindingRegistered(keybinding)).to.be.true;
183 expect(isKeyBindingRegistered(keybinding2)).to.be.true;
184 keybindingRegistry.unregisterKeybinding(TEST_COMMAND2);
185 expect(isKeyBindingRegistered(keybinding)).to.be.false;
186 expect(isKeyBindingRegistered(keybinding2)).to.be.false;
187 const bindingsAfterUnregister = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND2.id);
188 expect(bindingsAfterUnregister).not.to.be.undefined;
189 expect(bindingsAfterUnregister.length).to.be.equal(0);
190 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
191 });
192 it('should unregister a specific keybinding', () => {
193 const otherKeybinding = {
194 command: TEST_COMMAND2.id,
195 keybinding: 'F4'
196 };
197 keybindingRegistry.registerKeybinding(otherKeybinding);
198 const keybinding = {
199 command: TEST_COMMAND2.id,
200 keybinding: 'F5'
201 };
202 keybindingRegistry.registerKeybinding(keybinding);
203 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
204 expect(isKeyBindingRegistered(keybinding)).to.be.true;
205 keybindingRegistry.unregisterKeybinding(keybinding);
206 expect(isKeyBindingRegistered(keybinding)).to.be.false;
207 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
208 });
209 it('should unregister a specific key', () => {
210 const otherKeybinding = {
211 command: TEST_COMMAND.id,
212 keybinding: 'F4'
213 };
214 keybindingRegistry.registerKeybinding(otherKeybinding);
215 const testKey = 'F5';
216 const keybinding = {
217 command: TEST_COMMAND2.id,
218 keybinding: testKey
219 };
220 const keybinding2 = {
221 command: TEST_COMMAND.id,
222 keybinding: testKey
223 };
224 keybindingRegistry.registerKeybinding(keybinding);
225 keybindingRegistry.registerKeybinding(keybinding2);
226 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
227 expect(isKeyBindingRegistered(keybinding)).to.be.true;
228 expect(isKeyBindingRegistered(keybinding2)).to.be.true;
229 keybindingRegistry.unregisterKeybinding(testKey);
230 expect(isKeyBindingRegistered(otherKeybinding)).to.be.true;
231 expect(isKeyBindingRegistered(keybinding)).to.be.false;
232 expect(isKeyBindingRegistered(keybinding2)).to.be.false;
233 });
234 it('should register a correct keybinding, then default back to the original for a wrong one after', () => {
235 let keybindings = [{
236 command: TEST_COMMAND.id,
237 keybinding: 'ctrl+c'
238 }];
239 // Get default binding
240 const keystroke = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
241 // Set correct new binding
242 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindings);
243 const bindings = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
244 if (bindings) {
245 const keyCode = keys_1.KeyCode.parse(bindings[0].keybinding);
246 expect(keyCode.key).to.be.equal(keys_1.Key.KEY_C);
247 expect(keyCode.ctrl).to.be.true;
248 }
249 // Set invalid binding
250 keybindings = [{
251 command: TEST_COMMAND.id,
252 keybinding: 'ControlLeft+Invalid'
253 }];
254 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindings);
255 const defaultBindings = keybindingRegistry.getKeybindingsForCommand(TEST_COMMAND.id);
256 if (defaultBindings) {
257 if (keystroke) {
258 const keyCode = keys_1.KeyCode.parse(defaultBindings[0].keybinding);
259 const keyStrokeCode = keys_1.KeyCode.parse(keystroke[0].keybinding);
260 expect(keyCode.key).to.be.equal(keyStrokeCode.key);
261 }
262 }
263 });
264 it('should only return the more specific keybindings when a keystroke is entered', () => {
265 const keybindingsUser = [{
266 command: TEST_COMMAND.id,
267 keybinding: 'ctrl+b'
268 }];
269 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindingsUser);
270 const keybindingsSpecific = [{
271 command: TEST_COMMAND.id,
272 keybinding: 'ctrl+c'
273 }];
274 const validKeyCode = keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_C, modifiers: [keys_1.KeyModifier.CtrlCmd] });
275 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.WORKSPACE, keybindingsSpecific);
276 let match = keybindingRegistry.matchKeybinding([keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_A, modifiers: [keys_1.KeyModifier.CtrlCmd] })]);
277 expect(match && match.kind).to.be.equal('full');
278 match = keybindingRegistry.matchKeybinding([keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_B, modifiers: [keys_1.KeyModifier.CtrlCmd] })]);
279 expect(match && match.kind).to.be.equal('full');
280 match = keybindingRegistry.matchKeybinding([keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_C, modifiers: [keys_1.KeyModifier.CtrlCmd] })]);
281 const keyCode = match && keys_1.KeyCode.parse(match.binding.keybinding);
282 expect(keyCode === null || keyCode === void 0 ? void 0 : keyCode.key).to.be.equal(validKeyCode.key);
283 });
284 it('should return partial keybinding matches', () => {
285 const keybindingsUser = [{
286 command: TEST_COMMAND.id,
287 keybinding: 'ctrlcmd+x t'
288 }];
289 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, keybindingsUser);
290 const validKeyCodes = [];
291 validKeyCodes.push(keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_C, modifiers: [keys_1.KeyModifier.CtrlCmd] }));
292 validKeyCodes.push(keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_T }));
293 const match = keybindingRegistry.matchKeybinding(keys_1.KeySequence.parse('ctrlcmd+x'));
294 expect(match && match.kind).to.be.equal('partial');
295 });
296 it('should possible to override keybinding', () => {
297 const overriddenKeybinding = 'ctrlcmd+b a';
298 const command = TEST_COMMAND_SHADOW.id;
299 const keybindingShadowing = [
300 {
301 command,
302 keybinding: overriddenKeybinding
303 },
304 {
305 command,
306 keybinding: 'ctrlcmd+b'
307 }
308 ];
309 keybindingRegistry.registerKeybindings(...keybindingShadowing);
310 const bindings = keybindingRegistry.getKeybindingsForCommand(command);
311 expect(bindings.length).to.be.equal(2);
312 expect(bindings[0].keybinding).to.be.equal('ctrlcmd+b');
313 expect(bindings[1].keybinding).to.be.equal(overriddenKeybinding);
314 });
315 it('overridden bindings should be returned last', () => {
316 var _a, _b, _c;
317 const keyCode = keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_A, modifiers: [keys_1.KeyModifier.Shift] });
318 const overriddenDefaultBinding = {
319 keybinding: keyCode.toString(),
320 command: 'test.overridden-default-command'
321 };
322 const defaultBinding = {
323 keybinding: keyCode.toString(),
324 command: 'test.default-command'
325 };
326 const userBinding = {
327 keybinding: keyCode.toString(),
328 command: 'test.user-command'
329 };
330 const workspaceBinding = {
331 keybinding: keyCode.toString(),
332 command: 'test.workspace-command'
333 };
334 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.DEFAULT, [overriddenDefaultBinding, defaultBinding]);
335 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, [userBinding]);
336 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.WORKSPACE, [workspaceBinding]);
337 // now WORKSPACE bindings are overriding the other scopes
338 let match = keybindingRegistry.matchKeybinding([keyCode]);
339 expect(match === null || match === void 0 ? void 0 : match.kind).to.be.equal('full');
340 expect((_a = match === null || match === void 0 ? void 0 : match.binding) === null || _a === void 0 ? void 0 : _a.command).to.be.equal(workspaceBinding.command);
341 keybindingRegistry.resetKeybindingsForScope(keybinding_1.KeybindingScope.WORKSPACE);
342 // now it should find USER bindings
343 match = keybindingRegistry.matchKeybinding([keyCode]);
344 expect(match === null || match === void 0 ? void 0 : match.kind).to.be.equal('full');
345 expect((_b = match === null || match === void 0 ? void 0 : match.binding) === null || _b === void 0 ? void 0 : _b.command).to.be.equal(userBinding.command);
346 keybindingRegistry.resetKeybindingsForScope(keybinding_1.KeybindingScope.USER);
347 // and finally it should fallback to DEFAULT bindings.
348 match = keybindingRegistry.matchKeybinding([keyCode]);
349 expect(match === null || match === void 0 ? void 0 : match.kind).to.be.equal('full');
350 expect((_c = match === null || match === void 0 ? void 0 : match.binding) === null || _c === void 0 ? void 0 : _c.command).to.be.equal(defaultBinding.command);
351 keybindingRegistry.resetKeybindingsForScope(keybinding_1.KeybindingScope.DEFAULT);
352 // now the registry should be empty
353 match = keybindingRegistry.matchKeybinding([keyCode]);
354 expect(match).to.be.undefined;
355 });
356 it('should not match disabled keybindings', () => {
357 var _a, _b;
358 const keyCode = keys_1.KeyCode.createKeyCode({ first: keys_1.Key.KEY_A, modifiers: [keys_1.KeyModifier.Shift] });
359 const defaultBinding = {
360 keybinding: keyCode.toString(),
361 command: 'test.workspace-command'
362 };
363 const disableDefaultBinding = {
364 keybinding: keyCode.toString(),
365 command: '-test.workspace-command'
366 };
367 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.DEFAULT, [defaultBinding]);
368 let match = keybindingRegistry.matchKeybinding([keyCode]);
369 expect(match === null || match === void 0 ? void 0 : match.kind).to.be.equal('full');
370 expect((_a = match === null || match === void 0 ? void 0 : match.binding) === null || _a === void 0 ? void 0 : _a.command).to.be.equal(defaultBinding.command);
371 keybindingRegistry.setKeymap(keybinding_1.KeybindingScope.USER, [disableDefaultBinding]);
372 match = keybindingRegistry.matchKeybinding([keyCode]);
373 expect(match).to.be.undefined;
374 keybindingRegistry.resetKeybindingsForScope(keybinding_1.KeybindingScope.USER);
375 match = keybindingRegistry.matchKeybinding([keyCode]);
376 expect(match === null || match === void 0 ? void 0 : match.kind).to.be.equal('full');
377 expect((_b = match === null || match === void 0 ? void 0 : match.binding) === null || _b === void 0 ? void 0 : _b.command).to.be.equal(defaultBinding.command);
378 });
379});
380const TEST_COMMAND = {
381 id: 'test.command'
382};
383const TEST_COMMAND2 = {
384 id: 'test.command2'
385};
386const TEST_COMMAND_SHADOW = {
387 id: 'test.command-shadow'
388};
389let MockKeyboardLayoutProvider = class MockKeyboardLayoutProvider {
390 getNativeLayout() {
391 return Promise.resolve({
392 info: { id: 'mock', lang: 'en' },
393 mapping: {}
394 });
395 }
396};
397MockKeyboardLayoutProvider = (0, tslib_1.__decorate)([
398 (0, inversify_1.injectable)()
399], MockKeyboardLayoutProvider);
400let MockKeyboardLayoutChangeNotifier = class MockKeyboardLayoutChangeNotifier {
401 constructor() {
402 this.emitter = new event_1.Emitter();
403 }
404 get onDidChangeNativeLayout() {
405 return this.emitter.event;
406 }
407};
408MockKeyboardLayoutChangeNotifier = (0, tslib_1.__decorate)([
409 (0, inversify_1.injectable)()
410], MockKeyboardLayoutChangeNotifier);
411let TestContribution = class TestContribution {
412 registerCommands(commands) {
413 commands.registerCommand(TEST_COMMAND);
414 commands.registerCommand(TEST_COMMAND2);
415 commands.registerCommand(TEST_COMMAND_SHADOW);
416 }
417 registerKeybindings(keybindings) {
418 [{
419 command: TEST_COMMAND.id,
420 context: 'testContext',
421 keybinding: 'ctrl+a'
422 },
423 {
424 command: TEST_COMMAND2.id,
425 context: 'testContext',
426 keybinding: 'ctrl+f1'
427 },
428 {
429 command: TEST_COMMAND2.id,
430 context: 'testContext',
431 keybinding: 'ctrl+f2'
432 },
433 ].forEach(binding => {
434 keybindings.registerKeybinding(binding);
435 });
436 }
437};
438TestContribution = (0, tslib_1.__decorate)([
439 (0, inversify_1.injectable)()
440], TestContribution);
441function isKeyBindingRegistered(keybinding) {
442 const bindings = keybindingRegistry.getKeybindingsForCommand(keybinding.command);
443 expect(bindings).not.to.be.undefined;
444 let keyBindingFound = false;
445 bindings.forEach((value) => {
446 if (value.command === keybinding.command && value.keybinding === keybinding.keybinding) {
447 keyBindingFound = true;
448 }
449 });
450 return keyBindingFound;
451}
452//# sourceMappingURL=keybinding.spec.js.map
\No newline at end of file