UNPKG

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