@theia/preferences 1.51.0 → 1.53.0-next.18

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 (45) hide show
  1. package/lib/browser/preference-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/preference-frontend-module.js +2 -0
  3. package/lib/browser/preference-frontend-module.js.map +1 -1
  4. package/lib/browser/preference-tree-model.d.ts.map +1 -1
  5. package/lib/browser/preference-tree-model.js +2 -1
  6. package/lib/browser/preference-tree-model.js.map +1 -1
  7. package/lib/browser/util/preference-layout.d.ts +23 -0
  8. package/lib/browser/util/preference-layout.d.ts.map +1 -0
  9. package/lib/browser/util/preference-layout.js +365 -0
  10. package/lib/browser/util/preference-layout.js.map +1 -0
  11. package/lib/browser/util/preference-tree-generator.d.ts +16 -7
  12. package/lib/browser/util/preference-tree-generator.d.ts.map +1 -1
  13. package/lib/browser/util/preference-tree-generator.js +104 -75
  14. package/lib/browser/util/preference-tree-generator.js.map +1 -1
  15. package/lib/browser/util/preference-tree-label-provider.d.ts +2 -2
  16. package/lib/browser/util/preference-tree-label-provider.d.ts.map +1 -1
  17. package/lib/browser/util/preference-tree-label-provider.js +10 -6
  18. package/lib/browser/util/preference-tree-label-provider.js.map +1 -1
  19. package/lib/browser/util/preference-tree-label-provider.spec.js +2 -0
  20. package/lib/browser/util/preference-tree-label-provider.spec.js.map +1 -1
  21. package/lib/browser/util/preference-types.d.ts +8 -2
  22. package/lib/browser/util/preference-types.d.ts.map +1 -1
  23. package/lib/browser/util/preference-types.js +4 -0
  24. package/lib/browser/util/preference-types.js.map +1 -1
  25. package/lib/browser/views/preference-editor-widget.d.ts.map +1 -1
  26. package/lib/browser/views/preference-editor-widget.js +2 -2
  27. package/lib/browser/views/preference-editor-widget.js.map +1 -1
  28. package/lib/browser/views/preference-tree-widget.d.ts +2 -0
  29. package/lib/browser/views/preference-tree-widget.d.ts.map +1 -1
  30. package/lib/browser/views/preference-tree-widget.js +10 -1
  31. package/lib/browser/views/preference-tree-widget.js.map +1 -1
  32. package/lib/browser/views/preference-widget.d.ts.map +1 -1
  33. package/lib/browser/views/preference-widget.js +1 -0
  34. package/lib/browser/views/preference-widget.js.map +1 -1
  35. package/package.json +9 -9
  36. package/src/browser/preference-frontend-module.ts +2 -0
  37. package/src/browser/preference-tree-model.ts +2 -1
  38. package/src/browser/util/preference-layout.ts +377 -0
  39. package/src/browser/util/preference-tree-generator.ts +110 -77
  40. package/src/browser/util/preference-tree-label-provider.spec.ts +2 -0
  41. package/src/browser/util/preference-tree-label-provider.ts +12 -4
  42. package/src/browser/util/preference-types.ts +9 -1
  43. package/src/browser/views/preference-editor-widget.ts +1 -1
  44. package/src/browser/views/preference-tree-widget.tsx +10 -1
  45. package/src/browser/views/preference-widget.tsx +1 -0
@@ -20,58 +20,28 @@ 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';
24
+
25
+ export interface CreatePreferencesGroupOptions {
26
+ id: string,
27
+ group: string,
28
+ root: CompositeTreeNode,
29
+ expanded?: boolean,
30
+ depth?: number,
31
+ label?: string
32
+ }
23
33
 
24
- export const COMMONLY_USED_SECTION_PREFIX = 'commonly-used';
25
34
  @injectable()
26
35
  export class PreferenceTreeGenerator {
27
36
 
28
37
  @inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider;
29
38
  @inject(PreferenceConfigurations) protected readonly preferenceConfigs: PreferenceConfigurations;
39
+ @inject(PreferenceLayoutProvider) protected readonly layoutProvider: PreferenceLayoutProvider;
30
40
 
31
41
  protected _root: CompositeTreeNode;
32
42
 
33
43
  protected readonly onSchemaChangedEmitter = new Emitter<CompositeTreeNode>();
34
44
  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
- ['testing', 'features'],
71
- ['toolbar', 'features'],
72
- ['webview', 'features'],
73
- ['workspace', 'application'],
74
- ]);
75
45
  protected readonly defaultTopLevelCategory = 'extensions';
76
46
 
77
47
  get root(): CompositeTreeNode {
@@ -95,11 +65,25 @@ export class PreferenceTreeGenerator {
95
65
  const groups = new Map<string, Preference.CompositeTreeNode>();
96
66
  const root = this.createRootNode();
97
67
 
98
- for (const id of this.topLevelCategories.keys()) {
99
- this.getOrCreatePreferencesGroup(id, id, root, groups);
68
+ const commonlyUsedLayout = this.layoutProvider.getCommonlyUsedLayout();
69
+ const commonlyUsed = this.getOrCreatePreferencesGroup({
70
+ id: commonlyUsedLayout.id,
71
+ group: commonlyUsedLayout.id,
72
+ root,
73
+ groups,
74
+ label: commonlyUsedLayout.label
75
+ });
76
+
77
+ for (const layout of this.layoutProvider.getLayout()) {
78
+ this.getOrCreatePreferencesGroup({
79
+ id: layout.id,
80
+ group: layout.id,
81
+ root,
82
+ groups,
83
+ label: layout.label
84
+ });
100
85
  }
101
- const commonlyUsed = this.getOrCreatePreferencesGroup(COMMONLY_USED_SECTION_PREFIX, COMMONLY_USED_SECTION_PREFIX, root, groups);
102
- for (const preference of this.commonlyUsedPreferences) {
86
+ for (const preference of commonlyUsedLayout.settings ?? []) {
103
87
  if (preference in preferencesSchema.properties) {
104
88
  this.createLeafNode(preference, commonlyUsed, preferencesSchema.properties[preference]);
105
89
  }
@@ -107,13 +91,11 @@ export class PreferenceTreeGenerator {
107
91
  for (const propertyName of propertyNames) {
108
92
  const property = preferencesSchema.properties[propertyName];
109
93
  if (!this.preferenceConfigs.isSectionName(propertyName) && !OVERRIDE_PROPERTY_PATTERN.test(propertyName) && !property.deprecationMessage) {
110
- const labels = propertyName.split('.');
111
- const groupID = this.getGroupName(labels);
112
- const subgroupName = this.getSubgroupName(labels, groupID);
113
- const subgroupID = [groupID, subgroupName].join('.');
114
- const toplevelParent = this.getOrCreatePreferencesGroup(groupID, groupID, root, groups);
115
- const immediateParent = subgroupName && this.getOrCreatePreferencesGroup(subgroupID, groupID, toplevelParent, groups);
116
- this.createLeafNode(propertyName, immediateParent || toplevelParent, property);
94
+ if (property.owner) {
95
+ this.createPluginLeafNode(propertyName, property, root, groups);
96
+ } else {
97
+ this.createBuiltinLeafNode(propertyName, property, root, groups);
98
+ }
117
99
  }
118
100
  }
119
101
 
@@ -137,6 +119,63 @@ export class PreferenceTreeGenerator {
137
119
  return root;
138
120
  };
139
121
 
122
+ protected createBuiltinLeafNode(name: string, property: PreferenceDataProperty, root: CompositeTreeNode, groups: Map<string, Preference.CompositeTreeNode>): void {
123
+ const layoutItem = this.layoutProvider.getLayoutForPreference(name);
124
+ const labels = layoutItem ? layoutItem.id.split('.') : name.split('.');
125
+ const groupID = this.getGroupName(labels);
126
+ const subgroupName = this.getSubgroupName(labels, groupID);
127
+ const subgroupID = [groupID, subgroupName].join('.');
128
+ const toplevelParent = this.getOrCreatePreferencesGroup({
129
+ id: groupID,
130
+ group: groupID,
131
+ root,
132
+ groups
133
+ });
134
+ const immediateParent = subgroupName ? this.getOrCreatePreferencesGroup({
135
+ id: subgroupID,
136
+ group: groupID,
137
+ root: toplevelParent,
138
+ groups,
139
+ label: layoutItem?.label
140
+ }) : undefined;
141
+ this.createLeafNode(name, immediateParent || toplevelParent, property);
142
+ }
143
+
144
+ protected createPluginLeafNode(name: string, property: PreferenceDataProperty, root: CompositeTreeNode, groups: Map<string, Preference.CompositeTreeNode>): void {
145
+ if (!property.owner) {
146
+ return;
147
+ }
148
+ const groupID = this.defaultTopLevelCategory;
149
+ const subgroupName = property.owner;
150
+ const subsubgroupName = property.group;
151
+ const hasGroup = Boolean(subsubgroupName);
152
+ const toplevelParent = this.getOrCreatePreferencesGroup({
153
+ id: groupID,
154
+ group: groupID,
155
+ root,
156
+ groups
157
+ });
158
+ const subgroupID = [groupID, subgroupName].join('.');
159
+ const subgroupParent = this.getOrCreatePreferencesGroup({
160
+ id: subgroupID,
161
+ group: groupID,
162
+ root: toplevelParent,
163
+ groups,
164
+ expanded: hasGroup,
165
+ label: subgroupName
166
+ });
167
+ const subsubgroupID = [groupID, subgroupName, subsubgroupName].join('.');
168
+ const subsubgroupParent = hasGroup ? this.getOrCreatePreferencesGroup({
169
+ id: subsubgroupID,
170
+ group: subgroupID,
171
+ root: subgroupParent,
172
+ groups,
173
+ depth: 2,
174
+ label: subsubgroupName
175
+ }) : undefined;
176
+ this.createLeafNode(name, subsubgroupParent || subgroupParent, property);
177
+ }
178
+
140
179
  getNodeId(preferenceId: string): string {
141
180
  const expectedGroup = this.getGroupName(preferenceId.split('.'));
142
181
  const expectedId = `${expectedGroup}@${preferenceId}`;
@@ -145,21 +184,19 @@ export class PreferenceTreeGenerator {
145
184
 
146
185
  protected getGroupName(labels: string[]): string {
147
186
  const defaultGroup = labels[0];
148
- if (this.topLevelCategories.has(defaultGroup)) {
187
+ if (this.layoutProvider.hasCategory(defaultGroup)) {
149
188
  return defaultGroup;
150
189
  }
151
- const assignedGroup = this.sectionAssignments.get(defaultGroup);
152
- if (assignedGroup) {
153
- return assignedGroup;
154
- }
155
190
  return this.defaultTopLevelCategory;
156
191
  }
157
192
 
158
193
  protected getSubgroupName(labels: string[], computedGroupName: string): string | undefined {
159
194
  if (computedGroupName !== labels[0]) {
160
195
  return labels[0];
161
- } else if (labels.length > 2) {
196
+ } else if (labels.length > 1) {
162
197
  return labels[1];
198
+ } else {
199
+ return undefined;
163
200
  }
164
201
  }
165
202
 
@@ -182,46 +219,42 @@ export class PreferenceTreeGenerator {
182
219
 
183
220
  protected createLeafNode(property: string, preferencesGroup: Preference.CompositeTreeNode, data: PreferenceDataProperty): Preference.LeafNode {
184
221
  const { group } = Preference.TreeNode.getGroupAndIdFromNodeId(preferencesGroup.id);
185
- const newNode = {
222
+ const newNode: Preference.LeafNode = {
186
223
  id: `${group}@${property}`,
187
224
  preferenceId: property,
188
225
  parent: preferencesGroup,
189
226
  preference: { data },
190
- depth: Preference.TreeNode.isTopLevel(preferencesGroup) ? 1 : 2,
227
+ depth: Preference.TreeNode.isTopLevel(preferencesGroup) ? 1 : 2
191
228
  };
192
229
  CompositeTreeNode.addChild(preferencesGroup, newNode);
193
230
  return newNode;
194
231
  }
195
232
 
196
- protected createPreferencesGroup(id: string, group: string, root: CompositeTreeNode): Preference.CompositeTreeNode {
197
- const newNode = {
198
- id: `${group}@${id}`,
233
+ protected createPreferencesGroup(options: CreatePreferencesGroupOptions): Preference.CompositeTreeNode {
234
+ const newNode: Preference.CompositeTreeNode = {
235
+ id: `${options.group}@${options.id}`,
199
236
  visible: true,
200
- parent: root,
237
+ parent: options.root,
201
238
  children: [],
202
239
  expanded: false,
203
240
  selected: false,
204
241
  depth: 0,
242
+ label: options.label
205
243
  };
206
244
  const isTopLevel = Preference.TreeNode.isTopLevel(newNode);
207
- if (!isTopLevel) {
208
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
- delete (newNode as any).expanded;
245
+ if (!(options.expanded ?? isTopLevel)) {
246
+ delete newNode.expanded;
210
247
  }
211
- newNode.depth = isTopLevel ? 0 : 1;
212
- CompositeTreeNode.addChild(root, newNode);
248
+ newNode.depth = options.depth ?? (isTopLevel ? 0 : 1);
249
+ CompositeTreeNode.addChild(options.root, newNode);
213
250
  return newNode;
214
251
  }
215
252
 
216
- getCustomLabelFor(id: string): string | undefined {
217
- return this.topLevelCategories.get(id);
218
- }
219
-
220
- protected getOrCreatePreferencesGroup(id: string, group: string, root: CompositeTreeNode, groups: Map<string, Preference.CompositeTreeNode>): Preference.CompositeTreeNode {
221
- const existingGroup = groups.get(id);
253
+ protected getOrCreatePreferencesGroup(options: CreatePreferencesGroupOptions & { groups: Map<string, Preference.CompositeTreeNode> }): Preference.CompositeTreeNode {
254
+ const existingGroup = options.groups.get(options.id);
222
255
  if (existingGroup) { return existingGroup; }
223
- const newNode = this.createPreferencesGroup(id, group, root);
224
- groups.set(id, newNode);
256
+ const newNode = this.createPreferencesGroup(options);
257
+ options.groups.set(options.id, newNode);
225
258
  return newNode;
226
259
  };
227
260
  }
@@ -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,29 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { injectable, inject } from '@theia/core/shared/inversify';
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 { PreferenceTreeGenerator } from './preference-tree-generator';
20
+ import { PreferenceLayoutProvider } from './preference-layout';
21
+
21
22
  @injectable()
22
23
  export class PreferenceTreeLabelProvider implements LabelProviderContribution {
23
- @inject(PreferenceTreeGenerator) protected readonly treeGenerator: PreferenceTreeGenerator;
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.TreeNode.is(node) && node.label) {
34
+ return node.label;
35
+ }
30
36
  const { id } = Preference.TreeNode.getGroupAndIdFromNodeId(node.id);
31
- return this.formatString(this.treeGenerator.getCustomLabelFor(id) ?? id.split('.').pop()!);
37
+ const labels = id.split('.');
38
+ const groupName = labels[labels.length - 1];
39
+ return this.formatString(groupName);
32
40
  }
33
41
 
34
42
  getPrefix(node: Preference.TreeNode, fullPath = false): string | undefined {
@@ -19,6 +19,7 @@ import {
19
19
  PreferenceScope,
20
20
  TreeNode as BaseTreeNode,
21
21
  CompositeTreeNode as BaseCompositeTreeNode,
22
+ SelectableTreeNode,
22
23
  PreferenceInspection,
23
24
  CommonCommands,
24
25
  } from '@theia/core/lib/browser';
@@ -58,11 +59,18 @@ export namespace Preference {
58
59
  };
59
60
  }
60
61
 
61
- export interface CompositeTreeNode extends BaseCompositeTreeNode {
62
+ export interface CompositeTreeNode extends BaseCompositeTreeNode, SelectableTreeNode {
63
+ expanded?: boolean;
62
64
  depth: number;
65
+ label?: string;
66
+ }
67
+
68
+ export namespace CompositeTreeNode {
69
+ export const is = (node: TreeNode): node is CompositeTreeNode => !LeafNode.is(node);
63
70
  }
64
71
 
65
72
  export interface LeafNode extends BaseTreeNode {
73
+ label?: string;
66
74
  depth: number;
67
75
  preference: { data: PreferenceDataProperty };
68
76
  preferenceId: string;
@@ -33,9 +33,9 @@ import { BaseWidget, DEFAULT_SCROLL_OPTIONS } from '@theia/core/lib/browser/widg
33
33
  import { PreferenceTreeModel, PreferenceFilterChangeEvent, PreferenceFilterChangeSource } from '../preference-tree-model';
34
34
  import { PreferenceNodeRendererFactory, GeneralPreferenceNodeRenderer } from './components/preference-node-renderer';
35
35
  import { Preference } from '../util/preference-types';
36
- import { COMMONLY_USED_SECTION_PREFIX } from '../util/preference-tree-generator';
37
36
  import { PreferencesScopeTabBar } from './preference-scope-tabbar-widget';
38
37
  import { PreferenceNodeRendererCreatorRegistry } from './components/preference-node-renderer-creator';
38
+ import { COMMONLY_USED_SECTION_PREFIX } from '../util/preference-layout';
39
39
 
40
40
  export interface PreferencesEditorState {
41
41
  firstVisibleChildID: string,
@@ -24,6 +24,7 @@ import {
24
24
  } from '@theia/core/lib/browser';
25
25
  import React = require('@theia/core/shared/react');
26
26
  import { PreferenceTreeModel, PreferenceTreeNodeRow, PreferenceTreeNodeProps } from '../preference-tree-model';
27
+ import { Preference } from '../util/preference-types';
27
28
 
28
29
  @injectable()
29
30
  export class PreferencesTreeWidget extends TreeWidget {
@@ -50,13 +51,21 @@ export class PreferencesTreeWidget extends TreeWidget {
50
51
  this.rows = new Map();
51
52
  let index = 0;
52
53
  for (const [id, nodeRow] of this.model.currentRows.entries()) {
53
- if (nodeRow.visibleChildren > 0 && (ExpandableTreeNode.is(nodeRow.node) || ExpandableTreeNode.isExpanded(nodeRow.node.parent))) {
54
+ if (nodeRow.visibleChildren > 0 && this.isVisibleNode(nodeRow.node)) {
54
55
  this.rows.set(id, { ...nodeRow, index: index++ });
55
56
  }
56
57
  }
57
58
  this.updateScrollToRow();
58
59
  }
59
60
 
61
+ protected isVisibleNode(node: Preference.TreeNode): boolean {
62
+ if (Preference.TreeNode.isTopLevel(node)) {
63
+ return true;
64
+ } else {
65
+ return ExpandableTreeNode.isExpanded(node.parent) && Preference.TreeNode.is(node.parent) && this.isVisibleNode(node.parent);
66
+ }
67
+ }
68
+
60
69
  protected override doRenderNodeRow({ depth, visibleChildren, node, isExpansible }: PreferenceTreeNodeRow): React.ReactNode {
61
70
  return this.renderNode(node, { depth, visibleChildren, isExpansible });
62
71
  }
@@ -78,6 +78,7 @@ export class PreferencesWidget extends Panel implements StatefulWidget {
78
78
  protected init(): void {
79
79
  this.id = PreferencesWidget.ID;
80
80
  this.title.label = PreferencesWidget.LABEL;
81
+ this.title.caption = PreferencesWidget.LABEL;
81
82
  this.title.closable = true;
82
83
  this.addClass('theia-settings-container');
83
84
  this.title.iconClass = codicon('settings');