@opensumi/ide-core-common 2.21.13 → 2.22.0
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/command.d.ts +15 -5
- package/lib/command.d.ts.map +1 -1
- package/lib/command.js +11 -1
- package/lib/command.js.map +1 -1
- package/lib/const/application.d.ts +6 -1
- package/lib/const/application.d.ts.map +1 -1
- package/lib/const/application.js +8 -3
- package/lib/const/application.js.map +1 -1
- package/lib/declare.d.ts +2 -2
- package/lib/declare.d.ts.map +1 -1
- package/lib/editor.d.ts +4 -0
- package/lib/editor.d.ts.map +1 -1
- package/lib/electron.d.ts +1 -1
- package/lib/electron.d.ts.map +1 -1
- package/lib/event-bus/event-bus-types.d.ts +1 -1
- package/lib/event-bus/event-bus-types.d.ts.map +1 -1
- package/lib/event-bus/event-bus.js.map +1 -1
- package/lib/event-bus/event-decorator.js.map +1 -1
- package/lib/extension.schema.d.ts +1 -1
- package/lib/extension.schema.d.ts.map +1 -1
- package/lib/hash-calculate/WASMInterface.d.ts +2 -2
- package/lib/hash-calculate/WASMInterface.d.ts.map +1 -1
- package/lib/hash-calculate/hash-calculate.js.map +1 -1
- package/lib/hash-calculate/util.d.ts +2 -2
- package/lib/hash-calculate/util.d.ts.map +1 -1
- package/lib/json-schema.d.ts +9 -0
- package/lib/json-schema.d.ts.map +1 -1
- package/lib/keyboard/keymap.d.ts +1 -1
- package/lib/keyboard/keymap.d.ts.map +1 -1
- package/lib/localize.d.ts +1 -1
- package/lib/localize.d.ts.map +1 -1
- package/lib/log.d.ts +2 -2
- package/lib/log.d.ts.map +1 -1
- package/lib/mime.d.ts +6 -6
- package/lib/module.js.map +1 -1
- package/lib/preferences/preference-schema.d.ts +13 -3
- package/lib/preferences/preference-schema.d.ts.map +1 -1
- package/lib/preferences/preference-schema.js +11 -1
- package/lib/preferences/preference-schema.js.map +1 -1
- package/lib/preferences/preference-scope.d.ts +8 -1
- package/lib/preferences/preference-scope.d.ts.map +1 -1
- package/lib/preferences/preference-scope.js +11 -2
- package/lib/preferences/preference-scope.js.map +1 -1
- package/lib/problem-matcher.d.ts +1 -1
- package/lib/problem-matcher.d.ts.map +1 -1
- package/lib/problem-matcher.js.map +1 -1
- package/lib/problem-pattern.d.ts +4 -2
- package/lib/problem-pattern.d.ts.map +1 -1
- package/lib/problem-pattern.js +24 -1
- package/lib/problem-pattern.js.map +1 -1
- package/lib/reference.d.ts +2 -1
- package/lib/reference.d.ts.map +1 -1
- package/lib/reference.js +11 -6
- package/lib/reference.js.map +1 -1
- package/lib/reporter.js.map +1 -1
- package/lib/storage.d.ts +1 -1
- package/lib/storage.d.ts.map +1 -1
- package/lib/storage.js.map +1 -1
- package/lib/task-definition.js.map +1 -1
- package/lib/types/common.d.ts +1 -1
- package/lib/types/common.d.ts.map +1 -1
- package/lib/types/editor.d.ts +2 -2
- package/lib/types/editor.d.ts.map +1 -1
- package/lib/types/file-watch.d.ts +1 -1
- package/lib/types/file-watch.d.ts.map +1 -1
- package/lib/types/markers/markers-manager.d.ts.map +1 -1
- package/lib/types/markers/markers-manager.js +4 -10
- package/lib/types/markers/markers-manager.js.map +1 -1
- package/lib/types/markers/markers.d.ts +2 -0
- package/lib/types/markers/markers.d.ts.map +1 -1
- package/lib/types/markers/markers.js.map +1 -1
- package/package.json +7 -6
- package/src/LifeCyclePhase.ts +6 -0
- package/src/application-error.ts +77 -0
- package/src/application-props.ts +28 -0
- package/src/application.lifecycle.ts +15 -0
- package/src/browser-fs/ensure-dir.ts +46 -0
- package/src/browser-fs/util.ts +52 -0
- package/src/clipboard.ts +31 -0
- package/src/command.ts +726 -0
- package/src/commands/terminal.ts +0 -0
- package/src/comparers.ts +152 -0
- package/src/connection.ts +7 -0
- package/src/const/application.ts +11 -0
- package/src/const/index.ts +1 -0
- package/src/contribution-provider.ts +47 -0
- package/src/credential.ts +21 -0
- package/src/crypto.ts +8 -0
- package/src/declare.ts +3 -0
- package/src/di-helper/domain-helper.ts +48 -0
- package/src/di-helper/index.ts +1 -0
- package/src/editor.ts +6 -0
- package/src/electron.ts +168 -0
- package/src/env.ts +1 -0
- package/src/event-bus/basic-event.ts +3 -0
- package/src/event-bus/event-bus-types.ts +68 -0
- package/src/event-bus/event-bus.ts +57 -0
- package/src/event-bus/event-decorator.ts +32 -0
- package/src/event-bus/index.ts +4 -0
- package/src/extension.schema.ts +16 -0
- package/src/hash-calculate/WASMInterface.ts +266 -0
- package/src/hash-calculate/hash-calculate.ts +53 -0
- package/src/hash-calculate/lockedCreate.ts +17 -0
- package/src/hash-calculate/md5.wasm.json +1 -0
- package/src/hash-calculate/mutex.ts +30 -0
- package/src/hash-calculate/util.ts +190 -0
- package/src/id-generator.ts +15 -0
- package/src/index.ts +39 -0
- package/src/json-schema.ts +80 -0
- package/src/keyboard/index.ts +2 -0
- package/src/keyboard/keyboard-layout-provider.ts +46 -0
- package/src/keyboard/keymap.ts +224 -0
- package/src/line-text.ts +93 -0
- package/src/localize.ts +203 -0
- package/src/log.ts +338 -0
- package/src/markdown.ts +8 -0
- package/src/menu.ts +31 -0
- package/src/mime.ts +8 -0
- package/src/mocks/electron/browserMock.ts +10 -0
- package/src/mocks/electron/ipcRenderer.ts +30 -0
- package/src/module.ts +31 -0
- package/src/network.ts +47 -0
- package/src/node/cli.ts +5 -0
- package/src/node/port.ts +134 -0
- package/src/preferences/index.ts +2 -0
- package/src/preferences/preference-schema.ts +122 -0
- package/src/preferences/preference-scope.ts +65 -0
- package/src/problem-matcher.ts +389 -0
- package/src/problem-pattern.ts +574 -0
- package/src/range.ts +24 -0
- package/src/reference.ts +141 -0
- package/src/reporter.ts +64 -0
- package/src/settings/general.ts +5 -0
- package/src/settings/index.ts +3 -0
- package/src/settings/search.ts +7 -0
- package/src/settings/terminal.ts +9 -0
- package/src/storage.ts +99 -0
- package/src/task-definition.ts +172 -0
- package/src/theme.ts +7 -0
- package/src/types/accessibility.ts +4 -0
- package/src/types/application.ts +14 -0
- package/src/types/authentication.ts +120 -0
- package/src/types/common.ts +14 -0
- package/src/types/dnd.ts +8 -0
- package/src/types/editor.ts +246 -0
- package/src/types/extension.ts +96 -0
- package/src/types/file-watch.ts +100 -0
- package/src/types/file.ts +262 -0
- package/src/types/index.ts +15 -0
- package/src/types/markdown.ts +10 -0
- package/src/types/markers/index.ts +2 -0
- package/src/types/markers/markers-manager.ts +392 -0
- package/src/types/markers/markers.ts +125 -0
- package/src/types/message.ts +6 -0
- package/src/types/reporter.ts +96 -0
- package/src/types/statusbar.ts +6 -0
- package/src/types/string.ts +3 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/ipc.ts +28 -0
package/src/command.ts
ADDED
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { Disposable, Emitter, Event, IDisposable, MaybePromise } from '@opensumi/ide-utils';
|
|
3
|
+
|
|
4
|
+
import { ContributionProvider } from './contribution-provider';
|
|
5
|
+
import { replaceLocalizePlaceholder } from './localize';
|
|
6
|
+
import { getDebugLogger } from './log';
|
|
7
|
+
import { IExtensionInfo } from './types';
|
|
8
|
+
|
|
9
|
+
export interface Command {
|
|
10
|
+
/**
|
|
11
|
+
* 命令 id,全局唯一
|
|
12
|
+
*/
|
|
13
|
+
id: string;
|
|
14
|
+
/**
|
|
15
|
+
* 要在命令面板显示的文案
|
|
16
|
+
* 支持国际化占位符,例如 %evenEditorGroups%
|
|
17
|
+
*/
|
|
18
|
+
label?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 要在命令面板显示的较短的文案
|
|
21
|
+
* 支持国际化占位符,例如 %evenEditorGroups%
|
|
22
|
+
*/
|
|
23
|
+
shortLabel?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 要在命令面板显示的图标
|
|
26
|
+
*/
|
|
27
|
+
iconClass?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 要在命令面板显示的图标
|
|
30
|
+
*/
|
|
31
|
+
toogleIconClass?: string;
|
|
32
|
+
/**
|
|
33
|
+
* 要在命令面板显示的分组
|
|
34
|
+
* 支持国际化占位符,例如 %evenEditorGroups%
|
|
35
|
+
*/
|
|
36
|
+
category?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 代理执行的命令
|
|
40
|
+
*/
|
|
41
|
+
delegate?: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 在任意语言下都相同的别名
|
|
45
|
+
*/
|
|
46
|
+
alias?: string;
|
|
47
|
+
/**
|
|
48
|
+
* 在任意语言下都相同的分类名
|
|
49
|
+
*/
|
|
50
|
+
aliasCategory?: string;
|
|
51
|
+
/**
|
|
52
|
+
* 是否启用该命令,值为 when 表达式
|
|
53
|
+
* 这个值只影响 UI 是否展示 (命令面板或者菜单)
|
|
54
|
+
*/
|
|
55
|
+
enablement?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Command 的工具方法
|
|
60
|
+
*/
|
|
61
|
+
export namespace Command {
|
|
62
|
+
/**
|
|
63
|
+
* 判断是否是命令
|
|
64
|
+
* @param arg 要判断的对象
|
|
65
|
+
*/
|
|
66
|
+
export function is(arg: Command | any): arg is Command {
|
|
67
|
+
return !!arg && arg === Object(arg) && 'id' in arg;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 比较两个命令是否相等
|
|
72
|
+
* 用于命令面板的排序
|
|
73
|
+
* @param a 待比较的命令
|
|
74
|
+
* @param b 待比较的命令
|
|
75
|
+
*/
|
|
76
|
+
export function compareCommands(a: Command, b: Command): number {
|
|
77
|
+
if (a.label && b.label) {
|
|
78
|
+
const aCommand = a.category ? a.category + a.label : a.label;
|
|
79
|
+
const bCommand = b.category ? b.category + b.label : b.label;
|
|
80
|
+
return aCommand.localeCompare(bCommand);
|
|
81
|
+
} else {
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 命令处理函数接口
|
|
89
|
+
*/
|
|
90
|
+
export interface CommandHandler<T = any> {
|
|
91
|
+
/**
|
|
92
|
+
* 命令执行函数
|
|
93
|
+
* @param args 传递的参数
|
|
94
|
+
*/
|
|
95
|
+
execute: T;
|
|
96
|
+
/**
|
|
97
|
+
* 命令是否启用
|
|
98
|
+
* 若为否,则不会被执行到
|
|
99
|
+
* 并且命令面板也不会显示
|
|
100
|
+
* @param args 传递的参数
|
|
101
|
+
*/
|
|
102
|
+
isEnabled?(...args: any[]): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* 命令是否可见
|
|
105
|
+
* 若为否,则不会再命令面板显示
|
|
106
|
+
* 但是可以被外部执行
|
|
107
|
+
* @param args 传递的参数
|
|
108
|
+
*/
|
|
109
|
+
isVisible?(...args: any[]): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* 是否可切换
|
|
112
|
+
* 主要给菜单使用
|
|
113
|
+
* @param args
|
|
114
|
+
*/
|
|
115
|
+
isToggled?(...args: any[]): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* 获取鉴过权的命令处理函数
|
|
118
|
+
* @param commandId 命令 id
|
|
119
|
+
* @param extensionInfo 插件的主要属性
|
|
120
|
+
* @param args 命令其他参数
|
|
121
|
+
*/
|
|
122
|
+
isPermitted?(extensionInfo: IExtensionInfo, ...args: any[]): boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const CommandContribution = Symbol('CommandContribution');
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 命令贡献 Contribution
|
|
129
|
+
* 其他模块如果要注册命令需要实现该接口,并且把 Symbol 定义加入 Domain
|
|
130
|
+
*/
|
|
131
|
+
export interface CommandContribution {
|
|
132
|
+
/**
|
|
133
|
+
* 注册命令
|
|
134
|
+
*/
|
|
135
|
+
registerCommands(commands: CommandRegistry): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
type PostInterceptorFunction = (result: any) => MaybePromise<any>;
|
|
139
|
+
type PreInterceptorFunction = (args: any[]) => MaybePromise<any[] | boolean>;
|
|
140
|
+
|
|
141
|
+
export type PreCommandInterceptor = (command: string, args: any[]) => MaybePromise<any[] | boolean>;
|
|
142
|
+
export type PostCommandInterceptor = (command: string, result: any) => MaybePromise<any>;
|
|
143
|
+
|
|
144
|
+
export const CommandService = Symbol('CommandService');
|
|
145
|
+
export const CommandRegistry = Symbol('CommandRegistry');
|
|
146
|
+
|
|
147
|
+
export const HANDLER_NOT_FOUND = 'HANDLER_NOT_FOUND';
|
|
148
|
+
|
|
149
|
+
export interface ICommandEvent {
|
|
150
|
+
commandId: string;
|
|
151
|
+
args: any[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 命令执行模块
|
|
156
|
+
*/
|
|
157
|
+
export interface CommandService {
|
|
158
|
+
executeCommand<T>(commandId: string, ...args: any[]): Promise<T | undefined>;
|
|
159
|
+
/**
|
|
160
|
+
* 执行命令将报错 catch 并 log 输出
|
|
161
|
+
*/
|
|
162
|
+
tryExecuteCommand<T>(commandId: string, ...args: any[]): Promise<T | undefined>;
|
|
163
|
+
onWillExecuteCommand: Event<ICommandEvent>;
|
|
164
|
+
onDidExecuteCommand: Event<ICommandEvent>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 命令注册和管理模块
|
|
169
|
+
*/
|
|
170
|
+
interface CoreCommandRegistry {
|
|
171
|
+
/**
|
|
172
|
+
* 注册命令
|
|
173
|
+
* @param command 要注册的命令
|
|
174
|
+
* @param handler 要绑定的执行函数,可延后添加
|
|
175
|
+
* @returns 销毁命令的方法
|
|
176
|
+
*/
|
|
177
|
+
registerCommand<T = any>(command: Command, handler?: CommandHandler<T>): IDisposable;
|
|
178
|
+
updateCommandDetailById(id: string, command: Partial<Command>): void;
|
|
179
|
+
/**
|
|
180
|
+
* 解绑命令
|
|
181
|
+
* @param commandOrId 要解绑命令或命令 id
|
|
182
|
+
*/
|
|
183
|
+
unregisterCommand(commandOrId: Command | string): void;
|
|
184
|
+
/**
|
|
185
|
+
* 给命令注册处理函数
|
|
186
|
+
* 可以给命令加多个处理函数
|
|
187
|
+
* @param commandId 要添加的命令 id
|
|
188
|
+
* @param handler 要添加的处理函数
|
|
189
|
+
*/
|
|
190
|
+
registerHandler<T = any>(commandId: string, handler: CommandHandler<T>): IDisposable;
|
|
191
|
+
/**
|
|
192
|
+
* 通过命令 id 获取命令
|
|
193
|
+
* @param commandId 命令 id
|
|
194
|
+
*/
|
|
195
|
+
getCommand(commandId: string): Command | undefined;
|
|
196
|
+
getRawCommand(commandId: string): Command | undefined;
|
|
197
|
+
/**
|
|
198
|
+
* 获取所有命令
|
|
199
|
+
*/
|
|
200
|
+
getCommands(): Command[];
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 判断命令是否启用
|
|
204
|
+
* @param commandId 命令 id
|
|
205
|
+
* @param args 传递参数
|
|
206
|
+
*/
|
|
207
|
+
isEnabled(commandId: string, ...args: any[]): boolean;
|
|
208
|
+
/**
|
|
209
|
+
* 判断命令是否可见
|
|
210
|
+
* @param commandId 命令 id
|
|
211
|
+
* @param args 传递参数
|
|
212
|
+
*/
|
|
213
|
+
isVisible(commandId: string, ...args: any[]): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* 判断命令是否可切换
|
|
216
|
+
* @param commandId 命令 id
|
|
217
|
+
*/
|
|
218
|
+
isToggled(commandId: string, ...args: any[]): boolean;
|
|
219
|
+
/**
|
|
220
|
+
* 判断命令是否启用
|
|
221
|
+
* @param commandId 命令 id
|
|
222
|
+
* @param args
|
|
223
|
+
*/
|
|
224
|
+
getActiveHandler(commandId: string, ...args: any[]): CommandHandler | undefined;
|
|
225
|
+
/**
|
|
226
|
+
* 获取最近使用的命令列表
|
|
227
|
+
*/
|
|
228
|
+
getRecentCommands(): Command[];
|
|
229
|
+
/**
|
|
230
|
+
* 设置最近使用的命令列表
|
|
231
|
+
*/
|
|
232
|
+
setRecentCommands(commands: Command[]): Command[];
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 为特定的命令注册前置拦截器
|
|
236
|
+
*
|
|
237
|
+
* 拦截器的入参是该命令的参数数组,请返回修改后的参数数组或者返回 false 来拦截本次执行
|
|
238
|
+
*/
|
|
239
|
+
beforeExecuteCommand(commandId: string, interceptorFunc: PreInterceptorFunction): IDisposable;
|
|
240
|
+
/**
|
|
241
|
+
* 可以为命令添加拦截器
|
|
242
|
+
* 拦截器的入参是该命令的参数数组,请返回修改后的参数数组或者返回 false 来拦截本次执行
|
|
243
|
+
* @param interceptor 每个 command 都会执行一遍
|
|
244
|
+
*/
|
|
245
|
+
beforeExecuteCommand(interceptor: PreCommandInterceptor): IDisposable;
|
|
246
|
+
afterExecuteCommand(commandId: string, interceptorFunc: PostInterceptorFunction): IDisposable;
|
|
247
|
+
afterExecuteCommand(interceptor: PostCommandInterceptor): IDisposable;
|
|
248
|
+
/**
|
|
249
|
+
* 是否是通过鉴过权的命令
|
|
250
|
+
* @param commandId
|
|
251
|
+
* @param extensionInfo
|
|
252
|
+
* @param args
|
|
253
|
+
*/
|
|
254
|
+
isPermittedCommand(commandId: string, extensionInfo: IExtensionInfo, ...args: any[]): boolean;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export interface CommandRegistry extends CoreCommandRegistry {
|
|
258
|
+
/**
|
|
259
|
+
* 从 ContributionProvide 中拿到执行命令 Contributuon
|
|
260
|
+
* 执行注册操作
|
|
261
|
+
*/
|
|
262
|
+
initialize(): void;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 不带 contribution 的 CommandRegistry
|
|
266
|
+
@Injectable()
|
|
267
|
+
export class CoreCommandRegistryImpl implements CoreCommandRegistry {
|
|
268
|
+
protected readonly _commands: { [id: string]: Command } = {};
|
|
269
|
+
protected readonly _handlers: { [id: string]: CommandHandler[] } = {};
|
|
270
|
+
|
|
271
|
+
protected readonly unregisterCommands = new Map<string, Disposable>();
|
|
272
|
+
// 最近执行的命令列表
|
|
273
|
+
protected readonly _recent: Command[] = [];
|
|
274
|
+
|
|
275
|
+
public readonly preCommandInterceptors: PreCommandInterceptor[] = [];
|
|
276
|
+
|
|
277
|
+
public readonly postCommandInterceptors: PostCommandInterceptor[] = [];
|
|
278
|
+
|
|
279
|
+
private readonly preCommandInterceptorMap = new Map<string, PreInterceptorFunction[]>();
|
|
280
|
+
private readonly postCommandInterceptor = new Map<string, PostInterceptorFunction[]>();
|
|
281
|
+
|
|
282
|
+
private readonly logger = getDebugLogger();
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 命令执行方法
|
|
286
|
+
* @param commandId 命令执行方法
|
|
287
|
+
* @param args
|
|
288
|
+
*/
|
|
289
|
+
async executeCommand<T>(commandId: string, ...args: any[]): Promise<T | undefined> {
|
|
290
|
+
const command = this.getCommand(commandId);
|
|
291
|
+
// 执行代理命令。即该命令是另一个命令的 alias,这里转为执行真实的命令
|
|
292
|
+
if (command && command.delegate) {
|
|
293
|
+
return this.executeCommand<T>(command.delegate, ...args);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 把 before 在 handler 判断前置,对于 onCommand 激活的插件如果没有在 contributes 配置,那么 handler 是不存在的,也就无法激活
|
|
297
|
+
// 如 node debug 插件 https://github.com/microsoft/vscode-node-debug/blob/main/package.json
|
|
298
|
+
const _preCommandInterceptor = this.preCommandInterceptorMap.get(commandId);
|
|
299
|
+
const preInterceptorWrapper = (_preCommandInterceptor ?? []).map((cb) => (_, args) => cb(args));
|
|
300
|
+
const currentPreInterceptors = [...preInterceptorWrapper, ...this.preCommandInterceptors];
|
|
301
|
+
for (const preInterceptor of currentPreInterceptors) {
|
|
302
|
+
const result = await preInterceptor(commandId, args);
|
|
303
|
+
if (result === false) {
|
|
304
|
+
this.logger.log(`command ${commandId} is prevented by pre interceptor`, preInterceptor.name);
|
|
305
|
+
return undefined;
|
|
306
|
+
} else if (Array.isArray(result)) {
|
|
307
|
+
args = result;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const handler = this.getActiveHandler(commandId, ...args);
|
|
311
|
+
if (handler) {
|
|
312
|
+
let result = await handler.execute(...args);
|
|
313
|
+
const commandInterceptor = this.postCommandInterceptor.get(commandId);
|
|
314
|
+
if (commandInterceptor) {
|
|
315
|
+
for (const postInterceptor of commandInterceptor) {
|
|
316
|
+
result = await postInterceptor(result);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
for (const postCommand of this.postCommandInterceptors) {
|
|
320
|
+
result = await postCommand(commandId, result);
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
let argsMessage = '';
|
|
325
|
+
try {
|
|
326
|
+
argsMessage = args && args.length > 0 ? ` (args: ${JSON.stringify(args)})` : '';
|
|
327
|
+
} catch (e) {
|
|
328
|
+
argsMessage = 'args cannot be convert to JSON';
|
|
329
|
+
}
|
|
330
|
+
const err = new Error(
|
|
331
|
+
`The command '${commandId}' cannot be executed. There are no active handlers available for the command.${argsMessage}`,
|
|
332
|
+
);
|
|
333
|
+
err.name = HANDLER_NOT_FOUND;
|
|
334
|
+
throw err;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* 获取所有命令
|
|
339
|
+
*/
|
|
340
|
+
getCommands(): Command[] {
|
|
341
|
+
return Object.keys(this._commands).map((id) => this.getCommand(id)!);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* 注册命令,命令不能重复注册
|
|
346
|
+
* @param command
|
|
347
|
+
* @param handler
|
|
348
|
+
* @returns 命令销毁函数
|
|
349
|
+
*/
|
|
350
|
+
registerCommand<T>(command: Command, handler?: CommandHandler<T>): IDisposable {
|
|
351
|
+
if (this._commands[command.id]) {
|
|
352
|
+
this.logger.warn(`A command ${command.id} is already registered.`);
|
|
353
|
+
return Disposable.NULL;
|
|
354
|
+
}
|
|
355
|
+
const toDispose = new Disposable();
|
|
356
|
+
// 添加命令的销毁函数
|
|
357
|
+
toDispose.addDispose(this.doRegisterCommand(command));
|
|
358
|
+
if (handler) {
|
|
359
|
+
// 添加处理函数的销毁函数
|
|
360
|
+
toDispose.addDispose(this.registerHandler(command.id, handler));
|
|
361
|
+
}
|
|
362
|
+
// 添加解绑时的销毁逻辑
|
|
363
|
+
this.unregisterCommands.set(command.id, toDispose);
|
|
364
|
+
toDispose.addDispose(Disposable.create(() => this.unregisterCommands.delete(command.id)));
|
|
365
|
+
return toDispose;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 有时候我们需要在命令注册后才更新其描述。
|
|
370
|
+
*
|
|
371
|
+
* 比如说我们会为所有的 ContainerId 注册 Toggle Panel 的命令,但我们不想在 QuickOpen 中展示所有 ContainerId 对应的命令
|
|
372
|
+
* 这个时候我们可以先注册所有命令,然后再更新所有 Command 的描述
|
|
373
|
+
* @param id 命令 ID
|
|
374
|
+
* @param command
|
|
375
|
+
*/
|
|
376
|
+
updateCommandDetailById(id: string, command: Partial<Command>): void {
|
|
377
|
+
if (!this._commands[id]) {
|
|
378
|
+
this.logger.warn(`Command ${id} not found.`);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
this._commands[id] = {
|
|
383
|
+
...this._commands[id],
|
|
384
|
+
...command,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* 解绑命令
|
|
390
|
+
* @param command 命令
|
|
391
|
+
*/
|
|
392
|
+
unregisterCommand(command: Command): void;
|
|
393
|
+
/**
|
|
394
|
+
* 解绑命令
|
|
395
|
+
* @param id 命令 id
|
|
396
|
+
*/
|
|
397
|
+
unregisterCommand(commandOrId: Command | string): void {
|
|
398
|
+
const id = Command.is(commandOrId) ? commandOrId.id : commandOrId;
|
|
399
|
+
const unregisterCommand = this.unregisterCommands.get(id);
|
|
400
|
+
if (unregisterCommand) {
|
|
401
|
+
unregisterCommand.dispose();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 给命令注册处理函数
|
|
407
|
+
* 可以给命令加多个处理函数
|
|
408
|
+
* 默认后面注册的优先级更高
|
|
409
|
+
* @param commandId 要添加的命令 id
|
|
410
|
+
* @param handler 要添加的处理函数
|
|
411
|
+
* @returns 销毁函数
|
|
412
|
+
*/
|
|
413
|
+
registerHandler<T>(commandId: string, handler: CommandHandler<T>): IDisposable {
|
|
414
|
+
let handlers = this._handlers[commandId];
|
|
415
|
+
if (!handlers) {
|
|
416
|
+
this._handlers[commandId] = handlers = [];
|
|
417
|
+
}
|
|
418
|
+
handlers.unshift(handler);
|
|
419
|
+
return {
|
|
420
|
+
dispose: () => {
|
|
421
|
+
const idx = handlers.indexOf(handler);
|
|
422
|
+
if (idx >= 0) {
|
|
423
|
+
handlers.splice(idx, 1);
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* 判断命令是否启用
|
|
431
|
+
* @param commandId 命令 id
|
|
432
|
+
* @param args 传递参数
|
|
433
|
+
*/
|
|
434
|
+
isEnabled(command: string, ...args: any[]): boolean {
|
|
435
|
+
if (!this._handlers[command]) {
|
|
436
|
+
// 对于插件package.json中注册的command,会没有handler,
|
|
437
|
+
// 但是它应该可用,这样才能让插件在未启动的情况下点击菜单
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
return this.getActiveHandler(command, ...args) !== undefined;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* 判断命令是否可见
|
|
445
|
+
* @param commandId 命令 id
|
|
446
|
+
* @param args 传递参数
|
|
447
|
+
*/
|
|
448
|
+
isVisible(command: string, ...args: any[]): boolean {
|
|
449
|
+
if (!this._handlers[command]) {
|
|
450
|
+
// 对于插件package.json中注册的command,会没有handler,
|
|
451
|
+
// 但是它应该可见,这样才能让插件在未启动的情况下显示菜单
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
return this.getVisibleHandler(command, ...args) !== undefined;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* 是否可切换
|
|
459
|
+
* 主要给菜单使用
|
|
460
|
+
* @param commandId 命令 id
|
|
461
|
+
* @param args 传递参数
|
|
462
|
+
*/
|
|
463
|
+
isToggled(command: string, ...args: any[]): boolean {
|
|
464
|
+
const handler = this.getToggledHandler(command);
|
|
465
|
+
return handler && handler.isToggled ? handler.isToggled(...args) : false;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* 获取可见的命令处理函数
|
|
470
|
+
* @param commandId 命令 id
|
|
471
|
+
* @param args 传递参数
|
|
472
|
+
*/
|
|
473
|
+
protected getVisibleHandler(commandId: string, ...args: any[]): CommandHandler | undefined {
|
|
474
|
+
const handlers = this._handlers[commandId];
|
|
475
|
+
if (handlers) {
|
|
476
|
+
for (const handler of handlers) {
|
|
477
|
+
if (!handler.isVisible || handler.isVisible(...args)) {
|
|
478
|
+
return handler;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return undefined;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* 获取启用的命令处理函数
|
|
487
|
+
* @param commandId 命令 id
|
|
488
|
+
* @param args
|
|
489
|
+
*/
|
|
490
|
+
getActiveHandler(commandId: string, ...args: any[]): CommandHandler | undefined {
|
|
491
|
+
const command = this.getCommand(commandId);
|
|
492
|
+
if (command && command.delegate) {
|
|
493
|
+
return this.getActiveHandler(command.delegate, ...args);
|
|
494
|
+
}
|
|
495
|
+
const handlers = this._handlers[commandId];
|
|
496
|
+
if (handlers) {
|
|
497
|
+
for (const handler of handlers) {
|
|
498
|
+
if (!handler.isEnabled || handler.isEnabled(...args)) {
|
|
499
|
+
return handler;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* 获取鉴过权的命令处理函数
|
|
508
|
+
* @param commandId 命令 id
|
|
509
|
+
* @param extensionInfo 插件的主要属性
|
|
510
|
+
* @param args 命令其他参数
|
|
511
|
+
*/
|
|
512
|
+
isPermittedCommand(commandId: string, extensionInfo: IExtensionInfo, ...args: any[]): boolean {
|
|
513
|
+
const command = this.getCommand(commandId);
|
|
514
|
+
if (command && command.delegate) {
|
|
515
|
+
return this.isPermittedCommand(command.delegate, extensionInfo, ...args);
|
|
516
|
+
}
|
|
517
|
+
const handlers = this._handlers[commandId];
|
|
518
|
+
return (
|
|
519
|
+
!Array.isArray(handlers) ||
|
|
520
|
+
handlers.every((handler) => !handler.isPermitted || handler.isPermitted(extensionInfo, ...args))
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* 获取可切换的命令处理函数
|
|
526
|
+
* @param commandId 命令 id
|
|
527
|
+
*/
|
|
528
|
+
protected getToggledHandler(commandId: string): CommandHandler | undefined {
|
|
529
|
+
const handlers = this._handlers[commandId];
|
|
530
|
+
if (handlers) {
|
|
531
|
+
for (const handler of handlers) {
|
|
532
|
+
if (handler.isToggled) {
|
|
533
|
+
return handler;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return undefined;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* 解决语言包未加载时注册命令时没有 label/category 的场景
|
|
542
|
+
* 使用方需要自定处理 i18n 问题
|
|
543
|
+
*/
|
|
544
|
+
getRawCommand(id: string): Command | undefined {
|
|
545
|
+
const command = this._commands[id];
|
|
546
|
+
return command;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* 通过命令 id 获取命令
|
|
551
|
+
* @param commandId 命令 id
|
|
552
|
+
*/
|
|
553
|
+
getCommand(id: string): Command | undefined {
|
|
554
|
+
const command = this._commands[id];
|
|
555
|
+
return command
|
|
556
|
+
? {
|
|
557
|
+
...command,
|
|
558
|
+
label: replaceLocalizePlaceholder(command.label),
|
|
559
|
+
category: replaceLocalizePlaceholder(command.category),
|
|
560
|
+
}
|
|
561
|
+
: undefined;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* 给命令添加销毁函数
|
|
566
|
+
* @param command 要添加销毁函数的命令
|
|
567
|
+
*/
|
|
568
|
+
protected doRegisterCommand(command: Command): IDisposable {
|
|
569
|
+
this._commands[command.id] = command;
|
|
570
|
+
return {
|
|
571
|
+
dispose: () => {
|
|
572
|
+
delete this._commands[command.id];
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
beforeExecuteCommand(commandId: string, interceptorFunc: PreInterceptorFunction): IDisposable;
|
|
578
|
+
beforeExecuteCommand(interceptor: PreCommandInterceptor): IDisposable;
|
|
579
|
+
public beforeExecuteCommand(
|
|
580
|
+
interceptor: string | PreCommandInterceptor,
|
|
581
|
+
interceptorFunc?: PreInterceptorFunction,
|
|
582
|
+
): IDisposable {
|
|
583
|
+
if (typeof interceptor === 'string') {
|
|
584
|
+
const commandInterceptor = this.preCommandInterceptorMap.get(interceptor);
|
|
585
|
+
if (commandInterceptor) {
|
|
586
|
+
interceptorFunc && commandInterceptor.push(interceptorFunc);
|
|
587
|
+
} else {
|
|
588
|
+
interceptorFunc && this.preCommandInterceptorMap.set(interceptor, [interceptorFunc]);
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
dispose: () => {
|
|
592
|
+
const commandInterceptor = this.preCommandInterceptorMap.get(interceptor);
|
|
593
|
+
if (commandInterceptor && interceptorFunc) {
|
|
594
|
+
const index = commandInterceptor.indexOf(interceptorFunc);
|
|
595
|
+
if (index !== -1) {
|
|
596
|
+
commandInterceptor.splice(index, 1);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
} else {
|
|
602
|
+
this.preCommandInterceptors.push(interceptor);
|
|
603
|
+
return {
|
|
604
|
+
dispose: () => {
|
|
605
|
+
const index = this.preCommandInterceptors.indexOf(interceptor);
|
|
606
|
+
if (index !== -1) {
|
|
607
|
+
this.preCommandInterceptors.splice(index, 1);
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
afterExecuteCommand(commandId: string, interceptorFunc: PostInterceptorFunction): IDisposable;
|
|
615
|
+
afterExecuteCommand(interceptor: PostCommandInterceptor): IDisposable;
|
|
616
|
+
public afterExecuteCommand(interceptor: string | PostCommandInterceptor, result?: PostInterceptorFunction) {
|
|
617
|
+
if (typeof interceptor === 'string') {
|
|
618
|
+
const commandInterceptor = this.postCommandInterceptor.get(interceptor);
|
|
619
|
+
if (commandInterceptor) {
|
|
620
|
+
result && commandInterceptor.push(result);
|
|
621
|
+
} else {
|
|
622
|
+
result && this.postCommandInterceptor.set(interceptor, [result]);
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
dispose: () => {
|
|
626
|
+
const commandInterceptor = this.postCommandInterceptor.get(interceptor);
|
|
627
|
+
if (commandInterceptor && result) {
|
|
628
|
+
const index = commandInterceptor.indexOf(result);
|
|
629
|
+
if (index !== -1) {
|
|
630
|
+
commandInterceptor.splice(index, 1);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
} else {
|
|
636
|
+
this.postCommandInterceptors.push(interceptor);
|
|
637
|
+
return {
|
|
638
|
+
dispose: () => {
|
|
639
|
+
const index = this.postCommandInterceptors.indexOf(interceptor);
|
|
640
|
+
if (index !== -1) {
|
|
641
|
+
this.postCommandInterceptors.splice(index, 1);
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* 获取最近使用的命令列表
|
|
650
|
+
*/
|
|
651
|
+
getRecentCommands() {
|
|
652
|
+
return this._recent;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* 获取最近使用的命令列表
|
|
657
|
+
*/
|
|
658
|
+
setRecentCommands(commands: Command[]) {
|
|
659
|
+
commands.forEach((command: Command) => {
|
|
660
|
+
this.addRecentCommand(command);
|
|
661
|
+
});
|
|
662
|
+
return this._recent;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* 添加一个命令到最近使用列表中
|
|
667
|
+
* @param recent 待添加的命令
|
|
668
|
+
*/
|
|
669
|
+
protected addRecentCommand(recent: Command): void {
|
|
670
|
+
if (!recent || !recent.label) {
|
|
671
|
+
return; // 某些情况会报错
|
|
672
|
+
}
|
|
673
|
+
// 确定命令当前是否存在于最近使用的列表中
|
|
674
|
+
const index = this._recent.findIndex((command) => command.id === recent.id);
|
|
675
|
+
// 如果已经存在,则从最近使用的列表中删除
|
|
676
|
+
if (index >= 0) {
|
|
677
|
+
this._recent.splice(index, 1);
|
|
678
|
+
}
|
|
679
|
+
// 将这个命令添加到最近使用的列表的第一位
|
|
680
|
+
this._recent.unshift(recent);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
@Injectable()
|
|
685
|
+
export class CommandRegistryImpl extends CoreCommandRegistryImpl implements CommandRegistry {
|
|
686
|
+
@Autowired(CommandContribution)
|
|
687
|
+
protected readonly contributionProvider: ContributionProvider<CommandContribution>;
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* 执行 CommandContribution 的注册方法
|
|
691
|
+
*/
|
|
692
|
+
initialize(): void {
|
|
693
|
+
const contributions = this.contributionProvider.getContributions();
|
|
694
|
+
for (const contrib of contributions) {
|
|
695
|
+
contrib.registerCommands(this);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
@Injectable()
|
|
701
|
+
export class CommandServiceImpl implements CommandService {
|
|
702
|
+
@Autowired(CommandRegistry)
|
|
703
|
+
private commandRegistry: CommandRegistryImpl;
|
|
704
|
+
|
|
705
|
+
private readonly _onWillExecuteCommand = new Emitter<ICommandEvent>();
|
|
706
|
+
readonly onWillExecuteCommand: Event<ICommandEvent> = this._onWillExecuteCommand.event;
|
|
707
|
+
private readonly _onDidExecuteCommand = new Emitter<ICommandEvent>();
|
|
708
|
+
readonly onDidExecuteCommand: Event<ICommandEvent> = this._onDidExecuteCommand.event;
|
|
709
|
+
|
|
710
|
+
executeCommand<T>(commandId: string, ...args: any[]): Promise<T | undefined> {
|
|
711
|
+
this._onWillExecuteCommand.fire({ commandId, args });
|
|
712
|
+
const result = this.commandRegistry.executeCommand<T>(commandId, ...args).finally(() => {
|
|
713
|
+
this._onDidExecuteCommand.fire({ commandId, args });
|
|
714
|
+
});
|
|
715
|
+
return Promise.resolve(result);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
async tryExecuteCommand<T>(commandId: string, ...args: any[]): Promise<T | undefined> {
|
|
719
|
+
try {
|
|
720
|
+
return await this.executeCommand(commandId, ...args);
|
|
721
|
+
} catch (err) {
|
|
722
|
+
// no-op: failed when command not found
|
|
723
|
+
getDebugLogger().warn(err);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|