@theia/preferences 1.50.1 → 1.52.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/browser/preference-frontend-module.d.ts.map +1 -1
- package/lib/browser/preference-frontend-module.js +2 -0
- package/lib/browser/preference-frontend-module.js.map +1 -1
- package/lib/browser/preference-tree-model.d.ts +1 -0
- package/lib/browser/preference-tree-model.d.ts.map +1 -1
- package/lib/browser/preference-tree-model.js +10 -3
- package/lib/browser/preference-tree-model.js.map +1 -1
- package/lib/browser/util/preference-layout.d.ts +23 -0
- package/lib/browser/util/preference-layout.d.ts.map +1 -0
- package/lib/browser/util/preference-layout.js +365 -0
- package/lib/browser/util/preference-layout.js.map +1 -0
- package/lib/browser/util/preference-tree-generator.d.ts +4 -7
- package/lib/browser/util/preference-tree-generator.d.ts.map +1 -1
- package/lib/browser/util/preference-tree-generator.js +29 -62
- package/lib/browser/util/preference-tree-generator.js.map +1 -1
- package/lib/browser/util/preference-tree-label-provider.d.ts +2 -2
- package/lib/browser/util/preference-tree-label-provider.d.ts.map +1 -1
- package/lib/browser/util/preference-tree-label-provider.js +17 -6
- package/lib/browser/util/preference-tree-label-provider.js.map +1 -1
- package/lib/browser/util/preference-tree-label-provider.spec.js +2 -0
- package/lib/browser/util/preference-tree-label-provider.spec.js.map +1 -1
- package/lib/browser/util/preference-types.d.ts +6 -2
- package/lib/browser/util/preference-types.d.ts.map +1 -1
- package/lib/browser/util/preference-types.js +4 -0
- package/lib/browser/util/preference-types.js.map +1 -1
- package/lib/browser/views/preference-editor-widget.d.ts.map +1 -1
- package/lib/browser/views/preference-editor-widget.js +2 -2
- package/lib/browser/views/preference-editor-widget.js.map +1 -1
- package/lib/browser/views/preference-widget.d.ts.map +1 -1
- package/lib/browser/views/preference-widget.js +1 -0
- package/lib/browser/views/preference-widget.js.map +1 -1
- package/package.json +9 -9
- package/src/browser/preference-frontend-module.ts +2 -0
- package/src/browser/preference-tree-model.ts +10 -3
- package/src/browser/util/preference-layout.ts +377 -0
- package/src/browser/util/preference-tree-generator.ts +27 -63
- package/src/browser/util/preference-tree-label-provider.spec.ts +2 -0
- package/src/browser/util/preference-tree-label-provider.ts +18 -4
- package/src/browser/util/preference-types.ts +8 -2
- package/src/browser/views/preference-editor-widget.ts +1 -1
- package/src/browser/views/preference-widget.tsx +1 -0
|
@@ -30,11 +30,12 @@ import {
|
|
|
30
30
|
} from '@theia/core/lib/browser';
|
|
31
31
|
import { Emitter } from '@theia/core';
|
|
32
32
|
import { PreferencesSearchbarWidget } from './views/preference-searchbar-widget';
|
|
33
|
-
import { PreferenceTreeGenerator
|
|
33
|
+
import { PreferenceTreeGenerator } from './util/preference-tree-generator';
|
|
34
34
|
import * as fuzzy from '@theia/core/shared/fuzzy';
|
|
35
35
|
import { PreferencesScopeTabBar } from './views/preference-scope-tabbar-widget';
|
|
36
36
|
import { Preference } from './util/preference-types';
|
|
37
37
|
import { Event } from '@theia/core/lib/common';
|
|
38
|
+
import { COMMONLY_USED_SECTION_PREFIX } from './util/preference-layout';
|
|
38
39
|
|
|
39
40
|
export interface PreferenceTreeNodeProps extends NodeProps {
|
|
40
41
|
visibleChildren: number;
|
|
@@ -67,6 +68,7 @@ export class PreferenceTreeModel extends TreeModelImpl {
|
|
|
67
68
|
|
|
68
69
|
protected lastSearchedFuzzy: string = '';
|
|
69
70
|
protected lastSearchedLiteral: string = '';
|
|
71
|
+
protected lastSearchedTags: string[] = [];
|
|
70
72
|
protected _currentScope: number = Number(Preference.DEFAULT_SCOPE.scope);
|
|
71
73
|
protected _isFiltered: boolean = false;
|
|
72
74
|
protected _currentRows: Map<string, PreferenceTreeNodeRow> = new Map();
|
|
@@ -110,8 +112,10 @@ export class PreferenceTreeModel extends TreeModelImpl {
|
|
|
110
112
|
this.updateFilteredRows(PreferenceFilterChangeSource.Scope);
|
|
111
113
|
}),
|
|
112
114
|
this.filterInput.onFilterChanged(newSearchTerm => {
|
|
113
|
-
this.
|
|
114
|
-
|
|
115
|
+
this.lastSearchedTags = Array.from(newSearchTerm.matchAll(/@tag:([^\s]+)/g)).map(match => match[0].slice(5));
|
|
116
|
+
const newSearchTermWithoutTags = newSearchTerm.replace(/@tag:[^\s]+/g, '');
|
|
117
|
+
this.lastSearchedLiteral = newSearchTermWithoutTags;
|
|
118
|
+
this.lastSearchedFuzzy = newSearchTermWithoutTags.replace(/\s/g, '');
|
|
115
119
|
this._isFiltered = newSearchTerm.length > 2;
|
|
116
120
|
if (this.isFiltered) {
|
|
117
121
|
this.expandAll();
|
|
@@ -183,6 +187,9 @@ export class PreferenceTreeModel extends TreeModelImpl {
|
|
|
183
187
|
if (node.id.startsWith(COMMONLY_USED_SECTION_PREFIX)) {
|
|
184
188
|
return false;
|
|
185
189
|
}
|
|
190
|
+
if (!this.lastSearchedTags.every(tag => node.preference.data.tags?.includes(tag))) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
186
193
|
return fuzzy.test(this.lastSearchedFuzzy, prefID) // search matches preference name.
|
|
187
194
|
// search matches description. Fuzzy isn't ideal here because the score depends on the order of discovery.
|
|
188
195
|
|| (node.preference.data.description ?? '').includes(this.lastSearchedLiteral);
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 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
|
+
|
|
17
|
+
import { nls } from '@theia/core';
|
|
18
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
|
|
20
|
+
export interface PreferenceLayout {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
children?: PreferenceLayout[];
|
|
24
|
+
settings?: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const COMMONLY_USED_SECTION_PREFIX = 'commonly-used';
|
|
28
|
+
|
|
29
|
+
export const COMMONLY_USED_LAYOUT = {
|
|
30
|
+
id: COMMONLY_USED_SECTION_PREFIX,
|
|
31
|
+
label: nls.localizeByDefault('Commonly Used'),
|
|
32
|
+
settings: [
|
|
33
|
+
'files.autoSave',
|
|
34
|
+
'editor.fontSize',
|
|
35
|
+
'editor.fontFamily',
|
|
36
|
+
'editor.tabSize',
|
|
37
|
+
'editor.renderWhitespace',
|
|
38
|
+
'editor.cursorStyle',
|
|
39
|
+
'editor.multiCursorModifier',
|
|
40
|
+
'editor.insertSpaces',
|
|
41
|
+
'editor.wordWrap',
|
|
42
|
+
'files.exclude',
|
|
43
|
+
'files.associations'
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const DEFAULT_LAYOUT: PreferenceLayout[] = [
|
|
48
|
+
{
|
|
49
|
+
id: 'editor',
|
|
50
|
+
label: nls.localizeByDefault('Text Editor'),
|
|
51
|
+
settings: ['editor.*'],
|
|
52
|
+
children: [
|
|
53
|
+
{
|
|
54
|
+
id: 'editor.cursor',
|
|
55
|
+
label: nls.localizeByDefault('Cursor'),
|
|
56
|
+
settings: ['editor.cursor*']
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'editor.find',
|
|
60
|
+
label: nls.localizeByDefault('Find'),
|
|
61
|
+
settings: ['editor.find.*']
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'editor.font',
|
|
65
|
+
label: nls.localizeByDefault('Font'),
|
|
66
|
+
settings: ['editor.font*']
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'editor.format',
|
|
70
|
+
label: nls.localizeByDefault('Formatting'),
|
|
71
|
+
settings: ['editor.format*']
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'editor.diffEditor',
|
|
75
|
+
label: nls.localizeByDefault('Diff Editor'),
|
|
76
|
+
settings: ['diffEditor.*']
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'editor.multiDiffEditor',
|
|
80
|
+
label: nls.localizeByDefault('Multi-File Diff Editor'),
|
|
81
|
+
settings: ['multiDiffEditor.*']
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'editor.minimap',
|
|
85
|
+
label: nls.localizeByDefault('Minimap'),
|
|
86
|
+
settings: ['editor.minimap.*']
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'editor.suggestions',
|
|
90
|
+
label: nls.localizeByDefault('Suggestions'),
|
|
91
|
+
settings: ['editor.*suggest*']
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'editor.files',
|
|
95
|
+
label: nls.localizeByDefault('Files'),
|
|
96
|
+
settings: ['files.*']
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'workbench',
|
|
102
|
+
label: nls.localizeByDefault('Workbench'),
|
|
103
|
+
settings: ['workbench.*', 'workspace.*'],
|
|
104
|
+
children: [
|
|
105
|
+
{
|
|
106
|
+
id: 'workbench.appearance',
|
|
107
|
+
label: nls.localizeByDefault('Appearance'),
|
|
108
|
+
settings: [
|
|
109
|
+
'workbench.activityBar.*', 'workbench.*color*', 'workbench.fontAliasing', 'workbench.iconTheme', 'workbench.sidebar.location',
|
|
110
|
+
'workbench.*.visible', 'workbench.tips.enabled', 'workbench.tree.*', 'workbench.view.*'
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'workbench.breadcrumbs',
|
|
115
|
+
label: nls.localizeByDefault('Breadcrumbs'),
|
|
116
|
+
settings: ['breadcrumbs.*']
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'workbench.editor',
|
|
120
|
+
label: nls.localizeByDefault('Editor Management'),
|
|
121
|
+
settings: ['workbench.editor.*']
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'workbench.settings',
|
|
125
|
+
label: nls.localizeByDefault('Settings Editor'),
|
|
126
|
+
settings: ['workbench.settings.*']
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'workbench.zenmode',
|
|
130
|
+
label: nls.localizeByDefault('Zen Mode'),
|
|
131
|
+
settings: ['zenmode.*']
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: 'workbench.screencastmode',
|
|
135
|
+
label: nls.localizeByDefault('Screencast Mode'),
|
|
136
|
+
settings: ['screencastMode.*']
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'window',
|
|
142
|
+
label: nls.localizeByDefault('Window'),
|
|
143
|
+
settings: ['window.*'],
|
|
144
|
+
children: [
|
|
145
|
+
{
|
|
146
|
+
id: 'window.newWindow',
|
|
147
|
+
label: nls.localizeByDefault('New Window'),
|
|
148
|
+
settings: ['window.*newwindow*']
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 'features',
|
|
154
|
+
label: nls.localizeByDefault('Features'),
|
|
155
|
+
children: [
|
|
156
|
+
{
|
|
157
|
+
id: 'features.accessibilitySignals',
|
|
158
|
+
label: nls.localizeByDefault('Accessibility Signals'),
|
|
159
|
+
settings: ['accessibility.signal*']
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'features.accessibility',
|
|
163
|
+
label: nls.localizeByDefault('Accessibility'),
|
|
164
|
+
settings: ['accessibility.*']
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'features.explorer',
|
|
168
|
+
label: nls.localizeByDefault('Explorer'),
|
|
169
|
+
settings: ['explorer.*', 'outline.*']
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: 'features.search',
|
|
173
|
+
label: nls.localizeByDefault('Search'),
|
|
174
|
+
settings: ['search.*']
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'features.debug',
|
|
178
|
+
label: nls.localizeByDefault('Debug'),
|
|
179
|
+
settings: ['debug.*', 'launch']
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: 'features.testing',
|
|
183
|
+
label: nls.localizeByDefault('Testing'),
|
|
184
|
+
settings: ['testing.*']
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'features.scm',
|
|
188
|
+
label: nls.localizeByDefault('Source Control'),
|
|
189
|
+
settings: ['scm.*']
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'features.extensions',
|
|
193
|
+
label: nls.localizeByDefault('Extensions'),
|
|
194
|
+
settings: ['extensions.*']
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: 'features.terminal',
|
|
198
|
+
label: nls.localizeByDefault('Terminal'),
|
|
199
|
+
settings: ['terminal.*']
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: 'features.task',
|
|
203
|
+
label: nls.localizeByDefault('Task'),
|
|
204
|
+
settings: ['task.*']
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: 'features.problems',
|
|
208
|
+
label: nls.localizeByDefault('Problems'),
|
|
209
|
+
settings: ['problems.*']
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'features.output',
|
|
213
|
+
label: nls.localizeByDefault('Output'),
|
|
214
|
+
settings: ['output.*']
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 'features.comments',
|
|
218
|
+
label: nls.localizeByDefault('Comments'),
|
|
219
|
+
settings: ['comments.*']
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: 'features.remote',
|
|
223
|
+
label: nls.localizeByDefault('Remote'),
|
|
224
|
+
settings: ['remote.*']
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: 'features.timeline',
|
|
228
|
+
label: nls.localizeByDefault('Timeline'),
|
|
229
|
+
settings: ['timeline.*']
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: 'features.toolbar',
|
|
233
|
+
label: nls.localize('theia/preferences/toolbar', 'Toolbar'),
|
|
234
|
+
settings: ['toolbar.*']
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: 'features.notebook',
|
|
238
|
+
label: nls.localizeByDefault('Notebook'),
|
|
239
|
+
settings: ['notebook.*', 'interactiveWindow.*']
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'features.mergeEditor',
|
|
243
|
+
label: nls.localizeByDefault('Merge Editor'),
|
|
244
|
+
settings: ['mergeEditor.*']
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: 'features.chat',
|
|
248
|
+
label: nls.localizeByDefault('Chat'),
|
|
249
|
+
settings: ['chat.*', 'inlineChat.*']
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: 'application',
|
|
255
|
+
label: nls.localizeByDefault('Application'),
|
|
256
|
+
children: [
|
|
257
|
+
{
|
|
258
|
+
id: 'application.http',
|
|
259
|
+
label: nls.localizeByDefault('HTTP'),
|
|
260
|
+
settings: ['http.*']
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: 'application.keyboard',
|
|
264
|
+
label: nls.localizeByDefault('Keyboard'),
|
|
265
|
+
settings: ['keyboard.*']
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: 'application.update',
|
|
269
|
+
label: nls.localizeByDefault('Update'),
|
|
270
|
+
settings: ['update.*']
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'application.telemetry',
|
|
274
|
+
label: nls.localizeByDefault('Telemetry'),
|
|
275
|
+
settings: ['telemetry.*']
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'application.settingsSync',
|
|
279
|
+
label: nls.localizeByDefault('Settings Sync'),
|
|
280
|
+
settings: ['settingsSync.*']
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: 'application.experimental',
|
|
284
|
+
label: nls.localizeByDefault('Experimental'),
|
|
285
|
+
settings: ['application.experimental.*']
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: 'application.other',
|
|
289
|
+
label: nls.localizeByDefault('Other'),
|
|
290
|
+
settings: ['application.*']
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: 'security',
|
|
296
|
+
label: nls.localizeByDefault('Security'),
|
|
297
|
+
settings: ['security.*'],
|
|
298
|
+
children: [
|
|
299
|
+
{
|
|
300
|
+
id: 'security.workspace',
|
|
301
|
+
label: nls.localizeByDefault('Workspace'),
|
|
302
|
+
settings: ['security.workspace.*']
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
id: 'extensions',
|
|
308
|
+
label: nls.localizeByDefault('Extensions'),
|
|
309
|
+
children: [
|
|
310
|
+
{
|
|
311
|
+
id: 'extensions.hosted-plugin',
|
|
312
|
+
label: nls.localize('theia/preferences/hostedPlugin', 'Hosted Plugin'),
|
|
313
|
+
settings: ['hosted-plugin.*']
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
@injectable()
|
|
320
|
+
export class PreferenceLayoutProvider {
|
|
321
|
+
|
|
322
|
+
getLayout(): PreferenceLayout[] {
|
|
323
|
+
return DEFAULT_LAYOUT;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
getCommonlyUsedLayout(): PreferenceLayout {
|
|
327
|
+
return COMMONLY_USED_LAYOUT;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
hasCategory(id: string): boolean {
|
|
331
|
+
return [...this.getLayout(), this.getCommonlyUsedLayout()].some(e => e.id === id);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
getLayoutForPreference(preferenceId: string): PreferenceLayout | undefined {
|
|
335
|
+
const layout = this.getLayout();
|
|
336
|
+
for (const section of layout) {
|
|
337
|
+
const item = this.findItemInSection(section, preferenceId);
|
|
338
|
+
if (item) {
|
|
339
|
+
return item;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
protected findItemInSection(section: PreferenceLayout, preferenceId: string): PreferenceLayout | undefined {
|
|
346
|
+
// First check whether any of its children match the preferenceId.
|
|
347
|
+
if (section.children) {
|
|
348
|
+
for (const child of section.children) {
|
|
349
|
+
const item = this.findItemInSection(child, preferenceId);
|
|
350
|
+
if (item) {
|
|
351
|
+
return item;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Then check whether the section itself matches the preferenceId.
|
|
356
|
+
if (section.settings) {
|
|
357
|
+
for (const setting of section.settings) {
|
|
358
|
+
if (this.matchesSetting(preferenceId, setting)) {
|
|
359
|
+
return section;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return undefined;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
protected matchesSetting(preferenceId: string, setting: string): boolean {
|
|
367
|
+
if (setting.includes('*')) {
|
|
368
|
+
return this.createRegExp(setting).test(preferenceId);
|
|
369
|
+
}
|
|
370
|
+
return preferenceId === setting;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
protected createRegExp(setting: string): RegExp {
|
|
374
|
+
return new RegExp(`^${setting.replace(/\./g, '\\.').replace(/\*/g, '.*')}$`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
}
|
|
@@ -20,57 +20,19 @@ import { PreferenceConfigurations } from '@theia/core/lib/browser/preferences/pr
|
|
|
20
20
|
import { Emitter } from '@theia/core';
|
|
21
21
|
import debounce = require('@theia/core/shared/lodash.debounce');
|
|
22
22
|
import { Preference } from './preference-types';
|
|
23
|
+
import { COMMONLY_USED_SECTION_PREFIX, PreferenceLayoutProvider } from './preference-layout';
|
|
23
24
|
|
|
24
|
-
export const COMMONLY_USED_SECTION_PREFIX = 'commonly-used';
|
|
25
25
|
@injectable()
|
|
26
26
|
export class PreferenceTreeGenerator {
|
|
27
27
|
|
|
28
28
|
@inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider;
|
|
29
29
|
@inject(PreferenceConfigurations) protected readonly preferenceConfigs: PreferenceConfigurations;
|
|
30
|
+
@inject(PreferenceLayoutProvider) protected readonly layoutProvider: PreferenceLayoutProvider;
|
|
30
31
|
|
|
31
32
|
protected _root: CompositeTreeNode;
|
|
32
33
|
|
|
33
34
|
protected readonly onSchemaChangedEmitter = new Emitter<CompositeTreeNode>();
|
|
34
35
|
readonly onSchemaChanged = this.onSchemaChangedEmitter.event;
|
|
35
|
-
protected readonly commonlyUsedPreferences = [
|
|
36
|
-
'files.autoSave', 'files.autoSaveDelay', 'editor.fontSize',
|
|
37
|
-
'editor.fontFamily', 'editor.tabSize', 'editor.renderWhitespace',
|
|
38
|
-
'editor.cursorStyle', 'editor.multiCursorModifier', 'editor.insertSpaces',
|
|
39
|
-
'editor.wordWrap', 'files.exclude', 'files.associations'
|
|
40
|
-
];
|
|
41
|
-
protected readonly topLevelCategories = new Map([
|
|
42
|
-
[COMMONLY_USED_SECTION_PREFIX, 'Commonly Used'],
|
|
43
|
-
['editor', 'Text Editor'],
|
|
44
|
-
['workbench', 'Workbench'],
|
|
45
|
-
['window', 'Window'],
|
|
46
|
-
['features', 'Features'],
|
|
47
|
-
['application', 'Application'],
|
|
48
|
-
['security', 'Security'],
|
|
49
|
-
['extensions', 'Extensions']
|
|
50
|
-
]);
|
|
51
|
-
protected readonly sectionAssignments = new Map([
|
|
52
|
-
['breadcrumbs', 'workbench'],
|
|
53
|
-
['comments', 'features'],
|
|
54
|
-
['debug', 'features'],
|
|
55
|
-
['diffEditor', 'editor'],
|
|
56
|
-
['explorer', 'features'],
|
|
57
|
-
['extensions', 'features'],
|
|
58
|
-
['files', 'editor'],
|
|
59
|
-
['hosted-plugin', 'features'],
|
|
60
|
-
['http', 'application'],
|
|
61
|
-
['keyboard', 'application'],
|
|
62
|
-
['notification', 'workbench'],
|
|
63
|
-
['output', 'features'],
|
|
64
|
-
['preview', 'features'],
|
|
65
|
-
['problems', 'features'],
|
|
66
|
-
['scm', 'features'],
|
|
67
|
-
['search', 'features'],
|
|
68
|
-
['task', 'features'],
|
|
69
|
-
['terminal', 'features'],
|
|
70
|
-
['toolbar', 'features'],
|
|
71
|
-
['webview', 'features'],
|
|
72
|
-
['workspace', 'application'],
|
|
73
|
-
]);
|
|
74
36
|
protected readonly defaultTopLevelCategory = 'extensions';
|
|
75
37
|
|
|
76
38
|
get root(): CompositeTreeNode {
|
|
@@ -94,11 +56,13 @@ export class PreferenceTreeGenerator {
|
|
|
94
56
|
const groups = new Map<string, Preference.CompositeTreeNode>();
|
|
95
57
|
const root = this.createRootNode();
|
|
96
58
|
|
|
97
|
-
|
|
98
|
-
|
|
59
|
+
const commonlyUsedLayout = this.layoutProvider.getCommonlyUsedLayout();
|
|
60
|
+
const commonlyUsed = this.getOrCreatePreferencesGroup(commonlyUsedLayout.id, commonlyUsedLayout.id, root, groups, commonlyUsedLayout.label);
|
|
61
|
+
|
|
62
|
+
for (const layout of this.layoutProvider.getLayout()) {
|
|
63
|
+
this.getOrCreatePreferencesGroup(layout.id, layout.id, root, groups, layout.label);
|
|
99
64
|
}
|
|
100
|
-
const
|
|
101
|
-
for (const preference of this.commonlyUsedPreferences) {
|
|
65
|
+
for (const preference of commonlyUsedLayout.settings ?? []) {
|
|
102
66
|
if (preference in preferencesSchema.properties) {
|
|
103
67
|
this.createLeafNode(preference, commonlyUsed, preferencesSchema.properties[preference]);
|
|
104
68
|
}
|
|
@@ -106,12 +70,15 @@ export class PreferenceTreeGenerator {
|
|
|
106
70
|
for (const propertyName of propertyNames) {
|
|
107
71
|
const property = preferencesSchema.properties[propertyName];
|
|
108
72
|
if (!this.preferenceConfigs.isSectionName(propertyName) && !OVERRIDE_PROPERTY_PATTERN.test(propertyName) && !property.deprecationMessage) {
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
73
|
+
const layoutItem = this.layoutProvider.getLayoutForPreference(propertyName);
|
|
74
|
+
const labels = layoutItem ? layoutItem.id.split('.') : propertyName.split('.');
|
|
75
|
+
// If a title is set, this property belongs to the 'extensions' category
|
|
76
|
+
const groupID = property.title ? this.defaultTopLevelCategory : this.getGroupName(labels);
|
|
77
|
+
// Automatically assign all properties with the same title to the same subgroup
|
|
78
|
+
const subgroupName = property.title ?? this.getSubgroupName(labels, groupID);
|
|
112
79
|
const subgroupID = [groupID, subgroupName].join('.');
|
|
113
80
|
const toplevelParent = this.getOrCreatePreferencesGroup(groupID, groupID, root, groups);
|
|
114
|
-
const immediateParent = subgroupName && this.getOrCreatePreferencesGroup(subgroupID, groupID, toplevelParent, groups);
|
|
81
|
+
const immediateParent = subgroupName && this.getOrCreatePreferencesGroup(subgroupID, groupID, toplevelParent, groups, property.title ?? layoutItem?.label);
|
|
115
82
|
this.createLeafNode(propertyName, immediateParent || toplevelParent, property);
|
|
116
83
|
}
|
|
117
84
|
}
|
|
@@ -144,21 +111,19 @@ export class PreferenceTreeGenerator {
|
|
|
144
111
|
|
|
145
112
|
protected getGroupName(labels: string[]): string {
|
|
146
113
|
const defaultGroup = labels[0];
|
|
147
|
-
if (this.
|
|
114
|
+
if (this.layoutProvider.hasCategory(defaultGroup)) {
|
|
148
115
|
return defaultGroup;
|
|
149
116
|
}
|
|
150
|
-
const assignedGroup = this.sectionAssignments.get(defaultGroup);
|
|
151
|
-
if (assignedGroup) {
|
|
152
|
-
return assignedGroup;
|
|
153
|
-
}
|
|
154
117
|
return this.defaultTopLevelCategory;
|
|
155
118
|
}
|
|
156
119
|
|
|
157
120
|
protected getSubgroupName(labels: string[], computedGroupName: string): string | undefined {
|
|
158
121
|
if (computedGroupName !== labels[0]) {
|
|
159
122
|
return labels[0];
|
|
160
|
-
} else if (labels.length >
|
|
123
|
+
} else if (labels.length > 1) {
|
|
161
124
|
return labels[1];
|
|
125
|
+
} else {
|
|
126
|
+
return undefined;
|
|
162
127
|
}
|
|
163
128
|
}
|
|
164
129
|
|
|
@@ -181,7 +146,7 @@ export class PreferenceTreeGenerator {
|
|
|
181
146
|
|
|
182
147
|
protected createLeafNode(property: string, preferencesGroup: Preference.CompositeTreeNode, data: PreferenceDataProperty): Preference.LeafNode {
|
|
183
148
|
const { group } = Preference.TreeNode.getGroupAndIdFromNodeId(preferencesGroup.id);
|
|
184
|
-
const newNode = {
|
|
149
|
+
const newNode: Preference.LeafNode = {
|
|
185
150
|
id: `${group}@${property}`,
|
|
186
151
|
preferenceId: property,
|
|
187
152
|
parent: preferencesGroup,
|
|
@@ -192,8 +157,8 @@ export class PreferenceTreeGenerator {
|
|
|
192
157
|
return newNode;
|
|
193
158
|
}
|
|
194
159
|
|
|
195
|
-
protected createPreferencesGroup(id: string, group: string, root: CompositeTreeNode): Preference.CompositeTreeNode {
|
|
196
|
-
const newNode = {
|
|
160
|
+
protected createPreferencesGroup(id: string, group: string, root: CompositeTreeNode, label?: string): Preference.CompositeTreeNode {
|
|
161
|
+
const newNode: Preference.CompositeTreeNode = {
|
|
197
162
|
id: `${group}@${id}`,
|
|
198
163
|
visible: true,
|
|
199
164
|
parent: root,
|
|
@@ -201,6 +166,7 @@ export class PreferenceTreeGenerator {
|
|
|
201
166
|
expanded: false,
|
|
202
167
|
selected: false,
|
|
203
168
|
depth: 0,
|
|
169
|
+
label
|
|
204
170
|
};
|
|
205
171
|
const isTopLevel = Preference.TreeNode.isTopLevel(newNode);
|
|
206
172
|
if (!isTopLevel) {
|
|
@@ -212,14 +178,12 @@ export class PreferenceTreeGenerator {
|
|
|
212
178
|
return newNode;
|
|
213
179
|
}
|
|
214
180
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
protected getOrCreatePreferencesGroup(id: string, group: string, root: CompositeTreeNode, groups: Map<string, Preference.CompositeTreeNode>): Preference.CompositeTreeNode {
|
|
181
|
+
protected getOrCreatePreferencesGroup(
|
|
182
|
+
id: string, group: string, root: CompositeTreeNode, groups: Map<string, Preference.CompositeTreeNode>, label?: string
|
|
183
|
+
): Preference.CompositeTreeNode {
|
|
220
184
|
const existingGroup = groups.get(id);
|
|
221
185
|
if (existingGroup) { return existingGroup; }
|
|
222
|
-
const newNode = this.createPreferencesGroup(id, group, root);
|
|
186
|
+
const newNode = this.createPreferencesGroup(id, group, root, label);
|
|
223
187
|
groups.set(id, newNode);
|
|
224
188
|
return newNode;
|
|
225
189
|
};
|
|
@@ -28,6 +28,7 @@ import { PreferenceTreeGenerator } from './preference-tree-generator';
|
|
|
28
28
|
import { PreferenceTreeLabelProvider } from './preference-tree-label-provider';
|
|
29
29
|
import { Preference } from './preference-types';
|
|
30
30
|
import { SelectableTreeNode } from '@theia/core/lib/browser';
|
|
31
|
+
import { PreferenceLayoutProvider } from './preference-layout';
|
|
31
32
|
|
|
32
33
|
disableJSDOM();
|
|
33
34
|
|
|
@@ -37,6 +38,7 @@ describe('preference-tree-label-provider', () => {
|
|
|
37
38
|
|
|
38
39
|
beforeEach(() => {
|
|
39
40
|
const container = new Container();
|
|
41
|
+
container.bind(PreferenceLayoutProvider).toSelf().inSingletonScope();
|
|
40
42
|
container.bind<any>(PreferenceTreeGenerator).toConstantValue({ getCustomLabelFor: () => { } });
|
|
41
43
|
preferenceTreeLabelProvider = container.resolve(PreferenceTreeLabelProvider);
|
|
42
44
|
});
|
|
@@ -14,21 +14,35 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
18
|
import { LabelProviderContribution, TreeNode } from '@theia/core/lib/browser';
|
|
19
19
|
import { Preference } from './preference-types';
|
|
20
|
-
import {
|
|
20
|
+
import { PreferenceLayoutProvider } from './preference-layout';
|
|
21
|
+
|
|
21
22
|
@injectable()
|
|
22
23
|
export class PreferenceTreeLabelProvider implements LabelProviderContribution {
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
@inject(PreferenceLayoutProvider)
|
|
26
|
+
protected readonly layoutProvider: PreferenceLayoutProvider;
|
|
24
27
|
|
|
25
28
|
canHandle(element: object): number {
|
|
26
29
|
return TreeNode.is(element) && Preference.TreeNode.is(element) ? 150 : 0;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
getName(node: Preference.TreeNode): string {
|
|
33
|
+
if (Preference.CompositeTreeNode.is(node) && node.label) {
|
|
34
|
+
return node.label;
|
|
35
|
+
}
|
|
30
36
|
const { id } = Preference.TreeNode.getGroupAndIdFromNodeId(node.id);
|
|
31
|
-
|
|
37
|
+
const layouts = this.layoutProvider.getLayout();
|
|
38
|
+
const layout = layouts.find(e => e.id === id);
|
|
39
|
+
if (layout) {
|
|
40
|
+
return layout.label;
|
|
41
|
+
} else {
|
|
42
|
+
const labels = id.split('.');
|
|
43
|
+
const groupName = labels[labels.length - 1];
|
|
44
|
+
return this.formatString(groupName);
|
|
45
|
+
}
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
getPrefix(node: Preference.TreeNode, fullPath = false): string | undefined {
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
PreferenceDataProperty,
|
|
19
19
|
PreferenceScope,
|
|
20
20
|
TreeNode as BaseTreeNode,
|
|
21
|
-
|
|
21
|
+
ExpandableTreeNode,
|
|
22
|
+
SelectableTreeNode,
|
|
22
23
|
PreferenceInspection,
|
|
23
24
|
CommonCommands,
|
|
24
25
|
} from '@theia/core/lib/browser';
|
|
@@ -58,8 +59,13 @@ export namespace Preference {
|
|
|
58
59
|
};
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
export interface CompositeTreeNode extends
|
|
62
|
+
export interface CompositeTreeNode extends ExpandableTreeNode, SelectableTreeNode {
|
|
62
63
|
depth: number;
|
|
64
|
+
label?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export namespace CompositeTreeNode {
|
|
68
|
+
export const is = (node: TreeNode): node is CompositeTreeNode => !LeafNode.is(node);
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
export interface LeafNode extends BaseTreeNode {
|