@opensumi/ide-preferences 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.
Files changed (80) hide show
  1. package/lib/browser/abstract-resource-preference-provider.d.ts +1 -0
  2. package/lib/browser/abstract-resource-preference-provider.d.ts.map +1 -1
  3. package/lib/browser/abstract-resource-preference-provider.js +22 -3
  4. package/lib/browser/abstract-resource-preference-provider.js.map +1 -1
  5. package/lib/browser/folder-file-preference-provider.d.ts +24 -0
  6. package/lib/browser/folder-file-preference-provider.d.ts.map +1 -0
  7. package/lib/browser/{folder-preference-provider.js → folder-file-preference-provider.js} +12 -14
  8. package/lib/browser/folder-file-preference-provider.js.map +1 -0
  9. package/lib/browser/folders-preferences-provider.d.ts +8 -8
  10. package/lib/browser/folders-preferences-provider.d.ts.map +1 -1
  11. package/lib/browser/folders-preferences-provider.js +7 -7
  12. package/lib/browser/folders-preferences-provider.js.map +1 -1
  13. package/lib/browser/index.d.ts.map +1 -1
  14. package/lib/browser/index.js +8 -8
  15. package/lib/browser/index.js.map +1 -1
  16. package/lib/browser/preference-contribution.d.ts.map +1 -1
  17. package/lib/browser/preference-contribution.js +3 -3
  18. package/lib/browser/preference-contribution.js.map +1 -1
  19. package/lib/browser/preference-settings.service.d.ts +22 -10
  20. package/lib/browser/preference-settings.service.d.ts.map +1 -1
  21. package/lib/browser/preference-settings.service.js +284 -101
  22. package/lib/browser/preference-settings.service.js.map +1 -1
  23. package/lib/browser/preference-widgets.js.map +1 -1
  24. package/lib/browser/preferenceItem.view.d.ts +4 -3
  25. package/lib/browser/preferenceItem.view.d.ts.map +1 -1
  26. package/lib/browser/preferenceItem.view.js +125 -62
  27. package/lib/browser/preferenceItem.view.js.map +1 -1
  28. package/lib/browser/preferences.module.less +100 -60
  29. package/lib/browser/preferences.view.d.ts +3 -17
  30. package/lib/browser/preferences.view.d.ts.map +1 -1
  31. package/lib/browser/preferences.view.js +194 -112
  32. package/lib/browser/preferences.view.js.map +1 -1
  33. package/lib/browser/user-preference-provider.js.map +1 -1
  34. package/lib/browser/userstorage/user-storage.contribution.js.map +1 -1
  35. package/lib/browser/userstorage/user-storage.service.js +7 -7
  36. package/lib/browser/userstorage/user-storage.service.js.map +1 -1
  37. package/lib/browser/workspace-file-preference-provider.d.ts +1 -1
  38. package/lib/browser/workspace-file-preference-provider.d.ts.map +1 -1
  39. package/lib/browser/workspace-file-preference-provider.js.map +1 -1
  40. package/lib/browser/workspace-preference-provider.js.map +1 -1
  41. package/lib/common/preference-id.d.ts +3 -0
  42. package/lib/common/preference-id.d.ts.map +1 -1
  43. package/lib/common/preference-id.js +4 -1
  44. package/lib/common/preference-id.js.map +1 -1
  45. package/lib/common/preference.d.ts +1 -0
  46. package/lib/common/preference.d.ts.map +1 -1
  47. package/lib/common/preference.js +26 -4
  48. package/lib/common/preference.js.map +1 -1
  49. package/lib/common/types.d.ts +18 -3
  50. package/lib/common/types.d.ts.map +1 -1
  51. package/lib/common/user-storage.d.ts +1 -1
  52. package/lib/common/user-storage.d.ts.map +1 -1
  53. package/package.json +12 -11
  54. package/src/browser/abstract-resource-preference-provider.ts +357 -0
  55. package/src/browser/folder-file-preference-provider.ts +56 -0
  56. package/src/browser/folders-preferences-provider.ts +262 -0
  57. package/src/browser/index.ts +125 -0
  58. package/src/browser/preference-contribution.ts +432 -0
  59. package/src/browser/preference-settings.service.ts +810 -0
  60. package/src/browser/preference-widgets.ts +368 -0
  61. package/src/browser/preferenceItem.view.tsx +787 -0
  62. package/src/browser/preferences.module.less +345 -0
  63. package/src/browser/preferences.view.tsx +388 -0
  64. package/src/browser/user-preference-provider.ts +18 -0
  65. package/src/browser/userstorage/index.ts +2 -0
  66. package/src/browser/userstorage/user-storage.contribution.ts +19 -0
  67. package/src/browser/userstorage/user-storage.service.ts +192 -0
  68. package/src/browser/workspace-file-preference-provider.ts +50 -0
  69. package/src/browser/workspace-preference-provider.ts +129 -0
  70. package/src/common/commands.ts +5 -0
  71. package/src/common/index.ts +4 -0
  72. package/src/common/preference-id.ts +11 -0
  73. package/src/common/preference.ts +51 -0
  74. package/src/common/types.ts +63 -0
  75. package/src/common/user-storage.ts +6 -0
  76. package/src/index.ts +1 -0
  77. package/lib/browser/folder-preference-provider.d.ts +0 -26
  78. package/lib/browser/folder-preference-provider.d.ts.map +0 -1
  79. package/lib/browser/folder-preference-provider.js.map +0 -1
  80. package/lib/browser/index.less +0 -36
@@ -0,0 +1,368 @@
1
+ import { Autowired, Injectable, Optional } from '@opensumi/di';
2
+ import { getIcon } from '@opensumi/ide-components';
3
+ import { IPreferenceSettingsService, PreferenceSchemaProvider } from '@opensumi/ide-core-browser';
4
+ import {
5
+ AbstractContextMenuService,
6
+ ICtxMenuRenderer,
7
+ IMenuItem,
8
+ IMenuRegistry,
9
+ ISubmenuItem,
10
+ MenuCommandDesc,
11
+ MenuId,
12
+ } from '@opensumi/ide-core-browser/lib/menu/next';
13
+ import { CommandRegistry, Disposable, IDisposable, localize, PreferenceScope, URI } from '@opensumi/ide-core-common';
14
+ import { IEditor, IEditorDocumentModelService, IEditorFeatureContribution } from '@opensumi/ide-editor/lib/browser';
15
+ import { IFileServiceClient } from '@opensumi/ide-file-service';
16
+ import { MarkdownString } from '@opensumi/monaco-editor-core/esm/vs/base/common/htmlContent';
17
+ import { MouseTargetType } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorBrowser';
18
+ import { IModelDeltaDecoration } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model';
19
+ import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api';
20
+
21
+ import { SettingJSONGlyphMarginEdit } from '../common/commands';
22
+
23
+ import { PreferenceSettingsService } from './preference-settings.service';
24
+ import { USER_PREFERENCE_URI } from './user-preference-provider';
25
+
26
+ @Injectable({ multiple: true })
27
+ export class EditPreferenceDecorationsContribution implements IEditorFeatureContribution {
28
+ @Autowired(IPreferenceSettingsService)
29
+ private preferenceSettingsService: PreferenceSettingsService;
30
+
31
+ @Autowired(ICtxMenuRenderer)
32
+ private ctxMenuRenderer: ICtxMenuRenderer;
33
+
34
+ @Autowired(PreferenceSchemaProvider)
35
+ private preferenceSchemaProvider: PreferenceSchemaProvider;
36
+
37
+ @Autowired(IEditorDocumentModelService)
38
+ private editorDocumentModelService: IEditorDocumentModelService;
39
+
40
+ @Autowired(IFileServiceClient)
41
+ private fileServiceClient: IFileServiceClient;
42
+
43
+ @Autowired(AbstractContextMenuService)
44
+ private menuService: AbstractContextMenuService;
45
+
46
+ @Autowired(IMenuRegistry)
47
+ private menuRegistry: IMenuRegistry;
48
+
49
+ @Autowired(CommandRegistry)
50
+ private commandRegistry: CommandRegistry;
51
+
52
+ private readonly disposer: Disposable = new Disposable();
53
+
54
+ private _preferences: string[] = [];
55
+ private _currentLine = 0;
56
+
57
+ private readonly _editPreferenceDecoration = this.editor.monacoEditor.createDecorationsCollection();
58
+
59
+ constructor(@Optional() private readonly editor: IEditor) {}
60
+
61
+ private verifyEditor(): boolean {
62
+ if (this.editor.currentUri?.toString() === USER_PREFERENCE_URI.toString()) {
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * 返回 user scope 的真实 setting.json 路径
70
+ */
71
+ private async getPreferenceUrl(): Promise<URI | undefined> {
72
+ const settingUri = await this.preferenceSettingsService.getPreferenceUrl(PreferenceScope.User);
73
+ if (settingUri) {
74
+ const stat = await this.fileServiceClient.getFileStat(settingUri);
75
+ if (!stat) {
76
+ return undefined;
77
+ }
78
+
79
+ return URI.parse(stat.uri);
80
+ }
81
+ return undefined;
82
+ }
83
+
84
+ private async getDocumentModelRef(uri: URI) {
85
+ const document = this.editorDocumentModelService.getModelReference(uri);
86
+ if (!document) {
87
+ return this.editorDocumentModelService.createModelReference(uri);
88
+ }
89
+
90
+ return document;
91
+ }
92
+
93
+ public contribute(): IDisposable {
94
+ this.disposer.addDispose(
95
+ this.editor.monacoEditor.onMouseDown(async (e: monaco.editor.IEditorMouseEvent) => {
96
+ if (e.target.range?.startLineNumber !== this.currentLine && !this.verifyEditor()) {
97
+ return;
98
+ }
99
+ if (
100
+ e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN ||
101
+ e.target.detail.isAfterLines ||
102
+ !this.isVisible()
103
+ ) {
104
+ return;
105
+ }
106
+ this.registerMenuItems(this.preferences);
107
+ this.showContextMenu(e);
108
+ }),
109
+ );
110
+
111
+ this.disposer.addDispose(
112
+ this.editor.monacoEditor.onDidChangeCursorPosition((e: monaco.editor.ICursorPositionChangedEvent) => {
113
+ if (!this.verifyEditor()) {
114
+ return;
115
+ }
116
+ this.onPositionChanged(e);
117
+ }),
118
+ );
119
+
120
+ this.disposer.addDispose(
121
+ this.editor.monacoEditor.onContextMenu((e: monaco.editor.IEditorMouseEvent) => {
122
+ e.event.preventDefault();
123
+ e.event.stopPropagation();
124
+ return false;
125
+ }),
126
+ );
127
+
128
+ this.disposer.addDispose(
129
+ this.editor.monacoEditor.onDidChangeConfiguration(() => {
130
+ if (!this.editor.monacoEditor.getOption(monaco.editor.EditorOption.glyphMargin)) {
131
+ this.hide();
132
+ }
133
+ }),
134
+ );
135
+
136
+ this.disposer.addDispose(
137
+ Disposable.create(() => {
138
+ this.hide();
139
+ this.menuRegistry.unregisterMenuId(MenuId.SettingJSONGlyphMarginContext);
140
+ }),
141
+ );
142
+
143
+ this.disposer.addDispose(
144
+ this.commandRegistry.registerCommand(SettingJSONGlyphMarginEdit, {
145
+ execute: (key: string, value: string | boolean) => {
146
+ if (key && value) {
147
+ if (value === 'true') {
148
+ value = true;
149
+ }
150
+ if (value === 'false') {
151
+ value = false;
152
+ }
153
+ this.preferenceSettingsService.setPreference(key, value, PreferenceScope.User);
154
+ }
155
+ },
156
+ }),
157
+ );
158
+
159
+ return this.disposer;
160
+ }
161
+
162
+ private get preferences(): string[] {
163
+ return this._preferences;
164
+ }
165
+
166
+ private get currentLine(): number {
167
+ return this._currentLine;
168
+ }
169
+
170
+ private show(line: number, hoverMessage: string, preferences: string[]): void {
171
+ this._preferences = preferences;
172
+ const newDecoration: IModelDeltaDecoration[] = [];
173
+ newDecoration.push({
174
+ options: {
175
+ description: 'edit-preference-widget-decoration',
176
+ glyphMarginClassName: getIcon('edit') + ' setting-edit-glyph',
177
+ glyphMarginHoverMessage: new MarkdownString().appendText(hoverMessage),
178
+ stickiness: monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
179
+ },
180
+ range: {
181
+ startLineNumber: line,
182
+ startColumn: 1,
183
+ endLineNumber: line,
184
+ endColumn: 1,
185
+ },
186
+ });
187
+ this._editPreferenceDecoration.set(newDecoration);
188
+ }
189
+
190
+ private hide(): void {
191
+ this._editPreferenceDecoration.clear();
192
+ }
193
+
194
+ private isVisible(): boolean {
195
+ return this._editPreferenceDecoration.length > 0;
196
+ }
197
+
198
+ private async getPreferencesKeyAtLineNumber(lineNumber: number): Promise<string[]> {
199
+ const reg = new RegExp(/\"((?!,).)*\"+((\s+?)?)\:/g);
200
+ const settingUri = await this.getPreferenceUrl();
201
+ if (!settingUri) {
202
+ return [];
203
+ }
204
+
205
+ const ref = await this.getDocumentModelRef(settingUri);
206
+ const monaco = ref.instance.getMonacoModel();
207
+ const content = monaco.getLineContent(lineNumber);
208
+
209
+ ref.dispose();
210
+
211
+ // 提取配置项(同一行可能存在多个)
212
+ const match = content.match(reg) || [];
213
+ const keys = match.map((m) => {
214
+ const e = /\"(.*?)\"/g.exec(m);
215
+ return (e && e[1]) || '';
216
+ });
217
+
218
+ const properties = this.preferenceSchemaProvider.getCombinedSchema().properties;
219
+
220
+ // 筛选出 type 为 boolean 类型或含有 enum 字段这两种情况
221
+ return keys.filter((k) => {
222
+ const schema = properties[k];
223
+ if (schema) {
224
+ return schema.type === 'boolean' || schema.enum;
225
+ }
226
+ return false;
227
+ });
228
+ }
229
+
230
+ private async onPositionChanged(positionChangeEvent: monaco.editor.ICursorPositionChangedEvent) {
231
+ this.hide();
232
+ const {
233
+ position: { lineNumber },
234
+ } = positionChangeEvent;
235
+ this._currentLine = lineNumber;
236
+ const preferenceKeys = await this.getPreferencesKeyAtLineNumber(lineNumber);
237
+
238
+ if (preferenceKeys.length > 0) {
239
+ if (
240
+ this.editor.monacoEditor.getOption(monaco.editor.EditorOption.glyphMargin) &&
241
+ this.marginFreeFromOtherDecorations(lineNumber)
242
+ ) {
243
+ this.show(lineNumber, localize('editTtile'), preferenceKeys);
244
+ }
245
+ } else {
246
+ this.hide();
247
+ }
248
+ }
249
+
250
+ private marginFreeFromOtherDecorations(line: number): boolean {
251
+ const decorations = this.editor.monacoEditor.getLineDecorations(line);
252
+ if (decorations) {
253
+ for (const { options } of decorations) {
254
+ if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf(getIcon('edit')) === -1) {
255
+ return false;
256
+ }
257
+ }
258
+ }
259
+ return true;
260
+ }
261
+
262
+ private async registerMenuItems(preferences: string[]): Promise<void> {
263
+ if (preferences.length === 1) {
264
+ const menus = this.getActions(preferences[0]);
265
+ this.disposer.addDispose(
266
+ this.menuRegistry.registerMenuItems(
267
+ MenuId.SettingJSONGlyphMarginContext,
268
+ menus.map((m) => ({
269
+ command: {
270
+ id: SettingJSONGlyphMarginEdit.id,
271
+ label: m,
272
+ },
273
+ group: 'navigation',
274
+ extraTailArgs: [preferences[0], m],
275
+ })),
276
+ ),
277
+ );
278
+ } else {
279
+ // 表示同一行存在多个不同配置项,每一个配置项当作 subMenus 来渲染
280
+ preferences.forEach((key) => {
281
+ const sub = `${MenuId.SubSettingJSONGlyphMarginContext}_${key}`;
282
+
283
+ this.disposer.addDispose(
284
+ this.menuRegistry.registerMenuItem(MenuId.SettingJSONGlyphMarginContext, {
285
+ submenu: sub,
286
+ label: key,
287
+ group: 'navigation',
288
+ }),
289
+ );
290
+
291
+ const menus = this.getActions(key);
292
+
293
+ this.disposer.addDispose(
294
+ this.menuRegistry.registerMenuItems(
295
+ sub,
296
+ menus.map((m) => ({
297
+ command: {
298
+ id: SettingJSONGlyphMarginEdit.id,
299
+ label: m,
300
+ },
301
+ group: 'navigation',
302
+ extraTailArgs: [key, m],
303
+ })),
304
+ ),
305
+ );
306
+ });
307
+ }
308
+ }
309
+
310
+ private getActions(key: string): string[] {
311
+ const properties = this.preferenceSchemaProvider.getCombinedSchema().properties;
312
+ const schema = properties[key];
313
+ if (schema.type === 'boolean') {
314
+ return ['true', 'false'];
315
+ }
316
+ if (schema.enum) {
317
+ return schema.enum.map((value) => value.toString());
318
+ }
319
+ return [];
320
+ }
321
+
322
+ private showContextMenu(e: monaco.editor.IEditorMouseEvent) {
323
+ e.event.preventDefault();
324
+ e.event.stopPropagation();
325
+
326
+ const menus = this.menuService.createMenu({
327
+ id: MenuId.SettingJSONGlyphMarginContext,
328
+ config: {
329
+ separator: 'inline',
330
+ },
331
+ });
332
+ const menuNodes = menus.getMergedMenuNodes();
333
+ menus.dispose();
334
+
335
+ setTimeout(() => {
336
+ this.ctxMenuRenderer.show({
337
+ anchor: e.event.browserEvent,
338
+ menuNodes,
339
+ onHide: () => {
340
+ const preMenus = (context: MenuId | string, type: 'menu' | 'sub' = 'menu') =>
341
+ this.menuRegistry
342
+ .getMenuItems(context)
343
+ .map((e) =>
344
+ type === 'sub' ? (e as ISubmenuItem).submenu : ((e as IMenuItem).command as MenuCommandDesc),
345
+ )
346
+ .filter(Boolean);
347
+
348
+ preMenus(MenuId.SettingJSONGlyphMarginContext, 'sub').forEach((sub: string) => {
349
+ this.menuRegistry.unregisterMenuItem(MenuId.SettingJSONGlyphMarginContext, sub);
350
+
351
+ preMenus(sub).forEach((s: MenuCommandDesc) => {
352
+ this.menuRegistry.unregisterMenuItem(sub, s.id);
353
+ });
354
+ });
355
+
356
+ preMenus(MenuId.SettingJSONGlyphMarginContext).forEach((c: MenuCommandDesc) => {
357
+ this.menuRegistry.unregisterMenuItem(MenuId.SettingJSONGlyphMarginContext, c.id);
358
+ });
359
+
360
+ this.menuRegistry.unregisterMenuItem(
361
+ MenuId.SettingJSONGlyphMarginContext,
362
+ MenuId.SubSettingJSONGlyphMarginContext,
363
+ );
364
+ },
365
+ });
366
+ }, 10);
367
+ }
368
+ }