@theia/core 1.25.0-next.7 → 1.25.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 (148) hide show
  1. package/README.md +3 -3
  2. package/lib/browser/browser.d.ts +3 -0
  3. package/lib/browser/browser.d.ts.map +1 -1
  4. package/lib/browser/browser.js +51 -1
  5. package/lib/browser/browser.js.map +1 -1
  6. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  7. package/lib/browser/common-frontend-contribution.js +59 -10
  8. package/lib/browser/common-frontend-contribution.js.map +1 -1
  9. package/lib/browser/preferences/preference-validation-service.d.ts +13 -0
  10. package/lib/browser/preferences/preference-validation-service.d.ts.map +1 -1
  11. package/lib/browser/preferences/preference-validation-service.js +92 -7
  12. package/lib/browser/preferences/preference-validation-service.js.map +1 -1
  13. package/lib/browser/preferences/preference-validation-service.spec.js +58 -0
  14. package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
  15. package/lib/browser/preloader.d.ts +2 -0
  16. package/lib/browser/preloader.d.ts.map +1 -0
  17. package/lib/browser/{nls-loader.js → preloader.js} +25 -6
  18. package/lib/browser/preloader.js.map +1 -0
  19. package/lib/browser/quick-input/quick-pick-service-impl.d.ts +1 -1
  20. package/lib/browser/quick-input/quick-pick-service-impl.d.ts.map +1 -1
  21. package/lib/browser/quick-input/quick-pick-service-impl.js.map +1 -1
  22. package/lib/browser/resource-context-key.js +2 -3
  23. package/lib/browser/resource-context-key.js.map +1 -1
  24. package/lib/browser/saveable.d.ts +6 -1
  25. package/lib/browser/saveable.d.ts.map +1 -1
  26. package/lib/browser/saveable.js.map +1 -1
  27. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  28. package/lib/browser/shell/application-shell.js +1 -0
  29. package/lib/browser/shell/application-shell.js.map +1 -1
  30. package/lib/browser/status-bar/status-bar.d.ts +2 -0
  31. package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
  32. package/lib/browser/status-bar/status-bar.js +2 -1
  33. package/lib/browser/status-bar/status-bar.js.map +1 -1
  34. package/lib/browser/tree/tree-widget.d.ts +1 -1
  35. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  36. package/lib/browser/tree/tree-widget.js +18 -7
  37. package/lib/browser/tree/tree-widget.js.map +1 -1
  38. package/lib/browser/widget-decoration.d.ts +11 -0
  39. package/lib/browser/widget-decoration.d.ts.map +1 -1
  40. package/lib/browser/widget-decoration.js +7 -0
  41. package/lib/browser/widget-decoration.js.map +1 -1
  42. package/lib/browser/widgets/select-component.d.ts +52 -0
  43. package/lib/browser/widgets/select-component.d.ts.map +1 -0
  44. package/lib/browser/widgets/select-component.js +287 -0
  45. package/lib/browser/widgets/select-component.js.map +1 -0
  46. package/lib/common/application-protocol.d.ts +3 -0
  47. package/lib/common/application-protocol.d.ts.map +1 -1
  48. package/lib/common/disposable.d.ts +1 -0
  49. package/lib/common/disposable.d.ts.map +1 -1
  50. package/lib/common/disposable.js +12 -4
  51. package/lib/common/disposable.js.map +1 -1
  52. package/lib/common/disposable.spec.d.ts +2 -0
  53. package/lib/common/disposable.spec.d.ts.map +1 -0
  54. package/lib/common/disposable.spec.js +31 -0
  55. package/lib/common/disposable.spec.js.map +1 -0
  56. package/lib/common/i18n/localization.d.ts +7 -5
  57. package/lib/common/i18n/localization.d.ts.map +1 -1
  58. package/lib/common/i18n/localization.js.map +1 -1
  59. package/lib/common/json-schema.d.ts +1 -0
  60. package/lib/common/json-schema.d.ts.map +1 -1
  61. package/lib/common/nls.js +24 -4
  62. package/lib/common/nls.js.map +1 -1
  63. package/lib/common/os.d.ts +5 -0
  64. package/lib/common/os.d.ts.map +1 -1
  65. package/lib/common/os.js +5 -0
  66. package/lib/common/os.js.map +1 -1
  67. package/lib/common/path.d.ts +20 -17
  68. package/lib/common/path.d.ts.map +1 -1
  69. package/lib/common/path.js +37 -0
  70. package/lib/common/path.js.map +1 -1
  71. package/lib/common/path.spec.js +37 -0
  72. package/lib/common/path.spec.js.map +1 -1
  73. package/lib/common/quick-pick-service.d.ts +1 -1
  74. package/lib/common/quick-pick-service.d.ts.map +1 -1
  75. package/lib/common/quick-pick-service.js +0 -15
  76. package/lib/common/quick-pick-service.js.map +1 -1
  77. package/lib/common/selection-service.d.ts +7 -0
  78. package/lib/common/selection-service.d.ts.map +1 -1
  79. package/lib/common/selection-service.js +5 -0
  80. package/lib/common/selection-service.js.map +1 -1
  81. package/lib/common/uri.d.ts +12 -1
  82. package/lib/common/uri.d.ts.map +1 -1
  83. package/lib/common/uri.js +14 -0
  84. package/lib/common/uri.js.map +1 -1
  85. package/lib/electron-browser/menu/electron-menu-contribution.d.ts +1 -0
  86. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  87. package/lib/electron-browser/menu/electron-menu-contribution.js +10 -4
  88. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  89. package/lib/electron-common/electron-token.d.ts +3 -3
  90. package/lib/electron-common/electron-token.d.ts.map +1 -1
  91. package/lib/electron-common/electron-token.js +4 -3
  92. package/lib/electron-common/electron-token.js.map +1 -1
  93. package/lib/node/backend-application-module.d.ts.map +1 -1
  94. package/lib/node/backend-application-module.js +3 -0
  95. package/lib/node/backend-application-module.js.map +1 -1
  96. package/lib/node/i18n/localization-backend-contribution.js +1 -1
  97. package/lib/node/i18n/localization-backend-contribution.js.map +1 -1
  98. package/lib/node/i18n/localization-contribution.d.ts +4 -3
  99. package/lib/node/i18n/localization-contribution.d.ts.map +1 -1
  100. package/lib/node/i18n/localization-contribution.js +15 -10
  101. package/lib/node/i18n/localization-contribution.js.map +1 -1
  102. package/lib/node/i18n/localization-provider.d.ts +2 -2
  103. package/lib/node/i18n/localization-provider.d.ts.map +1 -1
  104. package/lib/node/i18n/localization-provider.js +9 -4
  105. package/lib/node/i18n/localization-provider.js.map +1 -1
  106. package/lib/node/os-backend-application-contribution.d.ts +6 -0
  107. package/lib/node/os-backend-application-contribution.d.ts.map +1 -0
  108. package/lib/node/os-backend-application-contribution.js +38 -0
  109. package/lib/node/os-backend-application-contribution.js.map +1 -0
  110. package/package.json +5 -5
  111. package/src/browser/browser.ts +62 -0
  112. package/src/browser/common-frontend-contribution.ts +68 -10
  113. package/src/browser/preferences/preference-validation-service.spec.ts +59 -0
  114. package/src/browser/preferences/preference-validation-service.ts +85 -8
  115. package/src/browser/{nls-loader.ts → preloader.ts} +26 -4
  116. package/src/browser/quick-input/quick-pick-service-impl.ts +2 -2
  117. package/src/browser/resource-context-key.ts +2 -2
  118. package/src/browser/saveable.ts +3 -1
  119. package/src/browser/shell/application-shell.ts +1 -0
  120. package/src/browser/status-bar/status-bar.tsx +4 -1
  121. package/src/browser/style/select-component.css +96 -0
  122. package/src/browser/style/tree.css +6 -0
  123. package/src/browser/style/view-container.css +2 -2
  124. package/src/browser/tree/tree-widget.tsx +21 -9
  125. package/src/browser/widget-decoration.ts +14 -0
  126. package/src/browser/widgets/select-component.tsx +340 -0
  127. package/src/common/application-protocol.ts +3 -0
  128. package/src/common/disposable.spec.ts +30 -0
  129. package/src/common/disposable.ts +15 -4
  130. package/src/common/i18n/localization.ts +6 -3
  131. package/src/common/json-schema.ts +1 -0
  132. package/src/common/nls.ts +25 -4
  133. package/src/common/os.ts +6 -0
  134. package/src/common/path.spec.ts +44 -0
  135. package/src/common/path.ts +40 -0
  136. package/src/common/quick-pick-service.ts +1 -17
  137. package/src/common/selection-service.ts +8 -2
  138. package/src/common/uri.ts +26 -1
  139. package/src/electron-browser/menu/electron-menu-contribution.ts +11 -4
  140. package/src/electron-common/electron-token.ts +4 -3
  141. package/src/node/backend-application-module.ts +4 -0
  142. package/src/node/i18n/localization-backend-contribution.ts +1 -1
  143. package/src/node/i18n/localization-contribution.ts +21 -13
  144. package/src/node/i18n/localization-provider.ts +12 -7
  145. package/src/node/os-backend-application-contribution.ts +30 -0
  146. package/lib/browser/nls-loader.d.ts +0 -2
  147. package/lib/browser/nls-loader.d.ts.map +0 -1
  148. package/lib/browser/nls-loader.js.map +0 -1
@@ -1143,17 +1143,19 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
1143
1143
  protected async configureDisplayLanguage(): Promise<void> {
1144
1144
  const availableLanguages = await this.localizationProvider.getAvailableLanguages();
1145
1145
  const items: QuickPickItem[] = [];
1146
- for (const additionalLanguage of ['en', ...availableLanguages]) {
1147
- items.push({
1148
- label: additionalLanguage,
1149
- execute: async () => {
1150
- if (additionalLanguage !== nls.locale && await this.confirmRestart()) {
1151
- this.windowService.setSafeToShutDown();
1152
- window.localStorage.setItem(nls.localeId, additionalLanguage);
1153
- this.windowService.reload();
1146
+ for (const languageId of ['en', ...availableLanguages.map(e => e.languageId)]) {
1147
+ if (typeof languageId === 'string') {
1148
+ items.push({
1149
+ label: languageId,
1150
+ execute: async () => {
1151
+ if (languageId !== nls.locale && await this.confirmRestart()) {
1152
+ this.windowService.setSafeToShutDown();
1153
+ window.localStorage.setItem(nls.localeId, languageId);
1154
+ this.windowService.reload();
1155
+ }
1154
1156
  }
1155
- }
1156
- });
1157
+ });
1158
+ }
1157
1159
  }
1158
1160
  this.quickInputService?.showQuickPick(items,
1159
1161
  {
@@ -1589,6 +1591,34 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
1589
1591
  hc: Color.rgba(255, 255, 255, 0.12)
1590
1592
  }, description: 'Status bar item background color when hovering. The status bar is shown in the bottom of the window.'
1591
1593
  },
1594
+ {
1595
+ id: 'statusBarItem.errorBackground', defaults: {
1596
+ dark: Color.darken('errorBackground', 0.4),
1597
+ light: Color.darken('errorBackground', 0.4),
1598
+ hc: undefined,
1599
+ }, description: 'Status bar error items background color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.'
1600
+ },
1601
+ {
1602
+ id: 'statusBarItem.errorForeground', defaults: {
1603
+ dark: Color.white,
1604
+ light: Color.white,
1605
+ hc: Color.white
1606
+ }, description: 'Status bar error items foreground color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.'
1607
+ },
1608
+ {
1609
+ id: 'statusBarItem.warningBackground', defaults: {
1610
+ dark: Color.darken('warningBackground', 0.4),
1611
+ light: Color.darken('warningBackground', 0.4),
1612
+ hc: undefined
1613
+ }, description: 'Status bar warning items background color. Warning items stand out from other status bar entries to indicate warning conditions. The status bar is shown in the bottom of the window.'
1614
+ },
1615
+ {
1616
+ id: 'statusBarItem.warningForeground', defaults: {
1617
+ dark: Color.white,
1618
+ light: Color.white,
1619
+ hc: Color.white
1620
+ }, description: 'Status bar warning items foreground color. Warning items stand out from other status bar entries to indicate warning conditions. The status bar is shown in the bottom of the window.'
1621
+ },
1592
1622
 
1593
1623
  // Quickinput colors should be aligned with https://code.visualstudio.com/api/references/theme-color#quick-picker
1594
1624
  // if not yet contributed by Monaco, check runtime css variables to learn.
@@ -1765,6 +1795,34 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
1765
1795
  { id: 'welcomePage.buttonHoverBackground', defaults: { dark: Color.rgba(200, 235, 255, .072), light: Color.rgba(0, 0, 0, .10) }, description: 'Hover background color for the buttons on the Welcome page.' },
1766
1796
  { id: 'walkThrough.embeddedEditorBackground', defaults: { dark: Color.rgba(0, 0, 0, .4), light: '#f4f4f4' }, description: 'Background color for the embedded editors on the Interactive Playground.' },
1767
1797
 
1798
+ // Dropdown colors should be aligned with https://code.visualstudio.com/api/references/theme-color#dropdown-control
1799
+
1800
+ {
1801
+ id: 'dropdown.background', defaults: {
1802
+ light: Color.white,
1803
+ dark: '#3C3C3C',
1804
+ hc: Color.black
1805
+ }, description: 'Dropdown background.'
1806
+ },
1807
+ {
1808
+ id: 'dropdown.listBackground', defaults: {
1809
+ hc: Color.black
1810
+ }, description: 'Dropdown list background.'
1811
+ },
1812
+ {
1813
+ id: 'dropdown.foreground', defaults: {
1814
+ dark: '#F0F0F0',
1815
+ hc: Color.white
1816
+ }, description: 'Dropdown foreground.'
1817
+ },
1818
+ {
1819
+ id: 'dropdown.border', defaults: {
1820
+ light: '#CECECE',
1821
+ dark: 'dropdown.background',
1822
+ hc: '#6FC3DF'
1823
+ }, description: 'Dropdown border.'
1824
+ },
1825
+
1768
1826
  // Settings Editor colors should be aligned with https://code.visualstudio.com/api/references/theme-color#settings-editor-colors
1769
1827
  {
1770
1828
  id: 'settings.headerForeground', defaults: {
@@ -20,6 +20,7 @@ import { JsonType, PreferenceItem, PreferenceSchemaProvider } from './preference
20
20
  import { PreferenceLanguageOverrideService } from './preference-language-override-service';
21
21
  import * as assert from 'assert';
22
22
  import { JSONValue } from '@phosphor/coreutils';
23
+ import { IJSONSchema } from 'src/common/json-schema';
23
24
 
24
25
  /* eslint-disable no-unused-expressions,no-null/no-null */
25
26
 
@@ -194,6 +195,39 @@ describe('Preference Validation Service', () => {
194
195
  assert.deepStrictEqual(actual, expected);
195
196
  });
196
197
  });
198
+ describe('should validate tuples', () => {
199
+ const schema: PreferenceItem & { items: IJSONSchema[] } = {
200
+ 'type': 'array',
201
+ 'items': [{
202
+ 'type': 'number',
203
+ },
204
+ {
205
+ 'type': 'string',
206
+ }],
207
+ };
208
+ it('good input -> returns same object', () => {
209
+ const expected = [1, 'two'];
210
+ assert.strictEqual(validateBySchema(expected, schema), expected);
211
+ });
212
+ it('bad input -> should use the default if supplied present and valid', () => {
213
+ const defaultValue = [8, 'three'];
214
+ const withDefault = { ...schema, default: defaultValue };
215
+ assert.strictEqual(validateBySchema('not even an array!', withDefault), defaultValue);
216
+ assert.strictEqual(validateBySchema(['first fails', 'second ok'], withDefault), defaultValue);
217
+ assert.strictEqual(validateBySchema([], withDefault), defaultValue);
218
+ assert.strictEqual(validateBySchema([2, ['second fails']], withDefault), defaultValue);
219
+ });
220
+ it('bad input -> in the absence of a default, it should return any good values or the default for each subschema', () => {
221
+ const withSubDefault: PreferenceItem = { ...schema, items: [{ type: 'string', default: 'cool' }, ...schema.items] };
222
+ assert.deepStrictEqual(validateBySchema('not an array', withSubDefault), ['cool', 0, '']);
223
+ assert.deepStrictEqual(validateBySchema([2, 8, null], withSubDefault), ['cool', 8, '']);
224
+ });
225
+ it("bad input -> uses the default, but fixes fields that don't match schema", () => {
226
+ const defaultValue = [8, 8];
227
+ const withDefault = { ...schema, default: defaultValue };
228
+ assert.deepStrictEqual(validateBySchema('something invalid', withDefault), [8, '']);
229
+ });
230
+ });
197
231
  describe('should validate type arrays', () => {
198
232
  const type: JsonType[] = ['boolean', 'string', 'number'];
199
233
  it('good input -> returns same value', () => {
@@ -232,6 +266,31 @@ describe('Preference Validation Service', () => {
232
266
  assert.strictEqual(validateBySchema({}, { ...schema, default: undefined }), 1);
233
267
  });
234
268
  });
269
+ describe('should validate oneOfs', () => {
270
+ // Between 4 and 6 should be rejected
271
+ const schema: PreferenceItem = { oneOf: [{ type: 'number', minimum: 1, maximum: 6 }, { type: 'number', minimum: 4, maximum: 10 }], default: 8 };
272
+ it('good input -> returns same value', () => {
273
+ assert.strictEqual(validateBySchema(2, schema), 2);
274
+ assert.strictEqual(validateBySchema(7, schema), 7);
275
+ });
276
+ it('bad input -> returns default if present and valid', () => {
277
+ assert.strictEqual(validateBySchema(5, schema), 8);
278
+ });
279
+ it('bad input -> returns value if default absent or invalid.', () => {
280
+ assert.strictEqual(validateBySchema(5, { ...schema, default: undefined }), 5);
281
+ });
282
+ });
283
+ describe('should validate consts', () => {
284
+ const schema: PreferenceItem = { const: { 'the only': 'possible value' }, default: 'ignore-the-default' };
285
+ const goodValue = { 'the only': 'possible value' };
286
+ it('good input -> returns same value', () => {
287
+ assert.strictEqual(validateBySchema(goodValue, schema), goodValue);
288
+ });
289
+ it('bad input -> returns the const value for any other value', () => {
290
+ assert.deepStrictEqual(validateBySchema('literally anything else', schema), goodValue);
291
+ assert.deepStrictEqual(validateBySchema('ignore-the-default', schema), goodValue);
292
+ });
293
+ });
235
294
  describe('should maintain triple equality for valid object types', () => {
236
295
  const arraySchema: PreferenceItem = { type: 'array', items: { type: 'string' } };
237
296
  it('maintains triple equality for arrays', () => {
@@ -37,6 +37,8 @@ export interface PreferenceValidationResult<T extends JSONValue> {
37
37
  messages: string[];
38
38
  }
39
39
 
40
+ type ValidatablePreferenceTuple = ValidatablePreference & ({ items: ValidatablePreference[] } | { prefixItems: ValidatablePreference[] });
41
+
40
42
  @injectable()
41
43
  export class PreferenceValidationService {
42
44
  @inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider;
@@ -75,12 +77,18 @@ export class PreferenceValidationService {
75
77
  console.warn('Request to validate preference with no schema registered:', key);
76
78
  return value;
77
79
  }
80
+ if (schema.const !== undefined) {
81
+ return this.validateConst(key, value, schema as ValidatablePreference & { const: JSONValue });
82
+ }
78
83
  if (Array.isArray(schema.enum)) {
79
84
  return this.validateEnum(key, value, schema as ValidatablePreference & { enum: JSONValue[] });
80
85
  }
81
86
  if (Array.isArray(schema.anyOf)) {
82
87
  return this.validateAnyOf(key, value, schema as ValidatablePreference & { anyOf: ValidatablePreference[] });
83
88
  }
89
+ if (Array.isArray(schema.oneOf)) {
90
+ return this.validateOneOf(key, value, schema as ValidatablePreference & { oneOf: ValidatablePreference[] });
91
+ }
84
92
  if (schema.type === undefined) {
85
93
  console.warn('Request to validate preference with no type information:', key);
86
94
  return value;
@@ -149,6 +157,28 @@ export class PreferenceValidationService {
149
157
  return candidate;
150
158
  }
151
159
 
160
+ protected validateOneOf(key: string, value: JSONValue, schema: ValidatablePreference & { oneOf: ValidatablePreference[] }): JSONValue {
161
+ let passed = false;
162
+ for (const subSchema of schema.oneOf) {
163
+ const validValue = this.validateBySchema(key, value, subSchema);
164
+ if (!passed && validValue === value) {
165
+ passed = true;
166
+ } else if (passed && validValue === value) {
167
+ passed = false;
168
+ break;
169
+ }
170
+ }
171
+ if (passed) {
172
+ return value;
173
+ }
174
+ if (schema.default !== undefined || schema.defaultValue !== undefined) {
175
+ const configuredDefault = this.getDefaultFromSchema(schema);
176
+ return this.validateOneOf(key, configuredDefault, { ...schema, default: undefined, defaultValue: undefined });
177
+ }
178
+ console.log(`While validating ${key}, failed to find a valid value or default value. Using configured value ${value}.`);
179
+ return value;
180
+ }
181
+
152
182
  protected mapValidators(key: string, value: JSONValue, validators: Iterable<(value: JSONValue) => JSONValue>): JSONValue {
153
183
  const candidates = [];
154
184
  for (const validator of validators) {
@@ -160,26 +190,73 @@ export class PreferenceValidationService {
160
190
  }
161
191
  return candidates[0];
162
192
  }
163
-
164
193
  protected validateArray(key: string, value: JSONValue, schema: ValidatablePreference): JSONValue[] {
165
194
  const candidate = Array.isArray(value) ? value : this.getDefaultFromSchema(schema);
166
195
  if (!Array.isArray(candidate)) {
167
196
  return [];
168
197
  }
169
- if (!schema.items || Array.isArray(schema.items)) { // Arrays were allowed in some draft of JSON schema, but never officially supported.
198
+ if (!schema.items && !schema.prefixItems) {
170
199
  console.warn('Requested validation of array without item specification:', key);
171
200
  return candidate;
172
201
  }
173
- const valid = [];
174
- for (const item of candidate) {
175
- const validated = this.validateBySchema(key, item, schema.items);
176
- if (validated === item) {
177
- valid.push(item);
178
- }
202
+ if (Array.isArray(schema.items) || Array.isArray(schema.prefixItems)) {
203
+ return this.validateTuple(key, value, schema as ValidatablePreferenceTuple);
179
204
  }
205
+ const itemSchema = schema.items!;
206
+ const valid = candidate.filter(item => this.validateBySchema(key, item, itemSchema) === item);
180
207
  return valid.length === candidate.length ? candidate : valid;
181
208
  }
182
209
 
210
+ protected validateTuple(key: string, value: JSONValue, schema: ValidatablePreferenceTuple): JSONValue[] {
211
+ const defaultValue = this.getDefaultFromSchema(schema);
212
+ const maybeCandidate = Array.isArray(value) ? value : defaultValue;
213
+ // If we find that the provided value is not valid, we immediately bail and try the default value instead.
214
+ const shouldTryDefault = Array.isArray(schema.defaultValue ?? schema.default) && !PreferenceProvider.deepEqual(defaultValue, maybeCandidate);
215
+ const tryDefault = () => this.validateTuple(key, defaultValue, schema);
216
+ const candidate = Array.isArray(maybeCandidate) ? maybeCandidate : [];
217
+ // Only `prefixItems` is officially part of the JSON Schema spec, but `items` as array was part of a draft and was used by VSCode.
218
+ const tuple = (schema.prefixItems ?? schema.items) as Required<ValidatablePreference>['prefixItems'];
219
+ const lengthIsWrong = candidate.length < tuple.length || (candidate.length > tuple.length && !schema.additionalItems);
220
+ if (lengthIsWrong && shouldTryDefault) { return tryDefault(); }
221
+ let valid = true;
222
+ const validItems: JSONValue[] = [];
223
+ for (const [index, subschema] of tuple.entries()) {
224
+ const targetItem = candidate[index];
225
+ const validatedItem = targetItem === undefined ? this.getDefaultFromSchema(subschema) : this.validateBySchema(key, targetItem, subschema);
226
+ valid &&= validatedItem === targetItem;
227
+ if (!valid && shouldTryDefault) { return tryDefault(); }
228
+ validItems.push(validatedItem);
229
+ };
230
+ if (candidate.length > tuple.length) {
231
+ if (!schema.additionalItems) {
232
+ return validItems;
233
+ } else if (schema.additionalItems === true && !valid) {
234
+ validItems.push(...candidate.slice(tuple.length));
235
+ return validItems;
236
+ } else if (schema.additionalItems !== true) {
237
+ const applicableSchema = schema.additionalItems;
238
+ for (let i = tuple.length; i < candidate.length; i++) {
239
+ const targetItem = candidate[i];
240
+ const validatedItem = this.validateBySchema(key, targetItem, applicableSchema);
241
+ if (validatedItem === targetItem) {
242
+ validItems.push(targetItem);
243
+ } else {
244
+ valid = false;
245
+ if (shouldTryDefault) { return tryDefault(); }
246
+ }
247
+ }
248
+ }
249
+ }
250
+ return valid ? candidate : validItems;
251
+ }
252
+
253
+ protected validateConst(key: string, value: JSONValue, schema: ValidatablePreference & { const: JSONValue }): JSONValue {
254
+ if (PreferenceProvider.deepEqual(value, schema.const)) {
255
+ return value;
256
+ }
257
+ return schema.const;
258
+ }
259
+
183
260
  protected validateEnum(key: string, value: JSONValue, schema: ValidatablePreference & { enum: JSONValue[] }): JSONValue {
184
261
  const options = schema.enum;
185
262
  if (options.some(option => PreferenceProvider.deepEqual(option, value))) {
@@ -1,5 +1,5 @@
1
1
  // *****************************************************************************
2
- // Copyright (C) 2021 TypeFox and others.
2
+ // Copyright (C) 2022 TypeFox and others.
3
3
  //
4
4
  // This program and the accompanying materials are made available under the
5
5
  // terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,9 +16,15 @@
16
16
 
17
17
  import { nls } from '../common/nls';
18
18
  import { Endpoint } from './endpoint';
19
+ import { OS } from '../common/os';
19
20
  import { FrontendApplicationConfigProvider } from './frontend-application-config-provider';
20
21
 
21
- export async function loadTranslations(): Promise<void> {
22
+ function fetchFrom(path: string): Promise<Response> {
23
+ const endpoint = new Endpoint({ path }).getRestUrl().toString();
24
+ return fetch(endpoint);
25
+ }
26
+
27
+ async function loadTranslations(): Promise<void> {
22
28
  const defaultLocale = FrontendApplicationConfigProvider.get().defaultLocale;
23
29
  if (defaultLocale && !nls.locale) {
24
30
  Object.assign(nls, {
@@ -26,8 +32,24 @@ export async function loadTranslations(): Promise<void> {
26
32
  });
27
33
  }
28
34
  if (nls.locale) {
29
- const endpoint = new Endpoint({ path: '/i18n/' + nls.locale }).getRestUrl().toString();
30
- const response = await fetch(endpoint);
35
+ const response = await fetchFrom(`/i18n/${nls.locale}`);
31
36
  nls.localization = await response.json();
32
37
  }
33
38
  }
39
+
40
+ async function loadBackendOS(): Promise<void> {
41
+ const response = await fetchFrom('/os');
42
+ const osType = await response.text() as OS.Type;
43
+ const isWindows = osType === 'Windows';
44
+ const isOSX = osType === 'OSX';
45
+ OS.backend.isOSX = isOSX;
46
+ OS.backend.isWindows = isWindows;
47
+ OS.backend.type = () => osType;
48
+ }
49
+
50
+ export async function preload(): Promise<void> {
51
+ await Promise.allSettled([
52
+ loadTranslations(),
53
+ loadBackendOS()
54
+ ]);
55
+ }
@@ -46,7 +46,7 @@ export class QuickPickServiceImpl implements QuickPickService {
46
46
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
47
  private items: Array<any> = [];
48
48
 
49
- async show<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T> {
49
+ async show<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T | undefined> {
50
50
  this.items = items;
51
51
  const opts = Object.assign({}, options, {
52
52
  onDidAccept: () => this.onDidAcceptEmitter.fire(),
@@ -56,7 +56,7 @@ export class QuickPickServiceImpl implements QuickPickService {
56
56
  onDidHide: () => this.onDidHideEmitter.fire(),
57
57
  onDidTriggerButton: (btn: QuickInputButtonHandle) => this.onDidTriggerButtonEmitter.fire(btn),
58
58
  });
59
- return this.quickInputService?.showQuickPick(this.items, opts);
59
+ return this.quickInputService?.showQuickPick<T>(this.items, opts);
60
60
  }
61
61
 
62
62
  hide(): void {
@@ -59,8 +59,8 @@ export class ResourceContextKey {
59
59
  this.resourceFileName.set(resourceUri && resourceUri.path.base);
60
60
  this.resourceExtname.set(resourceUri && resourceUri.path.ext);
61
61
  this.resourceLangId.set(resourceUri && this.getLanguageId(resourceUri));
62
- this.resourceDirName.set(resourceUri && Uri.parse(resourceUri.path.dir.toString()).fsPath);
63
- this.resourcePath.set(resourceUri && resourceUri['codeUri'].fsPath);
62
+ this.resourceDirName.set(resourceUri && resourceUri.path.dir.fsPath());
63
+ this.resourcePath.set(resourceUri && resourceUri.path.fsPath());
64
64
  }
65
65
 
66
66
  protected getLanguageId(uri: URI | undefined): string | undefined {
@@ -37,7 +37,7 @@ export interface Saveable {
37
37
  /**
38
38
  * Creates a snapshot of the dirty state.
39
39
  */
40
- createSnapshot?(): object;
40
+ createSnapshot?(): Saveable.Snapshot;
41
41
  /**
42
42
  * Applies the given snapshot to the dirty state.
43
43
  */
@@ -56,6 +56,8 @@ export namespace Saveable {
56
56
  */
57
57
  soft?: boolean
58
58
  }
59
+
60
+ export type Snapshot = { value: string } | { read(): string | null };
59
61
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
62
  export function isSource(arg: any): arg is SaveableSource {
61
63
  return !!arg && ('saveable' in arg) && is(arg.saveable);
@@ -1418,6 +1418,7 @@ export class ApplicationShell extends Widget {
1418
1418
  this.statusBar.removeElement(BOTTOM_PANEL_TOGGLE_ID);
1419
1419
  } else {
1420
1420
  const element: StatusBarEntry = {
1421
+ name: 'Toggle Bottom Panel',
1421
1422
  text: '$(codicon-window)',
1422
1423
  alignment: StatusBarAlignment.RIGHT,
1423
1424
  tooltip: 'Toggle Bottom Panel',
@@ -38,7 +38,9 @@ export interface StatusBarEntry {
38
38
  */
39
39
  text: string;
40
40
  alignment: StatusBarAlignment;
41
+ name?: string;
41
42
  color?: string;
43
+ backgroundColor?: string;
42
44
  className?: string;
43
45
  tooltip?: string;
44
46
  command?: string;
@@ -195,7 +197,8 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
195
197
  }
196
198
 
197
199
  attrs.style = {
198
- color: entry.color || this.color
200
+ color: entry.color || this.color,
201
+ backgroundColor: entry.backgroundColor
199
202
  };
200
203
 
201
204
  return attrs;
@@ -0,0 +1,96 @@
1
+ /********************************************************************************
2
+ * Copyright (C) 2022 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 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ .theia-select-component {
18
+ background-color: var(--theia-dropdown-background);
19
+ outline: var(--theia-dropdown-border) solid 1px;
20
+ outline-offset: -1px;
21
+ min-height: 23px;
22
+ min-width: 90px;
23
+ padding: 0px 8px;
24
+ display: flex;
25
+ align-items: center;
26
+ user-select: none;
27
+ }
28
+
29
+ .theia-select-component .theia-select-component-label {
30
+ width: 100%;
31
+ color: var(--theia-dropdown-foreground);
32
+ white-space: nowrap;
33
+ text-overflow: ellipsis;
34
+ overflow: hidden;
35
+ }
36
+
37
+ .theia-select-component:focus {
38
+ outline-color: var(--theia-focusBorder);
39
+ }
40
+
41
+ .theia-select-component-dropdown {
42
+ font-family: var(--theia-ui-font-family);
43
+ font-size: var(--theia-ui-font-size1);
44
+ color: var(--theia-foreground);
45
+ background-color: var(--theia-settings-dropdownBackground);
46
+ outline: var(--theia-focusBorder) solid 1px;
47
+ outline-offset: -1px;
48
+ user-select: none;
49
+ }
50
+
51
+ .theia-select-component-dropdown .theia-select-component-option {
52
+ text-overflow: ellipsis;
53
+ overflow: hidden;
54
+ display: flex;
55
+ padding: 2px 5px;
56
+ }
57
+
58
+ .theia-select-component-dropdown .theia-select-component-description {
59
+ padding: 6px 5px;
60
+ }
61
+
62
+ .theia-select-component-dropdown .theia-select-component-description:first-child {
63
+ border-bottom: 1px solid var(--theia-editorWidget-border);
64
+ margin-bottom: 2px;
65
+ }
66
+
67
+ .theia-select-component-dropdown .theia-select-component-description:last-child {
68
+ border-top: 1px solid var(--theia-editorWidget-border);
69
+ margin-top: 2px;
70
+ }
71
+
72
+ .theia-select-component-dropdown .theia-select-component-option .theia-select-component-option-value {
73
+ width: 100%;
74
+ }
75
+
76
+ .theia-select-component-dropdown .theia-select-component-option .theia-select-component-option-detail {
77
+ padding-left: 4px;
78
+ }
79
+
80
+ .theia-select-component-dropdown .theia-select-component-option:not(.selected) .theia-select-component-option-detail {
81
+ color: var(--theia-textLink-foreground);
82
+ }
83
+
84
+ .theia-select-component-dropdown .theia-select-component-option.selected {
85
+ color: var(--theia-list-activeSelectionForeground);
86
+ background: var(--theia-list-activeSelectionBackground);
87
+ outline: var(--theia-focusBorder) solid 1px;
88
+ outline-offset: -1px;
89
+ }
90
+
91
+ .theia-select-component-dropdown .theia-select-component-separator {
92
+ width: 84px;
93
+ height: 1px;
94
+ margin: 3px 3px;
95
+ background: var(--theia-foreground);
96
+ }
@@ -116,12 +116,15 @@
116
116
  .theia-TreeNode.theia-mod-not-selectable {
117
117
  color: var(--theia-descriptionForeground);
118
118
  }
119
+
119
120
  .theia-TreeNode.theia-mod-not-selectable:hover {
120
121
  background: none;
121
122
  cursor: default;
122
123
  }
123
124
 
124
125
  .theia-TreeNodeSegment {
126
+ display: flex;
127
+ align-items: center;
125
128
  flex-grow: 0;
126
129
  user-select: none;
127
130
  white-space: nowrap;
@@ -137,6 +140,7 @@
137
140
  .theia-TreeNodeTail {
138
141
  min-width: 1rem;
139
142
  text-align: center;
143
+ justify-content: center;
140
144
  }
141
145
 
142
146
  .theia-TreeNodeSegment mark {
@@ -159,10 +163,12 @@
159
163
  height: var(--theia-content-line-height);
160
164
  border-right: var(--theia-border-width) solid transparent;
161
165
  }
166
+
162
167
  .theia-tree-node-indent.always,
163
168
  .theia-TreeContainer:hover .theia-tree-node-indent.hover {
164
169
  border-color: var(--theia-tree-inactiveIndentGuidesStroke);
165
170
  }
171
+
166
172
  .theia-tree-node-indent.active {
167
173
  border-color: var(--theia-tree-indentGuidesStroke);
168
174
  }
@@ -75,11 +75,11 @@
75
75
  }
76
76
 
77
77
  .p-Widget > .theia-view-container-part-header {
78
- border-top: 1px solid var(--theia-sideBarSectionHeader-border);
78
+ box-shadow: 0 1px 0 var(--theia-sideBarSectionHeader-border) inset;
79
79
  }
80
80
 
81
81
  .p-Widget.p-first-visible > .theia-view-container-part-header {
82
- border-top: none;
82
+ box-shadow: none;
83
83
  }
84
84
 
85
85
  .theia-view-container-part-header .theia-ExpansionToggle {
@@ -806,19 +806,31 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
806
806
  return this.renderTailDecorationsForNode(node, props, tailDecorations);
807
807
  }
808
808
 
809
- protected renderTailDecorationsForNode(node: TreeNode, props: NodeProps, tailDecorations:
810
- (TreeDecoration.TailDecoration | TreeDecoration.TailDecorationIcon | TreeDecoration.TailDecorationIconClass)[]): React.ReactNode {
809
+ protected renderTailDecorationsForNode(node: TreeNode, props: NodeProps, tailDecorations: TreeDecoration.TailDecoration.AnyPartial[]): React.ReactNode {
810
+ let dotDecoration: TreeDecoration.TailDecoration.AnyPartial | undefined;
811
+ const otherDecorations: TreeDecoration.TailDecoration.AnyPartial[] = [];
812
+ tailDecorations.reverse().forEach(decoration => {
813
+ if (TreeDecoration.TailDecoration.isDotDecoration(decoration)) {
814
+ dotDecoration ||= decoration;
815
+ } else if (decoration.data || decoration.icon || decoration.iconClass) {
816
+ otherDecorations.push(decoration);
817
+ }
818
+ });
819
+ const decorationsToRender = dotDecoration ? [dotDecoration, ...otherDecorations] : otherDecorations;
811
820
  return <React.Fragment>
812
- {tailDecorations.reverse().map((decoration, index) => {
813
- const { tooltip } = decoration;
814
- const { data, fontData } = decoration as TreeDecoration.TailDecoration;
815
- const color = (decoration as TreeDecoration.TailDecorationIcon).color;
821
+ {decorationsToRender.map((decoration, index) => {
822
+ const { tooltip, data, fontData, color, icon, iconClass } = decoration;
823
+ const iconToRender = icon ?? iconClass;
816
824
  const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS].join(' ');
817
825
  const style = fontData ? this.applyFontStyles({}, fontData) : color ? { color } : undefined;
818
- const icon = (decoration as TreeDecoration.TailDecorationIcon).icon || (decoration as TreeDecoration.TailDecorationIconClass).iconClass;
819
- const content = data ? data : icon ? <span key={node.id + 'icon' + index} className={this.getIconClass(icon)}></span> : '';
826
+ const content = data ? data : iconToRender
827
+ ? <span
828
+ key={node.id + 'icon' + index}
829
+ className={this.getIconClass(iconToRender, iconToRender === 'circle' ? [TreeDecoration.Styles.DECORATOR_SIZE_CLASS] : [])}
830
+ ></span>
831
+ : '';
820
832
  return <div key={node.id + className + index} className={className} style={style} title={tooltip}>
821
- {content}{index !== tailDecorations.length - 1 ? ',' : ''}
833
+ {content}{index !== decorationsToRender.length - 1 ? ',' : ''}
822
834
  </div>;
823
835
  })}
824
836
  </React.Fragment>;
@@ -97,6 +97,20 @@ export namespace WidgetDecoration {
97
97
  */
98
98
  readonly fontData?: FontData;
99
99
  }
100
+
101
+ export namespace TailDecoration {
102
+ /**
103
+ * Combines all fields of all `TailDecoration` variants
104
+ */
105
+ export type AnyPartial = Partial<TailDecoration & TailDecorationIcon & TailDecorationIconClass>;
106
+ /**
107
+ * Represents any permissible concrete `TailDecoration` variation.
108
+ */
109
+ export type AnyConcrete = TailDecoration | TailDecorationIcon | TailDecorationIconClass;
110
+ export function isDotDecoration(decoration: AnyPartial): decoration is TailDecorationIcon {
111
+ return decoration.icon === 'circle';
112
+ }
113
+ }
100
114
  export interface TailDecorationIcon extends BaseTailDecoration {
101
115
  /**
102
116
  * This should be the name of the Font Awesome icon with out the `fa fa-` prefix, just the name, for instance `paw`.