@opensumi/ide-keymaps 2.12.1-next-079c1930
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.
- package/lib/browser/index.d.ts +6 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +26 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/keymaps-parser.d.ts +46 -0
- package/lib/browser/keymaps-parser.d.ts.map +1 -0
- package/lib/browser/keymaps-parser.js +100 -0
- package/lib/browser/keymaps-parser.js.map +1 -0
- package/lib/browser/keymaps.contribution.d.ts +36 -0
- package/lib/browser/keymaps.contribution.d.ts.map +1 -0
- package/lib/browser/keymaps.contribution.js +169 -0
- package/lib/browser/keymaps.contribution.js.map +1 -0
- package/lib/browser/keymaps.module.less +310 -0
- package/lib/browser/keymaps.service.d.ts +136 -0
- package/lib/browser/keymaps.service.d.ts.map +1 -0
- package/lib/browser/keymaps.service.js +671 -0
- package/lib/browser/keymaps.service.js.map +1 -0
- package/lib/browser/keymaps.view.d.ts +3 -0
- package/lib/browser/keymaps.view.d.ts.map +1 -0
- package/lib/browser/keymaps.view.js +250 -0
- package/lib/browser/keymaps.view.js.map +1 -0
- package/lib/common/const.d.ts +3 -0
- package/lib/common/const.d.ts.map +1 -0
- package/lib/common/const.js +6 -0
- package/lib/common/const.js.map +1 -0
- package/lib/common/index.d.ts +3 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +6 -0
- package/lib/common/index.js.map +1 -0
- package/lib/common/keymaps.d.ts +98 -0
- package/lib/common/keymaps.d.ts.map +1 -0
- package/lib/common/keymaps.js +5 -0
- package/lib/common/keymaps.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var KeymapService_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.KeymapService = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const di_1 = require("@opensumi/di");
|
|
7
|
+
const mobx_1 = require("mobx");
|
|
8
|
+
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
|
|
9
|
+
const keymaps_parser_1 = require("./keymaps-parser");
|
|
10
|
+
const fuzzy = (0, tslib_1.__importStar)(require("fuzzy"));
|
|
11
|
+
const common_1 = require("../common");
|
|
12
|
+
const ide_preferences_1 = require("@opensumi/ide-preferences");
|
|
13
|
+
const ide_file_service_1 = require("@opensumi/ide-file-service");
|
|
14
|
+
const progress_1 = require("@opensumi/ide-core-browser/lib/progress");
|
|
15
|
+
let KeymapService = KeymapService_1 = class KeymapService {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.keymapChangeEmitter = new ide_core_browser_1.Emitter();
|
|
18
|
+
this.convertKeySequence = [];
|
|
19
|
+
this.toUnregisterUserKeybindingMap = new Map();
|
|
20
|
+
this.toRestoreDefaultKeybindingMap = new Map();
|
|
21
|
+
this.searchDelayer = new ide_core_browser_1.ThrottledDelayer(KeymapService_1.DEFAULT_SEARCH_DELAY);
|
|
22
|
+
this.disposableCollection = new ide_core_browser_1.DisposableCollection();
|
|
23
|
+
/**
|
|
24
|
+
* fuzzy搜索参数,pre及post用于包裹搜索结果
|
|
25
|
+
* @protected
|
|
26
|
+
* @memberof KeymapService
|
|
27
|
+
*/
|
|
28
|
+
this.fuzzyOptions = {
|
|
29
|
+
pre: '<match>',
|
|
30
|
+
post: '</match>',
|
|
31
|
+
};
|
|
32
|
+
this.keybindings = [];
|
|
33
|
+
/**
|
|
34
|
+
* 设置快捷键
|
|
35
|
+
* @param {Keybinding} keybindings
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
* @memberof KeymapsService
|
|
38
|
+
*/
|
|
39
|
+
this.setKeybinding = (keybinding) => {
|
|
40
|
+
this.progressService.withProgress({
|
|
41
|
+
location: ide_core_browser_1.ProgressLocation.Notification,
|
|
42
|
+
}, (progress) => {
|
|
43
|
+
return new Promise(async (resolve, reject) => {
|
|
44
|
+
progress.report({ message: (0, ide_core_browser_1.localize)('keymaps.keybinding.loading'), increment: 0, total: 100 });
|
|
45
|
+
const keybindings = this.storeKeybindings || [];
|
|
46
|
+
let updated = false;
|
|
47
|
+
for (const kb of keybindings) {
|
|
48
|
+
const item = {
|
|
49
|
+
when: kb.when,
|
|
50
|
+
command: kb.command,
|
|
51
|
+
keybinding: kb.key,
|
|
52
|
+
};
|
|
53
|
+
if (kb.command === keybinding.command) {
|
|
54
|
+
updated = true;
|
|
55
|
+
this.unregisterUserKeybinding(item);
|
|
56
|
+
kb.key = keybinding.keybinding;
|
|
57
|
+
this.registerUserKeybinding(Object.assign(Object.assign({}, item), { priority: ide_core_browser_1.KeybindingWeight.WorkbenchContrib * 100 }));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!updated) {
|
|
61
|
+
const defaultBinding = this.keybindings.find((kb) => kb.id === keybinding.command && this.getRaw(kb.when) === keybinding.when);
|
|
62
|
+
if (defaultBinding && defaultBinding.keybinding) {
|
|
63
|
+
this.unregisterDefaultKeybinding({
|
|
64
|
+
when: this.getRaw(defaultBinding.when),
|
|
65
|
+
command: defaultBinding.id,
|
|
66
|
+
keybinding: this.getRaw(defaultBinding.keybinding),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// 不能额外传入keybinding的resolved值
|
|
70
|
+
const item = {
|
|
71
|
+
when: this.getWhen(keybinding),
|
|
72
|
+
command: keybinding.command,
|
|
73
|
+
key: keybinding.keybinding,
|
|
74
|
+
};
|
|
75
|
+
keybindings.push(item);
|
|
76
|
+
this.registerUserKeybinding(keybinding);
|
|
77
|
+
}
|
|
78
|
+
// 后置存储流程
|
|
79
|
+
this.saveKeybinding(keybindings).then(() => {
|
|
80
|
+
resolve(undefined);
|
|
81
|
+
progress.report({ message: (0, ide_core_browser_1.localize)('keymaps.keybinding.success'), increment: 99 });
|
|
82
|
+
}).catch((e) => {
|
|
83
|
+
reject(e);
|
|
84
|
+
progress.report({ message: (0, ide_core_browser_1.localize)('keymaps.keybinding.fail'), increment: 99 });
|
|
85
|
+
}).finally(() => {
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
// 3s 后再隐藏进度条
|
|
88
|
+
progress.report({ increment: 100 });
|
|
89
|
+
}, 3000);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}, () => { });
|
|
93
|
+
};
|
|
94
|
+
this.covert = (event) => {
|
|
95
|
+
return this.keybindingService.convert(event, ' ');
|
|
96
|
+
};
|
|
97
|
+
this.clearCovert = () => {
|
|
98
|
+
return this.keybindingService.clearConvert();
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* 移除给定ID的快捷键绑定
|
|
102
|
+
* @param {string} commandId
|
|
103
|
+
* @returns {Promise<void>}
|
|
104
|
+
* @memberof KeymapsService
|
|
105
|
+
*/
|
|
106
|
+
this.resetKeybinding = async (item) => {
|
|
107
|
+
if (!this.resource) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const keymaps = this.storeKeybindings;
|
|
111
|
+
const filtered = keymaps.filter((a) => a.command !== item.command);
|
|
112
|
+
this.unregisterUserKeybinding(item);
|
|
113
|
+
this.restoreDefaultKeybinding(item);
|
|
114
|
+
this.saveKeybinding(filtered);
|
|
115
|
+
};
|
|
116
|
+
this.fixed = async () => {
|
|
117
|
+
this.commandService.executeCommand(ide_core_browser_1.EDITOR_COMMANDS.OPEN_RESOURCE.id, new ide_core_browser_1.URI().withScheme(common_1.KEYMAPS_SCHEME), { preview: false });
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* 搜索快捷键
|
|
121
|
+
*/
|
|
122
|
+
this.searchKeybindings = (search) => {
|
|
123
|
+
this.currentSearchValue = search;
|
|
124
|
+
// throttle
|
|
125
|
+
if (!this.searchDelayer.isTriggered) {
|
|
126
|
+
this.searchDelayer.cancel();
|
|
127
|
+
}
|
|
128
|
+
this.searchDelayer.trigger(async () => {
|
|
129
|
+
this.doSearchKeybindings(this.currentSearchValue);
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* 模糊搜索匹配的快捷键
|
|
134
|
+
* @protected
|
|
135
|
+
*/
|
|
136
|
+
this.doSearchKeybindings = (search) => {
|
|
137
|
+
const items = this.getKeybindingItems();
|
|
138
|
+
const result = [];
|
|
139
|
+
items.forEach((item) => {
|
|
140
|
+
const keys = ['command', 'keybinding', 'when', 'context', 'source'];
|
|
141
|
+
let matched = false;
|
|
142
|
+
for (const key of keys) {
|
|
143
|
+
const str = item[key];
|
|
144
|
+
if (str) {
|
|
145
|
+
const fuzzyMatch = fuzzy.match(search, str, this.fuzzyOptions);
|
|
146
|
+
if (fuzzyMatch) {
|
|
147
|
+
item[key] = fuzzyMatch.rendered;
|
|
148
|
+
matched = true;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// 匹配到的快捷键会有不同的显示优先级
|
|
152
|
+
// 排序
|
|
153
|
+
if (key === 'keybinding') {
|
|
154
|
+
const queryItems = search.split('+');
|
|
155
|
+
// 处理组合键
|
|
156
|
+
const tempItems = str.split(' ');
|
|
157
|
+
// 存储空格字符串
|
|
158
|
+
const spaceIndexArr = [0];
|
|
159
|
+
let bindingItems = [];
|
|
160
|
+
if (tempItems.length > 1) {
|
|
161
|
+
tempItems.forEach((tItem) => {
|
|
162
|
+
const tKeys = tItem.split('+');
|
|
163
|
+
spaceIndexArr.push(tKeys.length + spaceIndexArr[-1]);
|
|
164
|
+
bindingItems.push(...tKeys);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
bindingItems = str.split('+');
|
|
169
|
+
}
|
|
170
|
+
spaceIndexArr.shift();
|
|
171
|
+
const renderedResult = [...bindingItems];
|
|
172
|
+
let matchCounter = 0;
|
|
173
|
+
queryItems.forEach((queryItem) => {
|
|
174
|
+
let keyFuzzyMatch = { rendered: '', score: 0 };
|
|
175
|
+
let keyIndex = -1;
|
|
176
|
+
if (str) {
|
|
177
|
+
bindingItems.forEach((bindingItem) => {
|
|
178
|
+
// 通过用户输入匹配所有快捷键字段
|
|
179
|
+
const tempFuzzyMatch = fuzzy.match(queryItem, bindingItem, this.fuzzyOptions);
|
|
180
|
+
// 选择匹配度的匹配项
|
|
181
|
+
if (tempFuzzyMatch && tempFuzzyMatch.score > keyFuzzyMatch.score) {
|
|
182
|
+
keyFuzzyMatch = tempFuzzyMatch;
|
|
183
|
+
// 获取在快捷键数组中对应的位置
|
|
184
|
+
keyIndex = renderedResult.indexOf(bindingItem);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
const keyRendered = keyFuzzyMatch.rendered;
|
|
188
|
+
if (keyRendered) {
|
|
189
|
+
if (keyIndex > -1) {
|
|
190
|
+
renderedResult[keyIndex] = keyRendered;
|
|
191
|
+
}
|
|
192
|
+
// 在快捷键数组中移除匹配过的快捷键
|
|
193
|
+
bindingItems.splice(keyIndex, 1, '');
|
|
194
|
+
matchCounter += 1;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
if (matchCounter === queryItems.length) {
|
|
199
|
+
// 处理组合键的渲染
|
|
200
|
+
if (spaceIndexArr.length > 0) {
|
|
201
|
+
const chordRenderedResult = '';
|
|
202
|
+
renderedResult.forEach((resultKey, index) => {
|
|
203
|
+
if (index === 0) {
|
|
204
|
+
chordRenderedResult.concat(resultKey);
|
|
205
|
+
}
|
|
206
|
+
else if (spaceIndexArr.indexOf(index) !== -1) {
|
|
207
|
+
chordRenderedResult.concat(' ' + resultKey);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
chordRenderedResult.concat('+' + resultKey);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
item[key] = chordRenderedResult;
|
|
214
|
+
}
|
|
215
|
+
item[key] = renderedResult.join('+');
|
|
216
|
+
matched = true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (matched) {
|
|
223
|
+
result.push(item);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
this.keybindings = result;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* 验证快捷键是否可用
|
|
230
|
+
* @memberof KeymapService
|
|
231
|
+
*/
|
|
232
|
+
this.validateKeybinding = (keybindingItem, keybinding) => {
|
|
233
|
+
if (!keybinding) {
|
|
234
|
+
return (0, ide_core_browser_1.localize)('keymaps.keybinding.require');
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const binding = {
|
|
238
|
+
command: keybindingItem.command,
|
|
239
|
+
when: keybindingItem.when,
|
|
240
|
+
keybinding,
|
|
241
|
+
};
|
|
242
|
+
if (keybindingItem.keybinding === keybinding) {
|
|
243
|
+
return ' ';
|
|
244
|
+
}
|
|
245
|
+
return this.keybindingRegistry.validateKeybindingInScope(binding);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
return error;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
this.detectKeybindings = (keybindingItem, keybinding) => {
|
|
252
|
+
if (!keybinding) {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
if (keybindingItem.keybinding === keybinding) {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
// 可能匹配了高亮结果,需要还原部分数据
|
|
260
|
+
const keybindings = this.keybindings.filter((kb) => this.getRaw(kb.keybinding) === keybinding);
|
|
261
|
+
// 只返回全匹配快捷键,不返回包含关系快捷键(包含关系会在保存前提示冲突)
|
|
262
|
+
if (keybindings.length > 0) {
|
|
263
|
+
return keybindings.map((binding) => {
|
|
264
|
+
const command = this.commandRegistry.getCommand(this.getRaw(binding.command));
|
|
265
|
+
const isUserKeybinding = this.storeKeybindings.find((kb) => command && kb.command === command.id);
|
|
266
|
+
binding.when = this.getRaw(binding.when);
|
|
267
|
+
binding.keybinding = this.getRaw(binding.keybinding);
|
|
268
|
+
return {
|
|
269
|
+
id: command ? command.id : this.getRaw(binding.command),
|
|
270
|
+
command: (command ? command.label || command.id : binding.command) || '',
|
|
271
|
+
when: this.keybindingService.convertMonacoWhen(binding.when),
|
|
272
|
+
keybinding: this.getRaw(binding.keybinding),
|
|
273
|
+
source: isUserKeybinding ? this.getScope(ide_core_browser_1.KeybindingScope.USER) : this.getScope(ide_core_browser_1.KeybindingScope.DEFAULT),
|
|
274
|
+
};
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
this.logger.error(error);
|
|
280
|
+
}
|
|
281
|
+
return [];
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
get onDidKeymapChanges() {
|
|
285
|
+
return this.keymapChangeEmitter.event;
|
|
286
|
+
}
|
|
287
|
+
get storeKeybindings() {
|
|
288
|
+
return this._storeKeybindings && this._storeKeybindings.map((keybinding) => (Object.assign(Object.assign({}, keybinding), { command: this.getValidateCommand(keybinding.command),
|
|
289
|
+
// 保持对旧版 keybinding 格式兼容
|
|
290
|
+
key: keybinding.key || keybinding.keybinding })));
|
|
291
|
+
}
|
|
292
|
+
set storeKeybindings(value) {
|
|
293
|
+
this._storeKeybindings = value;
|
|
294
|
+
}
|
|
295
|
+
async init() {
|
|
296
|
+
const keymapUrl = KeymapService_1.KEYMAP_FILE_URI.toString();
|
|
297
|
+
this.resource = await this.filesystem.getFileStat(keymapUrl);
|
|
298
|
+
// 如果不存在,则默认创建一个空文件
|
|
299
|
+
// 集成测有可能后置才会同步这个配置,如果不创建好不方便 watch
|
|
300
|
+
if (!this.resource) {
|
|
301
|
+
this.resource = await this.filesystem.createFile(keymapUrl, {
|
|
302
|
+
content: JSON.stringify([]),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
await this.reconcile();
|
|
306
|
+
const watcher = await this.filesystem.watchFileChanges(KeymapService_1.KEYMAP_FILE_URI);
|
|
307
|
+
this.disposableCollection.push(watcher);
|
|
308
|
+
watcher.onFilesChanged(() => {
|
|
309
|
+
// 快捷键绑定文件内容变化,重新更新快捷键信息
|
|
310
|
+
this.reconcile();
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
async openResource() {
|
|
314
|
+
if (!this.resource || !this.resource.uri) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const fsPath = await this.resource.uri;
|
|
318
|
+
if (!fsPath) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const exist = await this.filesystem.access(fsPath);
|
|
322
|
+
if (!exist) {
|
|
323
|
+
const fileStat = await this.filesystem.createFile(fsPath);
|
|
324
|
+
const stat = await this.filesystem.setContent(fileStat, '{\n}');
|
|
325
|
+
this.resource = stat || undefined;
|
|
326
|
+
}
|
|
327
|
+
if (fsPath) {
|
|
328
|
+
this.commandService.executeCommand(ide_core_browser_1.EDITOR_COMMANDS.OPEN_RESOURCE.id, new ide_core_browser_1.URI(fsPath), { preview: false });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
disposeRegistedKeybinding() {
|
|
332
|
+
for (const [, value] of this.toUnregisterUserKeybindingMap) {
|
|
333
|
+
value.dispose();
|
|
334
|
+
}
|
|
335
|
+
for (const [, value] of this.toRestoreDefaultKeybindingMap) {
|
|
336
|
+
value.dispose();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
dispose() {
|
|
340
|
+
this.disposeRegistedKeybinding();
|
|
341
|
+
this.disposableCollection.dispose();
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* 因为 monaco.edtior.* 替换为 editor.* 为了兼容在 storage 里存量的数据,需要兼容一下
|
|
345
|
+
* @param command
|
|
346
|
+
*/
|
|
347
|
+
getValidateCommand(command) {
|
|
348
|
+
return command.replace(/^monaco.editor/, 'editor');
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* 重新加载并设置Keymap定义的快捷键
|
|
352
|
+
* @param keybindings
|
|
353
|
+
*/
|
|
354
|
+
async reconcile(keybindings) {
|
|
355
|
+
const keymap = keybindings ? keybindings.slice(0) : await this.parseKeybindings();
|
|
356
|
+
const bindings = keymap.map((kb) => {
|
|
357
|
+
// 清洗存入keymap数据
|
|
358
|
+
return {
|
|
359
|
+
when: kb.when,
|
|
360
|
+
command: this.getValidateCommand(kb.command),
|
|
361
|
+
keybinding: kb.key || kb.keybinding,
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
const added = [];
|
|
365
|
+
const removed = [];
|
|
366
|
+
// 重新注册快捷键前取消注册先前的快捷键
|
|
367
|
+
this.disposeRegistedKeybinding();
|
|
368
|
+
bindings.forEach((kb) => {
|
|
369
|
+
if (kb.command.startsWith('-')) {
|
|
370
|
+
removed.push(kb);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
added.push(kb);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
// 卸载快捷键的语法仅对默认快捷键生效,故这里不需要进行额外操作
|
|
377
|
+
added.map((kb) => {
|
|
378
|
+
this.unregisterDefaultKeybinding(kb, true);
|
|
379
|
+
this.registerUserKeybinding(kb);
|
|
380
|
+
});
|
|
381
|
+
// 卸载默认快捷键
|
|
382
|
+
removed.map((kb) => {
|
|
383
|
+
// 去除开头的 '-' 便于查找默认快捷键
|
|
384
|
+
kb.command = kb.command.slice(1);
|
|
385
|
+
this.unregisterDefaultKeybinding(kb, true);
|
|
386
|
+
});
|
|
387
|
+
this.updateKeybindings();
|
|
388
|
+
}
|
|
389
|
+
unregisterUserKeybinding(kb) {
|
|
390
|
+
const key = this.toUniqueKey(kb);
|
|
391
|
+
if (this.toUnregisterUserKeybindingMap.has(key)) {
|
|
392
|
+
const disposeable = this.toUnregisterUserKeybindingMap.get(key);
|
|
393
|
+
disposeable === null || disposeable === void 0 ? void 0 : disposeable.dispose();
|
|
394
|
+
this.toUnregisterUserKeybindingMap.delete(key);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
registerUserKeybinding(kb) {
|
|
398
|
+
const key = this.toUniqueKey(kb);
|
|
399
|
+
this.toUnregisterUserKeybindingMap.set(key, this.keybindingRegistry.registerKeybinding(kb, ide_core_browser_1.KeybindingScope.USER));
|
|
400
|
+
}
|
|
401
|
+
unregisterDefaultKeybinding(kd, fromUserScope = false) {
|
|
402
|
+
if (fromUserScope) {
|
|
403
|
+
// 当卸载默认快捷键的操作是从用户快捷键初始化时操作的时候
|
|
404
|
+
// 此时需要找到command下对应keybindings中when及快捷键匹配的快捷键进行卸载
|
|
405
|
+
const keybindings = this.keybindingRegistry.getKeybindingsForCommand(kd.command);
|
|
406
|
+
keybindings.map((rawKd) => {
|
|
407
|
+
const targetKd = Object.assign(Object.assign({}, kd), { keybinding: rawKd.keybinding });
|
|
408
|
+
this.keybindingRegistry.unregisterKeybinding(targetKd);
|
|
409
|
+
const key = this.toUniqueKey(kd);
|
|
410
|
+
// 存储可恢复默认快捷键注册的函数
|
|
411
|
+
this.toRestoreDefaultKeybindingMap.set(key, ide_core_browser_1.Disposable.create(() => {
|
|
412
|
+
this.keybindingRegistry.registerKeybinding(targetKd);
|
|
413
|
+
}));
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
// 当直接从快捷键编辑面板直接修改默认快捷键的时候
|
|
418
|
+
// 由于卸载是定向的快捷键,有明确的快捷键,不需要进行command对应到快捷键的查找,可直接卸载
|
|
419
|
+
this.keybindingRegistry.unregisterKeybinding(kd);
|
|
420
|
+
const key = this.toUniqueKey(kd);
|
|
421
|
+
// 存储可恢复默认快捷键注册的函数
|
|
422
|
+
this.toRestoreDefaultKeybindingMap.set(key, ide_core_browser_1.Disposable.create(() => {
|
|
423
|
+
this.keybindingRegistry.registerKeybinding(kd);
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
restoreDefaultKeybinding(kb) {
|
|
428
|
+
const key = this.toUniqueKey(kb);
|
|
429
|
+
const restore = this.toRestoreDefaultKeybindingMap.get(key);
|
|
430
|
+
restore === null || restore === void 0 ? void 0 : restore.dispose();
|
|
431
|
+
}
|
|
432
|
+
toUniqueKey(kb) {
|
|
433
|
+
return `${kb.command}${kb.when ? `-${kb.when}` : '-'}${kb.keybinding ? `-${kb.keybinding}` : '-'}`;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 更新keybindings列表
|
|
437
|
+
*/
|
|
438
|
+
updateKeybindings() {
|
|
439
|
+
if (this.currentSearchValue) {
|
|
440
|
+
this.doSearchKeybindings(this.currentSearchValue);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
this.keybindings = this.getKeybindingItems();
|
|
444
|
+
}
|
|
445
|
+
this.keymapChangeEmitter.fire();
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 解析快捷键数据
|
|
449
|
+
* @protected
|
|
450
|
+
* @returns {Promise<Keybinding[]>}
|
|
451
|
+
* @memberof KeymapsService
|
|
452
|
+
*/
|
|
453
|
+
async parseKeybindings() {
|
|
454
|
+
try {
|
|
455
|
+
const resource = await this.resource;
|
|
456
|
+
if (!resource) {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
const { content } = await this.filesystem.readFile(resource.uri);
|
|
460
|
+
this.storeKeybindings = this.parser.parse(content.toString());
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
this.logger.warn(`ParseKeybindings fail: ${error.stack}`);
|
|
464
|
+
this.storeKeybindings = [];
|
|
465
|
+
}
|
|
466
|
+
return this.storeKeybindings;
|
|
467
|
+
}
|
|
468
|
+
async saveKeybinding(keymaps) {
|
|
469
|
+
this.storeKeybindings = keymaps;
|
|
470
|
+
this.updateKeybindings();
|
|
471
|
+
if (!this.resource) {
|
|
472
|
+
this.resource = await this.filesystem.createFile(KeymapService_1.KEYMAP_FILE_URI.toString());
|
|
473
|
+
}
|
|
474
|
+
// 更新当前文件资源
|
|
475
|
+
const stat = await this.filesystem.setContent(this.resource, JSON.stringify(keymaps, undefined, 2));
|
|
476
|
+
this.resource = stat || undefined;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* 从keymaps.json获取快捷键列表
|
|
480
|
+
* @returns {Promise<Keybinding[]>}
|
|
481
|
+
* @memberof KeymapsService
|
|
482
|
+
*/
|
|
483
|
+
async getKeybindings() {
|
|
484
|
+
return this.storeKeybindings.map((keymap) => ({
|
|
485
|
+
command: keymap.command,
|
|
486
|
+
keybinding: keymap.key,
|
|
487
|
+
when: keymap.when,
|
|
488
|
+
args: keymap.args,
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* 打开快捷键面板
|
|
493
|
+
* @protected
|
|
494
|
+
* @returns {Promise<void>}
|
|
495
|
+
* @memberof KeymapService
|
|
496
|
+
*/
|
|
497
|
+
async open() {
|
|
498
|
+
this.commandService.executeCommand(ide_core_browser_1.EDITOR_COMMANDS.OPEN_RESOURCE.id, new ide_core_browser_1.URI().withScheme(common_1.KEYMAPS_SCHEME), { preview: true });
|
|
499
|
+
}
|
|
500
|
+
getWhen(keybinding) {
|
|
501
|
+
if (!keybinding) {
|
|
502
|
+
return '';
|
|
503
|
+
}
|
|
504
|
+
return this.keybindingService.convertMonacoWhen(keybinding.when);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* 获取可读的作用域
|
|
508
|
+
* @param {KeybindingScope} scope
|
|
509
|
+
* @returns
|
|
510
|
+
* @memberof KeymapService
|
|
511
|
+
*/
|
|
512
|
+
getScope(scope) {
|
|
513
|
+
if (scope === ide_core_browser_1.KeybindingScope.DEFAULT) {
|
|
514
|
+
return (0, ide_core_browser_1.localize)('keymaps.source.default');
|
|
515
|
+
}
|
|
516
|
+
else if (scope === ide_core_browser_1.KeybindingScope.USER) {
|
|
517
|
+
return (0, ide_core_browser_1.localize)('keymaps.source.user');
|
|
518
|
+
}
|
|
519
|
+
else if (scope === ide_core_browser_1.KeybindingScope.WORKSPACE) {
|
|
520
|
+
return (0, ide_core_browser_1.localize)('keymaps.source.workspace');
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
return '';
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* 获取所有快捷键项
|
|
528
|
+
* @returns {KeybindingItem[]}
|
|
529
|
+
* @memberof KeymapService
|
|
530
|
+
*/
|
|
531
|
+
getKeybindingItems() {
|
|
532
|
+
const commands = this.commandRegistry.getCommands();
|
|
533
|
+
const items = [];
|
|
534
|
+
for (const command of commands) {
|
|
535
|
+
const keybindings = this.keybindingRegistry.getKeybindingsForCommand(command.id);
|
|
536
|
+
if (!keybindings || !keybindings.length) {
|
|
537
|
+
// 针对带有label的Command,在快捷键面板上添加可配置按钮
|
|
538
|
+
if (command.label) {
|
|
539
|
+
items.push({
|
|
540
|
+
id: command.id,
|
|
541
|
+
command: command.label,
|
|
542
|
+
hasCommandLabel: true,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
keybindings.forEach((kd) => {
|
|
548
|
+
let item;
|
|
549
|
+
if (this.storeKeybindings) {
|
|
550
|
+
const isUserKeybinding = this.storeKeybindings.find((kb) => command && kb.command === command.id);
|
|
551
|
+
item = {
|
|
552
|
+
id: command.id,
|
|
553
|
+
command: command.label || command.id,
|
|
554
|
+
keybinding: isUserKeybinding ? isUserKeybinding.key : kd ? this.keybindingRegistry.acceleratorFor(kd, '+').join(' ') : '',
|
|
555
|
+
when: isUserKeybinding ? this.getWhen(isUserKeybinding) : this.getWhen((keybindings && kd)),
|
|
556
|
+
source: isUserKeybinding ? this.getScope(ide_core_browser_1.KeybindingScope.USER) : this.getScope(ide_core_browser_1.KeybindingScope.DEFAULT),
|
|
557
|
+
hasCommandLabel: !!command.label,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
item = {
|
|
562
|
+
id: command.id,
|
|
563
|
+
command: command.label || command.id,
|
|
564
|
+
keybinding: (keybindings && kd) ? this.keybindingRegistry.acceleratorFor(kd, '+').join(' ') : '',
|
|
565
|
+
when: this.getWhen((keybindings && kd)),
|
|
566
|
+
source: (keybindings && kd && typeof kd.scope !== 'undefined')
|
|
567
|
+
? this.getScope(kd.scope) : '',
|
|
568
|
+
hasCommandLabel: !!command.label,
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
items.push(item);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
// 获取排序后的列表
|
|
576
|
+
const sorted = items.sort((a, b) => this.compareItem(a, b));
|
|
577
|
+
// 获取定义了快捷键的列表
|
|
578
|
+
const keyItems = sorted.filter((a) => !!a.keybinding);
|
|
579
|
+
const otherItems = sorted.filter((a) => !a.keybinding && a.hasCommandLabel);
|
|
580
|
+
// 让带有 Label 的快捷键命令排序靠前
|
|
581
|
+
const withLabelItems = keyItems.filter((keybinding) => keybinding.hasCommandLabel);
|
|
582
|
+
const withoutLabelItems = keyItems.filter((keybinding) => !keybinding.hasCommandLabel);
|
|
583
|
+
return [...withLabelItems, ...withoutLabelItems, ...otherItems];
|
|
584
|
+
}
|
|
585
|
+
// 字典排序
|
|
586
|
+
compareItem(a, b) {
|
|
587
|
+
if (a && b) {
|
|
588
|
+
if (a.source === b.source) {
|
|
589
|
+
return (a.command.toLowerCase()).localeCompare(b.command.toLowerCase());
|
|
590
|
+
}
|
|
591
|
+
else if (a.source === this.getScope(ide_core_browser_1.KeybindingScope.USER)) {
|
|
592
|
+
return -1;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
return 1;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return 0;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* 获取被fuzzy替换的原始值
|
|
602
|
+
* @param {string} keybinding
|
|
603
|
+
*/
|
|
604
|
+
getRaw(keybinding) {
|
|
605
|
+
if (!keybinding) {
|
|
606
|
+
return '';
|
|
607
|
+
}
|
|
608
|
+
return keybinding.replace(new RegExp(/<(\/)?match>/ig), '');
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
KeymapService.DEFAULT_SEARCH_DELAY = 500;
|
|
612
|
+
KeymapService.KEYMAP_FILE_URI = new ide_core_browser_1.URI().withScheme(ide_preferences_1.USER_STORAGE_SCHEME).withPath(common_1.KEYMAPS_FILE_NAME);
|
|
613
|
+
(0, tslib_1.__decorate)([
|
|
614
|
+
(0, di_1.Autowired)(ide_core_browser_1.KeybindingRegistry),
|
|
615
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
616
|
+
], KeymapService.prototype, "keyBindingRegistry", void 0);
|
|
617
|
+
(0, tslib_1.__decorate)([
|
|
618
|
+
(0, di_1.Autowired)(keymaps_parser_1.KeymapsParser),
|
|
619
|
+
(0, tslib_1.__metadata)("design:type", keymaps_parser_1.KeymapsParser)
|
|
620
|
+
], KeymapService.prototype, "parser", void 0);
|
|
621
|
+
(0, tslib_1.__decorate)([
|
|
622
|
+
(0, di_1.Autowired)(ide_core_browser_1.CommandService),
|
|
623
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
624
|
+
], KeymapService.prototype, "commandService", void 0);
|
|
625
|
+
(0, tslib_1.__decorate)([
|
|
626
|
+
(0, di_1.Autowired)(ide_core_browser_1.CommandRegistry),
|
|
627
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
628
|
+
], KeymapService.prototype, "commandRegistry", void 0);
|
|
629
|
+
(0, tslib_1.__decorate)([
|
|
630
|
+
(0, di_1.Autowired)(ide_core_browser_1.KeybindingRegistry),
|
|
631
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
632
|
+
], KeymapService.prototype, "keybindingRegistry", void 0);
|
|
633
|
+
(0, tslib_1.__decorate)([
|
|
634
|
+
(0, di_1.Autowired)(ide_core_browser_1.KeybindingService),
|
|
635
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
636
|
+
], KeymapService.prototype, "keybindingService", void 0);
|
|
637
|
+
(0, tslib_1.__decorate)([
|
|
638
|
+
(0, di_1.Autowired)(ide_file_service_1.IFileServiceClient),
|
|
639
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
640
|
+
], KeymapService.prototype, "filesystem", void 0);
|
|
641
|
+
(0, tslib_1.__decorate)([
|
|
642
|
+
(0, di_1.Autowired)(ide_core_browser_1.ILogger),
|
|
643
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
644
|
+
], KeymapService.prototype, "logger", void 0);
|
|
645
|
+
(0, tslib_1.__decorate)([
|
|
646
|
+
(0, di_1.Autowired)(progress_1.IProgressService),
|
|
647
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
648
|
+
], KeymapService.prototype, "progressService", void 0);
|
|
649
|
+
(0, tslib_1.__decorate)([
|
|
650
|
+
mobx_1.observable.shallow,
|
|
651
|
+
(0, tslib_1.__metadata)("design:type", Array)
|
|
652
|
+
], KeymapService.prototype, "keybindings", void 0);
|
|
653
|
+
(0, tslib_1.__decorate)([
|
|
654
|
+
mobx_1.action,
|
|
655
|
+
(0, tslib_1.__metadata)("design:type", Function),
|
|
656
|
+
(0, tslib_1.__metadata)("design:paramtypes", []),
|
|
657
|
+
(0, tslib_1.__metadata)("design:returntype", void 0)
|
|
658
|
+
], KeymapService.prototype, "updateKeybindings", null);
|
|
659
|
+
(0, tslib_1.__decorate)([
|
|
660
|
+
mobx_1.action,
|
|
661
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
662
|
+
], KeymapService.prototype, "searchKeybindings", void 0);
|
|
663
|
+
(0, tslib_1.__decorate)([
|
|
664
|
+
mobx_1.action,
|
|
665
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
666
|
+
], KeymapService.prototype, "doSearchKeybindings", void 0);
|
|
667
|
+
KeymapService = KeymapService_1 = (0, tslib_1.__decorate)([
|
|
668
|
+
(0, di_1.Injectable)()
|
|
669
|
+
], KeymapService);
|
|
670
|
+
exports.KeymapService = KeymapService;
|
|
671
|
+
//# sourceMappingURL=keymaps.service.js.map
|