-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
monaco-keybinding.ts
111 lines (102 loc) · 5.5 KB
/
monaco-keybinding.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// *****************************************************************************
// Copyright (C) 2017 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
import { KeybindingContribution, KeybindingRegistry, KeybindingScope, KeyCode } from '@theia/core/lib/browser';
import { MonacoCommands } from './monaco-command';
import { MonacoCommandRegistry } from './monaco-command-registry';
import { CommandRegistry, DisposableCollection, environment, isOSX } from '@theia/core';
import { MonacoResolvedKeybinding } from './monaco-resolved-keybinding';
import { KeybindingsRegistry } from '@theia/monaco-editor-core/esm/vs/platform/keybinding/common/keybindingsRegistry';
import { StandaloneKeybindingService, StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
import { IKeybindingService } from '@theia/monaco-editor-core/esm/vs/platform/keybinding/common/keybinding';
import { MonacoContextKeyService } from './monaco-context-key-service';
import { KEY_CODE_MAP } from './monaco-keycode-map';
import * as monaco from '@theia/monaco-editor-core';
@injectable()
export class MonacoKeybindingContribution implements KeybindingContribution {
protected toDisposeOnKeybindingChange = new DisposableCollection();
@inject(MonacoCommandRegistry) protected readonly commands: MonacoCommandRegistry;
@inject(KeybindingRegistry) protected readonly keybindings: KeybindingRegistry;
@inject(CommandRegistry) protected readonly theiaCommandRegistry: CommandRegistry;
@inject(MonacoContextKeyService) protected readonly contextKeyService: MonacoContextKeyService;
@postConstruct()
protected init(): void {
this.keybindings.onKeybindingsChanged(() => this.updateMonacoKeybindings());
}
registerKeybindings(registry: KeybindingRegistry): void {
const defaultKeybindings = KeybindingsRegistry.getDefaultKeybindings();
for (const item of defaultKeybindings) {
const command = this.commands.validate(item.command || undefined);
if (command && item.keybinding) {
const when = (item.when && item.when.serialize()) ?? undefined;
let keybinding;
if (item.command === MonacoCommands.GO_TO_DEFINITION && !environment.electron.is()) {
keybinding = 'ctrlcmd+f11';
} else {
keybinding = MonacoResolvedKeybinding.toKeybinding(item.keybinding.chords);
}
registry.registerKeybinding({ command, keybinding, when });
}
}
}
protected updateMonacoKeybindings(): void {
const monacoKeybindingRegistry = StandaloneServices.get(IKeybindingService);
if (monacoKeybindingRegistry instanceof StandaloneKeybindingService) {
this.toDisposeOnKeybindingChange.dispose();
for (const binding of this.keybindings.getKeybindingsByScope(KeybindingScope.USER).concat(this.keybindings.getKeybindingsByScope(KeybindingScope.WORKSPACE))) {
const resolved = this.keybindings.resolveKeybinding(binding);
const command = binding.command;
const when = binding.when
? this.contextKeyService.parse(binding.when)
: binding.context
? this.contextKeyService.parse(binding.context)
: undefined;
this.toDisposeOnKeybindingChange.push(monacoKeybindingRegistry.addDynamicKeybinding(
binding.command,
this.toMonacoKeybindingNumber(resolved),
(_, ...args) => this.theiaCommandRegistry.executeCommand(command, ...args),
when,
));
}
}
}
protected toMonacoKeybindingNumber(codes: KeyCode[]): number {
const [firstPart, secondPart] = codes;
if (codes.length > 2) {
console.warn('Key chords should not consist of more than two parts; got ', codes);
}
const encodedFirstPart = this.toSingleMonacoKeybindingNumber(firstPart);
const encodedSecondPart = secondPart ? this.toSingleMonacoKeybindingNumber(secondPart) << 16 : 0;
return monaco.KeyMod.chord(encodedFirstPart, encodedSecondPart);
}
protected toSingleMonacoKeybindingNumber(code: KeyCode): number {
const keyCode = code.key?.keyCode !== undefined ? KEY_CODE_MAP[code.key.keyCode] : 0;
let encoded = (keyCode >>> 0) & 0x000000FF;
if (code.alt) {
encoded |= monaco.KeyMod.Alt;
}
if (code.shift) {
encoded |= monaco.KeyMod.Shift;
}
if (code.ctrl) {
encoded |= monaco.KeyMod.WinCtrl;
}
if (code.meta && isOSX) {
encoded |= monaco.KeyMod.CtrlCmd;
}
return encoded;
}
}