@theia/keymaps 1.45.1 → 1.46.0-next.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,44 +1,44 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2018 Ericsson and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
-
17
- import './keymaps-monaco-contribution';
18
- import '../../src/browser/style/index.css';
19
- import { ContainerModule } from '@theia/core/shared/inversify';
20
- import { KeymapsService } from './keymaps-service';
21
- import { KeymapsFrontendContribution } from './keymaps-frontend-contribution';
22
- import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
23
- import { KeybindingContribution } from '@theia/core/lib/browser/keybinding';
24
- import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
25
- import { WidgetFactory } from '@theia/core/lib/browser';
26
- import { KeybindingWidget } from './keybindings-widget';
27
- import { KeybindingSchemaUpdater } from './keybinding-schema-updater';
28
- import { JsonSchemaContribution } from '@theia/core/lib/browser/json-schema-store';
29
-
30
- export default new ContainerModule(bind => {
31
- bind(KeymapsService).toSelf().inSingletonScope();
32
- bind(KeymapsFrontendContribution).toSelf().inSingletonScope();
33
- bind(CommandContribution).toService(KeymapsFrontendContribution);
34
- bind(KeybindingContribution).toService(KeymapsFrontendContribution);
35
- bind(MenuContribution).toService(KeymapsFrontendContribution);
36
- bind(KeybindingWidget).toSelf();
37
- bind(TabBarToolbarContribution).toService(KeymapsFrontendContribution);
38
- bind(WidgetFactory).toDynamicValue(context => ({
39
- id: KeybindingWidget.ID,
40
- createWidget: () => context.container.get<KeybindingWidget>(KeybindingWidget),
41
- })).inSingletonScope();
42
- bind(KeybindingSchemaUpdater).toSelf().inSingletonScope();
43
- bind(JsonSchemaContribution).toService(KeybindingSchemaUpdater);
44
- });
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 Ericsson and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import './keymaps-monaco-contribution';
18
+ import '../../src/browser/style/index.css';
19
+ import { ContainerModule } from '@theia/core/shared/inversify';
20
+ import { KeymapsService } from './keymaps-service';
21
+ import { KeymapsFrontendContribution } from './keymaps-frontend-contribution';
22
+ import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
23
+ import { KeybindingContribution } from '@theia/core/lib/browser/keybinding';
24
+ import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
25
+ import { WidgetFactory } from '@theia/core/lib/browser';
26
+ import { KeybindingWidget } from './keybindings-widget';
27
+ import { KeybindingSchemaUpdater } from './keybinding-schema-updater';
28
+ import { JsonSchemaContribution } from '@theia/core/lib/browser/json-schema-store';
29
+
30
+ export default new ContainerModule(bind => {
31
+ bind(KeymapsService).toSelf().inSingletonScope();
32
+ bind(KeymapsFrontendContribution).toSelf().inSingletonScope();
33
+ bind(CommandContribution).toService(KeymapsFrontendContribution);
34
+ bind(KeybindingContribution).toService(KeymapsFrontendContribution);
35
+ bind(MenuContribution).toService(KeymapsFrontendContribution);
36
+ bind(KeybindingWidget).toSelf();
37
+ bind(TabBarToolbarContribution).toService(KeymapsFrontendContribution);
38
+ bind(WidgetFactory).toDynamicValue(context => ({
39
+ id: KeybindingWidget.ID,
40
+ createWidget: () => context.container.get<KeybindingWidget>(KeybindingWidget),
41
+ })).inSingletonScope();
42
+ bind(KeybindingSchemaUpdater).toSelf().inSingletonScope();
43
+ bind(JsonSchemaContribution).toService(KeybindingSchemaUpdater);
44
+ });
@@ -1,26 +1,26 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2018 TypeFox and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
- import * as monaco from '@theia/monaco-editor-core';
17
-
18
- monaco.languages.register({
19
- id: 'jsonc',
20
- 'aliases': [
21
- 'JSON with Comments'
22
- ],
23
- 'filenames': [
24
- 'keymaps.json'
25
- ]
26
- });
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 TypeFox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ import * as monaco from '@theia/monaco-editor-core';
17
+
18
+ monaco.languages.register({
19
+ id: 'jsonc',
20
+ 'aliases': [
21
+ 'JSON with Comments'
22
+ ],
23
+ 'filenames': [
24
+ 'keymaps.json'
25
+ ]
26
+ });
@@ -1,214 +1,214 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2017 Ericsson and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
-
17
- import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
18
- import { OpenerService, open, WidgetOpenerOptions, Widget } from '@theia/core/lib/browser';
19
- import { KeybindingRegistry, KeybindingScope, ScopedKeybinding } from '@theia/core/lib/browser/keybinding';
20
- import { Keybinding, RawKeybinding } from '@theia/core/lib/common/keybinding';
21
- import { UserStorageUri } from '@theia/userstorage/lib/browser';
22
- import * as jsoncparser from 'jsonc-parser';
23
- import { Emitter } from '@theia/core/lib/common/event';
24
- import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
25
- import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
26
- import { Deferred } from '@theia/core/lib/common/promise-util';
27
- import URI from '@theia/core/lib/common/uri';
28
- import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace';
29
- import { MessageService } from '@theia/core/lib/common/message-service';
30
- import { MonacoJSONCEditor } from '@theia/preferences/lib/browser/monaco-jsonc-editor';
31
-
32
- @injectable()
33
- export class KeymapsService {
34
-
35
- @inject(MonacoWorkspace)
36
- protected readonly workspace: MonacoWorkspace;
37
-
38
- @inject(MonacoTextModelService)
39
- protected readonly textModelService: MonacoTextModelService;
40
-
41
- @inject(KeybindingRegistry)
42
- protected readonly keybindingRegistry: KeybindingRegistry;
43
-
44
- @inject(OpenerService)
45
- protected readonly opener: OpenerService;
46
-
47
- @inject(MessageService)
48
- protected readonly messageService: MessageService;
49
-
50
- @inject(MonacoJSONCEditor)
51
- protected readonly jsoncEditor: MonacoJSONCEditor;
52
-
53
- protected readonly changeKeymapEmitter = new Emitter<void>();
54
- readonly onDidChangeKeymaps = this.changeKeymapEmitter.event;
55
-
56
- protected model: MonacoEditorModel | undefined;
57
- protected readonly deferredModel = new Deferred<MonacoEditorModel>();
58
-
59
- /**
60
- * Initialize the keybinding service.
61
- */
62
- @postConstruct()
63
- protected init(): void {
64
- this.doInit();
65
- }
66
-
67
- protected async doInit(): Promise<void> {
68
- const reference = await this.textModelService.createModelReference(UserStorageUri.resolve('keymaps.json'));
69
- this.model = reference.object;
70
- this.deferredModel.resolve(this.model);
71
-
72
- this.reconcile();
73
- this.model.onDidChangeContent(() => this.reconcile());
74
- this.model.onDirtyChanged(() => this.reconcile());
75
- this.model.onDidChangeValid(() => this.reconcile());
76
- this.keybindingRegistry.onKeybindingsChanged(() => this.changeKeymapEmitter.fire(undefined));
77
- }
78
-
79
- /**
80
- * Reconcile all the keybindings, registering them to the registry.
81
- */
82
- protected reconcile(): void {
83
- const model = this.model;
84
- if (!model || model.dirty) {
85
- return;
86
- }
87
- try {
88
- const keybindings: Keybinding[] = [];
89
- if (model.valid) {
90
- const content = model.getText();
91
- const json = jsoncparser.parse(content, undefined, { disallowComments: false });
92
- if (Array.isArray(json)) {
93
- for (const value of json) {
94
- if (Keybinding.is(value)) {
95
- keybindings.push(value);
96
- } else if (RawKeybinding.is(value)) {
97
- keybindings.push(Keybinding.apiObjectify(value));
98
- }
99
- }
100
- }
101
- }
102
- this.keybindingRegistry.setKeymap(KeybindingScope.USER, keybindings);
103
- } catch (e) {
104
- console.error(`Failed to load keymaps from '${model.uri}'.`, e);
105
- }
106
- }
107
-
108
- /**
109
- * Open the keybindings widget.
110
- * @param ref the optional reference for opening the widget.
111
- */
112
- async open(ref?: Widget): Promise<void> {
113
- const model = await this.deferredModel.promise;
114
- const options: WidgetOpenerOptions = {
115
- widgetOptions: ref ? { area: 'main', mode: 'split-right', ref } : { area: 'main' },
116
- mode: 'activate'
117
- };
118
- if (!model.valid) {
119
- await model.save();
120
- }
121
- await open(this.opener, new URI(model.uri), options);
122
- }
123
-
124
- /**
125
- * Set the keybinding in the JSON.
126
- * @param newKeybinding the new JSON keybinding
127
- * @param oldKeybinding the old JSON keybinding
128
- */
129
- async setKeybinding(newKeybinding: Keybinding, oldKeybinding: ScopedKeybinding | undefined): Promise<void> {
130
- return this.updateKeymap(() => {
131
- const keybindings: Keybinding[] = [...this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER)];
132
- if (!oldKeybinding) {
133
- Keybinding.addKeybinding(keybindings, newKeybinding);
134
- return keybindings;
135
- } else if (oldKeybinding.scope === KeybindingScope.DEFAULT) {
136
- Keybinding.addKeybinding(keybindings, newKeybinding);
137
- const disabledBinding = {
138
- ...oldKeybinding,
139
- command: '-' + oldKeybinding.command
140
- };
141
- Keybinding.addKeybinding(keybindings, disabledBinding);
142
- return keybindings;
143
- } else if (Keybinding.replaceKeybinding(keybindings, oldKeybinding, newKeybinding)) {
144
- return keybindings;
145
- }
146
- });
147
- }
148
-
149
- /**
150
- * Unset the given keybinding in the JSON.
151
- * If the given keybinding has a default scope, it will be disabled in the JSON.
152
- * Otherwise, it will be removed from the JSON.
153
- * @param keybinding the keybinding to unset
154
- */
155
- unsetKeybinding(keybinding: ScopedKeybinding): Promise<void> {
156
- return this.updateKeymap(() => {
157
- const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
158
- if (keybinding.scope === KeybindingScope.DEFAULT) {
159
- const result: Keybinding[] = [...keybindings];
160
- const disabledBinding = {
161
- ...keybinding,
162
- command: '-' + keybinding.command
163
- };
164
- Keybinding.addKeybinding(result, disabledBinding);
165
- return result;
166
- } else {
167
- const filtered = keybindings.filter(a => !Keybinding.equals(a, keybinding, false, true));
168
- if (filtered.length !== keybindings.length) {
169
- return filtered;
170
- }
171
- }
172
- });
173
- }
174
-
175
- /**
176
- * Whether there is a keybinding with the given command id in the JSON.
177
- * @param commandId the keybinding command id
178
- */
179
- hasKeybinding(commandId: string): boolean {
180
- const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
181
- return keybindings.some(a => a.command === commandId);
182
- }
183
-
184
- /**
185
- * Remove the keybindings with the given command id from the JSON.
186
- * This includes disabled keybindings.
187
- * @param commandId the keybinding command id.
188
- */
189
- removeKeybinding(commandId: string): Promise<void> {
190
- return this.updateKeymap(() => {
191
- const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
192
- const removedCommand = '-' + commandId;
193
- const filtered = keybindings.filter(a => a.command !== commandId && a.command !== removedCommand);
194
- if (filtered.length !== keybindings.length) {
195
- return filtered;
196
- }
197
- });
198
- }
199
-
200
- protected async updateKeymap(op: () => Keybinding[] | void): Promise<void> {
201
- const model = await this.deferredModel.promise;
202
- try {
203
- const keybindings = op();
204
- if (keybindings && this.model) {
205
- await this.jsoncEditor.setValue(this.model, [], keybindings.map(binding => Keybinding.apiObjectify(binding)));
206
- }
207
- } catch (e) {
208
- const message = `Failed to update a keymap in '${model.uri}'.`;
209
- this.messageService.error(`${message} Please check if it is corrupted.`);
210
- console.error(`${message}`, e);
211
- }
212
- }
213
-
214
- }
1
+ // *****************************************************************************
2
+ // Copyright (C) 2017 Ericsson and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
18
+ import { OpenerService, open, WidgetOpenerOptions, Widget } from '@theia/core/lib/browser';
19
+ import { KeybindingRegistry, KeybindingScope, ScopedKeybinding } from '@theia/core/lib/browser/keybinding';
20
+ import { Keybinding, RawKeybinding } from '@theia/core/lib/common/keybinding';
21
+ import { UserStorageUri } from '@theia/userstorage/lib/browser';
22
+ import * as jsoncparser from 'jsonc-parser';
23
+ import { Emitter } from '@theia/core/lib/common/event';
24
+ import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
25
+ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
26
+ import { Deferred } from '@theia/core/lib/common/promise-util';
27
+ import URI from '@theia/core/lib/common/uri';
28
+ import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace';
29
+ import { MessageService } from '@theia/core/lib/common/message-service';
30
+ import { MonacoJSONCEditor } from '@theia/preferences/lib/browser/monaco-jsonc-editor';
31
+
32
+ @injectable()
33
+ export class KeymapsService {
34
+
35
+ @inject(MonacoWorkspace)
36
+ protected readonly workspace: MonacoWorkspace;
37
+
38
+ @inject(MonacoTextModelService)
39
+ protected readonly textModelService: MonacoTextModelService;
40
+
41
+ @inject(KeybindingRegistry)
42
+ protected readonly keybindingRegistry: KeybindingRegistry;
43
+
44
+ @inject(OpenerService)
45
+ protected readonly opener: OpenerService;
46
+
47
+ @inject(MessageService)
48
+ protected readonly messageService: MessageService;
49
+
50
+ @inject(MonacoJSONCEditor)
51
+ protected readonly jsoncEditor: MonacoJSONCEditor;
52
+
53
+ protected readonly changeKeymapEmitter = new Emitter<void>();
54
+ readonly onDidChangeKeymaps = this.changeKeymapEmitter.event;
55
+
56
+ protected model: MonacoEditorModel | undefined;
57
+ protected readonly deferredModel = new Deferred<MonacoEditorModel>();
58
+
59
+ /**
60
+ * Initialize the keybinding service.
61
+ */
62
+ @postConstruct()
63
+ protected init(): void {
64
+ this.doInit();
65
+ }
66
+
67
+ protected async doInit(): Promise<void> {
68
+ const reference = await this.textModelService.createModelReference(UserStorageUri.resolve('keymaps.json'));
69
+ this.model = reference.object;
70
+ this.deferredModel.resolve(this.model);
71
+
72
+ this.reconcile();
73
+ this.model.onDidChangeContent(() => this.reconcile());
74
+ this.model.onDirtyChanged(() => this.reconcile());
75
+ this.model.onDidChangeValid(() => this.reconcile());
76
+ this.keybindingRegistry.onKeybindingsChanged(() => this.changeKeymapEmitter.fire(undefined));
77
+ }
78
+
79
+ /**
80
+ * Reconcile all the keybindings, registering them to the registry.
81
+ */
82
+ protected reconcile(): void {
83
+ const model = this.model;
84
+ if (!model || model.dirty) {
85
+ return;
86
+ }
87
+ try {
88
+ const keybindings: Keybinding[] = [];
89
+ if (model.valid) {
90
+ const content = model.getText();
91
+ const json = jsoncparser.parse(content, undefined, { disallowComments: false });
92
+ if (Array.isArray(json)) {
93
+ for (const value of json) {
94
+ if (Keybinding.is(value)) {
95
+ keybindings.push(value);
96
+ } else if (RawKeybinding.is(value)) {
97
+ keybindings.push(Keybinding.apiObjectify(value));
98
+ }
99
+ }
100
+ }
101
+ }
102
+ this.keybindingRegistry.setKeymap(KeybindingScope.USER, keybindings);
103
+ } catch (e) {
104
+ console.error(`Failed to load keymaps from '${model.uri}'.`, e);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Open the keybindings widget.
110
+ * @param ref the optional reference for opening the widget.
111
+ */
112
+ async open(ref?: Widget): Promise<void> {
113
+ const model = await this.deferredModel.promise;
114
+ const options: WidgetOpenerOptions = {
115
+ widgetOptions: ref ? { area: 'main', mode: 'split-right', ref } : { area: 'main' },
116
+ mode: 'activate'
117
+ };
118
+ if (!model.valid) {
119
+ await model.save();
120
+ }
121
+ await open(this.opener, new URI(model.uri), options);
122
+ }
123
+
124
+ /**
125
+ * Set the keybinding in the JSON.
126
+ * @param newKeybinding the new JSON keybinding
127
+ * @param oldKeybinding the old JSON keybinding
128
+ */
129
+ async setKeybinding(newKeybinding: Keybinding, oldKeybinding: ScopedKeybinding | undefined): Promise<void> {
130
+ return this.updateKeymap(() => {
131
+ const keybindings: Keybinding[] = [...this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER)];
132
+ if (!oldKeybinding) {
133
+ Keybinding.addKeybinding(keybindings, newKeybinding);
134
+ return keybindings;
135
+ } else if (oldKeybinding.scope === KeybindingScope.DEFAULT) {
136
+ Keybinding.addKeybinding(keybindings, newKeybinding);
137
+ const disabledBinding = {
138
+ ...oldKeybinding,
139
+ command: '-' + oldKeybinding.command
140
+ };
141
+ Keybinding.addKeybinding(keybindings, disabledBinding);
142
+ return keybindings;
143
+ } else if (Keybinding.replaceKeybinding(keybindings, oldKeybinding, newKeybinding)) {
144
+ return keybindings;
145
+ }
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Unset the given keybinding in the JSON.
151
+ * If the given keybinding has a default scope, it will be disabled in the JSON.
152
+ * Otherwise, it will be removed from the JSON.
153
+ * @param keybinding the keybinding to unset
154
+ */
155
+ unsetKeybinding(keybinding: ScopedKeybinding): Promise<void> {
156
+ return this.updateKeymap(() => {
157
+ const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
158
+ if (keybinding.scope === KeybindingScope.DEFAULT) {
159
+ const result: Keybinding[] = [...keybindings];
160
+ const disabledBinding = {
161
+ ...keybinding,
162
+ command: '-' + keybinding.command
163
+ };
164
+ Keybinding.addKeybinding(result, disabledBinding);
165
+ return result;
166
+ } else {
167
+ const filtered = keybindings.filter(a => !Keybinding.equals(a, keybinding, false, true));
168
+ if (filtered.length !== keybindings.length) {
169
+ return filtered;
170
+ }
171
+ }
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Whether there is a keybinding with the given command id in the JSON.
177
+ * @param commandId the keybinding command id
178
+ */
179
+ hasKeybinding(commandId: string): boolean {
180
+ const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
181
+ return keybindings.some(a => a.command === commandId);
182
+ }
183
+
184
+ /**
185
+ * Remove the keybindings with the given command id from the JSON.
186
+ * This includes disabled keybindings.
187
+ * @param commandId the keybinding command id.
188
+ */
189
+ removeKeybinding(commandId: string): Promise<void> {
190
+ return this.updateKeymap(() => {
191
+ const keybindings = this.keybindingRegistry.getKeybindingsByScope(KeybindingScope.USER);
192
+ const removedCommand = '-' + commandId;
193
+ const filtered = keybindings.filter(a => a.command !== commandId && a.command !== removedCommand);
194
+ if (filtered.length !== keybindings.length) {
195
+ return filtered;
196
+ }
197
+ });
198
+ }
199
+
200
+ protected async updateKeymap(op: () => Keybinding[] | void): Promise<void> {
201
+ const model = await this.deferredModel.promise;
202
+ try {
203
+ const keybindings = op();
204
+ if (keybindings && this.model) {
205
+ await this.jsoncEditor.setValue(this.model, [], keybindings.map(binding => Keybinding.apiObjectify(binding)));
206
+ }
207
+ } catch (e) {
208
+ const message = `Failed to update a keymap in '${model.uri}'.`;
209
+ this.messageService.error(`${message} Please check if it is corrupted.`);
210
+ console.error(`${message}`, e);
211
+ }
212
+ }
213
+
214
+ }