@theia/core 1.70.0-next.26 → 1.70.0-next.34

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 (67) hide show
  1. package/lib/browser/catalog.json +19 -3
  2. package/lib/browser/quick-input/quick-input-service.spec.js +53 -9
  3. package/lib/browser/quick-input/quick-input-service.spec.js.map +1 -1
  4. package/lib/browser/tree/fuzzy-search.d.ts +1 -60
  5. package/lib/browser/tree/fuzzy-search.d.ts.map +1 -1
  6. package/lib/browser/tree/fuzzy-search.js +3 -58
  7. package/lib/browser/tree/fuzzy-search.js.map +1 -1
  8. package/lib/browser/window/default-window-service.d.ts +2 -1
  9. package/lib/browser/window/default-window-service.d.ts.map +1 -1
  10. package/lib/browser/window/default-window-service.js +5 -1
  11. package/lib/browser/window/default-window-service.js.map +1 -1
  12. package/lib/browser/window/test/mock-window-service.d.ts +2 -1
  13. package/lib/browser/window/test/mock-window-service.d.ts.map +1 -1
  14. package/lib/browser/window/test/mock-window-service.js +2 -1
  15. package/lib/browser/window/test/mock-window-service.js.map +1 -1
  16. package/lib/browser/window/window-service.d.ts +8 -1
  17. package/lib/browser/window/window-service.d.ts.map +1 -1
  18. package/lib/common/fuzzy-match-utils.d.ts +27 -0
  19. package/lib/common/fuzzy-match-utils.d.ts.map +1 -0
  20. package/lib/common/fuzzy-match-utils.js +96 -0
  21. package/lib/common/fuzzy-match-utils.js.map +1 -0
  22. package/lib/common/fuzzy-match-utils.spec.d.ts +2 -0
  23. package/lib/common/fuzzy-match-utils.spec.d.ts.map +1 -0
  24. package/lib/common/fuzzy-match-utils.spec.js +109 -0
  25. package/lib/common/fuzzy-match-utils.spec.js.map +1 -0
  26. package/lib/common/fuzzy-search.d.ts +63 -0
  27. package/lib/common/fuzzy-search.d.ts.map +1 -0
  28. package/lib/common/fuzzy-search.js +101 -0
  29. package/lib/common/fuzzy-search.js.map +1 -0
  30. package/lib/common/fuzzy-search.spec.d.ts.map +1 -0
  31. package/lib/{browser/tree → common}/fuzzy-search.spec.js +20 -1
  32. package/lib/common/fuzzy-search.spec.js.map +1 -0
  33. package/lib/common/quick-pick-service.d.ts.map +1 -1
  34. package/lib/common/quick-pick-service.js +34 -7
  35. package/lib/common/quick-pick-service.js.map +1 -1
  36. package/lib/electron-browser/window/electron-window-service.d.ts +3 -2
  37. package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
  38. package/lib/electron-browser/window/electron-window-service.js +5 -2
  39. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  40. package/lib/electron-common/electron-main-window-service.d.ts +2 -1
  41. package/lib/electron-common/electron-main-window-service.d.ts.map +1 -1
  42. package/lib/electron-main/electron-main-application.d.ts +1 -0
  43. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  44. package/lib/electron-main/electron-main-application.js +6 -0
  45. package/lib/electron-main/electron-main-application.js.map +1 -1
  46. package/lib/electron-main/electron-main-window-service-impl.d.ts +2 -1
  47. package/lib/electron-main/electron-main-window-service-impl.d.ts.map +1 -1
  48. package/lib/electron-main/electron-main-window-service-impl.js +6 -2
  49. package/lib/electron-main/electron-main-window-service-impl.js.map +1 -1
  50. package/package.json +4 -4
  51. package/src/browser/quick-input/quick-input-service.spec.ts +58 -9
  52. package/src/browser/tree/fuzzy-search.ts +2 -120
  53. package/src/browser/window/default-window-service.ts +6 -1
  54. package/src/browser/window/test/mock-window-service.ts +2 -1
  55. package/src/browser/window/window-service.ts +9 -1
  56. package/src/common/fuzzy-match-utils.spec.ts +141 -0
  57. package/src/common/fuzzy-match-utils.ts +78 -0
  58. package/src/{browser/tree → common}/fuzzy-search.spec.ts +23 -1
  59. package/src/common/fuzzy-search.ts +158 -0
  60. package/src/common/quick-pick-service.ts +44 -9
  61. package/src/electron-browser/window/electron-window-service.ts +7 -4
  62. package/src/electron-common/electron-main-window-service.ts +2 -1
  63. package/src/electron-main/electron-main-application.ts +7 -0
  64. package/src/electron-main/electron-main-window-service-impl.ts +7 -2
  65. package/lib/browser/tree/fuzzy-search.spec.d.ts.map +0 -1
  66. package/lib/browser/tree/fuzzy-search.spec.js.map +0 -1
  67. /package/lib/{browser/tree → common}/fuzzy-search.spec.d.ts +0 -0
@@ -0,0 +1,78 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 EclipseSource 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
+ /**
18
+ * Returns the index of the first case-insensitive substring match of `pattern` in `text`,
19
+ * or `-1` if `pattern` is not a substring. Returns `0` for an empty pattern.
20
+ */
21
+ export function findSubstringIndex(text: string, pattern: string): number {
22
+ if (!pattern) { return 0; }
23
+ return text.toLowerCase().indexOf(pattern.toLowerCase());
24
+ }
25
+
26
+ export function hasSubstringMatch(text: string, pattern: string): boolean {
27
+ return findSubstringIndex(text, pattern) !== -1;
28
+ }
29
+
30
+ const SEGMENT_SEPARATOR = /[\p{P}\s]+/u;
31
+
32
+ /**
33
+ * Tests whether `pattern` is a "prefix match" for `text`, accounting for punctuation-separated segments.
34
+ *
35
+ * The pattern is split on punctuation into query parts. The text is split on punctuation into segments.
36
+ * It is a prefix match when the first query part matches the start of segment 0, and each subsequent
37
+ * query part matches the start of a later segment, in order.
38
+ *
39
+ * Examples:
40
+ * - `hasPrefixMatch("workspace-server", "works-ser")` → true
41
+ * - `hasPrefixMatch("backend-workspace-service", "works-ser")` → false (first segment doesn't match)
42
+ * - `hasPrefixMatch("fontSize", "font")` → true (single-part prefix)
43
+ */
44
+ export function hasPrefixMatch(text: string, pattern: string): boolean {
45
+ if (!pattern) { return true; }
46
+ const queryParts = pattern.toLowerCase().split(SEGMENT_SEPARATOR).filter(Boolean);
47
+ if (queryParts.length === 0) { return true; }
48
+ const textSegments = text.toLowerCase().split(SEGMENT_SEPARATOR).filter(Boolean);
49
+ if (textSegments.length === 0) { return false; }
50
+ // First query part must match the start of the first text segment.
51
+ if (!textSegments[0].startsWith(queryParts[0])) { return false; }
52
+ let segIdx = 1;
53
+ for (let qIdx = 1; qIdx < queryParts.length; qIdx++) {
54
+ let found = false;
55
+ while (segIdx < textSegments.length) {
56
+ if (textSegments[segIdx].startsWith(queryParts[qIdx])) {
57
+ segIdx++;
58
+ found = true;
59
+ break;
60
+ }
61
+ segIdx++;
62
+ }
63
+ if (!found) { return false; }
64
+ }
65
+ return true;
66
+ }
67
+
68
+ /**
69
+ * Returns a numeric rank for how well `pattern` matches `text`:
70
+ * - 0: prefix match (best)
71
+ * - 1: substring match
72
+ * - 2: fuzzy-only match (worst)
73
+ */
74
+ export function matchRank(text: string, pattern: string): number {
75
+ if (hasPrefixMatch(text, pattern)) { return 0; }
76
+ if (hasSubstringMatch(text, pattern)) { return 1; }
77
+ return 2;
78
+ }
@@ -71,7 +71,9 @@ describe('fuzzy-search', () => {
71
71
  });
72
72
 
73
73
  ([
74
- ['con', ['configs', 'base.tsconfig.json', 'tsconfig.json', 'base.nyc.json', 'CONTRIBUTING.MD']],
74
+ // "con" prefix matches (configs, CONTRIBUTING.MD) first, then substring matches (base.tsconfig.json, tsconfig.json), then fuzzy-only (base.nyc.json)
75
+ ['con', ['configs', 'base.tsconfig.json', 'tsconfig.json', 'base.nyc.json', 'CONTRIBUTING.MD'],
76
+ ['configs', 'CONTRIBUTING.MD', 'base.tsconfig.json', 'tsconfig.json', 'base.nyc.json']],
75
77
  ['bcn', ['baconing', 'narwhal', 'a mighty bear canoe'], ['baconing', 'a mighty bear canoe']]
76
78
  ] as ([string, string[], string[]])[]).forEach(test => {
77
79
  const [pattern, items, expected] = test;
@@ -80,6 +82,26 @@ describe('fuzzy-search', () => {
80
82
  });
81
83
  });
82
84
 
85
+ it('should rank substring matches before fuzzy-only matches', async () => {
86
+ const results = await search('font', ['reformatting', 'fontSize', 'fontFamily']);
87
+ // "reformatting" contains f-o-n-t scattered but not as substring; fontSize/fontFamily do
88
+ expectOrder(results, ['fontSize', 'fontFamily']);
89
+ });
90
+
91
+ it('should preserve original order for equal-score fuzzy-only matches', async () => {
92
+ // Both are fuzzy-only matches for "bcn" with different scores from the fuzzy library;
93
+ // when scores are equal, original array order (index) should be preserved.
94
+ const results = await search('ab', ['xab', 'yab']);
95
+ expectOrder(results, ['xab', 'yab']);
96
+ });
97
+
98
+ it('should highlight contiguous substring range instead of scattered fuzzy ranges', async () => {
99
+ const results = await search('works', ['browser-only-workspace-server.ts']);
100
+ expect(results).to.have.length(1);
101
+ // "works" appears at index 13 in "browser-only-workspace-server.ts"
102
+ expect(results[0].ranges).to.deep.equal([{ offset: 13, length: 5 }]);
103
+ });
104
+
83
105
  function expectOrder(actual: FuzzySearch.Match<string>[], expected: string[]): void {
84
106
  expect(actual.map(result => result.item)).to.be.deep.equal(expected);
85
107
  }
@@ -0,0 +1,158 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 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 * as fuzzy from 'fuzzy';
18
+ import { injectable } from 'inversify';
19
+ import { findSubstringIndex, matchRank } from './fuzzy-match-utils';
20
+
21
+ @injectable()
22
+ export class FuzzySearch {
23
+
24
+ private static readonly PRE = '\x01';
25
+ private static readonly POST = '\x02';
26
+
27
+ /**
28
+ * Filters the input and returns with an array that contains all items that match the pattern.
29
+ */
30
+ async filter<T>(input: FuzzySearch.Input<T>): Promise<FuzzySearch.Match<T>[]> {
31
+ return fuzzy.filter(input.pattern, input.items.slice(), {
32
+ pre: FuzzySearch.PRE,
33
+ post: FuzzySearch.POST,
34
+ extract: input.transform
35
+ }).sort((left, right) => this.sortResultsForInput(left, right, input))
36
+ .map(result => this.mapResultForInput(result, input));
37
+ }
38
+
39
+ protected sortResultsForInput<T>(left: fuzzy.FilterResult<T>, right: fuzzy.FilterResult<T>, input: FuzzySearch.Input<T>): number {
40
+ const leftRank = matchRank(input.transform(left.original), input.pattern);
41
+ const rightRank = matchRank(input.transform(right.original), input.pattern);
42
+ if (leftRank !== rightRank) { return leftRank - rightRank; }
43
+ return this.sortResults(left, right);
44
+ }
45
+
46
+ protected sortResults<T>(left: fuzzy.FilterResult<T>, right: fuzzy.FilterResult<T>): number {
47
+ if (right.score !== left.score) { return right.score - left.score; }
48
+ return left.index - right.index;
49
+ }
50
+
51
+ protected mapResultForInput<T>(result: fuzzy.FilterResult<T>, input: FuzzySearch.Input<T>): FuzzySearch.Match<T> {
52
+ const text = input.transform(result.original);
53
+ const substringIndex = input.pattern ? findSubstringIndex(text, input.pattern) : -1;
54
+ if (substringIndex !== -1) {
55
+ return {
56
+ item: result.original,
57
+ ranges: [{ offset: substringIndex, length: input.pattern.length }]
58
+ };
59
+ }
60
+ return this.mapResult(result);
61
+ }
62
+
63
+ protected mapResult<T>(result: fuzzy.FilterResult<T>): FuzzySearch.Match<T> {
64
+ return {
65
+ item: result.original,
66
+ ranges: this.mapRanges(result.string)
67
+ };
68
+ }
69
+
70
+ protected mapRanges(input: string): ReadonlyArray<FuzzySearch.Range> {
71
+ const copy = input.split('').filter(s => s !== '');
72
+ const ranges: FuzzySearch.Range[] = [];
73
+ const validate = (pre: number, post: number) => {
74
+ if (preIndex > postIndex || (preIndex === -1) !== (postIndex === -1)) {
75
+ throw new Error(`Error when trying to map ranges. Escaped string was: '${input}. [${[...input].join('|')}]'`);
76
+ }
77
+ };
78
+ let preIndex = copy.indexOf(FuzzySearch.PRE);
79
+ let postIndex = copy.indexOf(FuzzySearch.POST);
80
+ validate(preIndex, postIndex);
81
+ while (preIndex !== -1 && postIndex !== -1) {
82
+ ranges.push({
83
+ offset: preIndex,
84
+ length: postIndex - preIndex - 1
85
+ });
86
+ copy.splice(postIndex, 1);
87
+ copy.splice(preIndex, 1);
88
+ preIndex = copy.indexOf(FuzzySearch.PRE);
89
+ postIndex = copy.indexOf(FuzzySearch.POST);
90
+ }
91
+ if (ranges.length === 0) {
92
+ throw new Error(`Unexpected zero ranges for match-string: ${input}.`);
93
+ }
94
+ return ranges;
95
+ }
96
+
97
+ }
98
+
99
+ /**
100
+ * Fuzzy searcher.
101
+ */
102
+ export namespace FuzzySearch {
103
+
104
+ /**
105
+ * A range representing the match region.
106
+ */
107
+ export interface Range {
108
+
109
+ /**
110
+ * The zero based offset of the match region.
111
+ */
112
+ readonly offset: number;
113
+
114
+ /**
115
+ * The length of the match region.
116
+ */
117
+ readonly length: number;
118
+ }
119
+
120
+ /**
121
+ * A fuzzy search match.
122
+ */
123
+ export interface Match<T> {
124
+
125
+ /**
126
+ * The original item.
127
+ */
128
+ readonly item: T;
129
+
130
+ /**
131
+ * An array of ranges representing the match regions.
132
+ */
133
+ readonly ranges: ReadonlyArray<Range>;
134
+ }
135
+
136
+ /**
137
+ * The fuzzy search input.
138
+ */
139
+ export interface Input<T> {
140
+
141
+ /**
142
+ * The pattern to match.
143
+ */
144
+ readonly pattern: string;
145
+
146
+ /**
147
+ * The items to filter based on the `pattern`.
148
+ */
149
+ readonly items: ReadonlyArray<T>;
150
+
151
+ /**
152
+ * Function that extracts the string from the inputs which will be used to evaluate the fuzzy matching filter.
153
+ */
154
+ readonly transform: (item: T) => string;
155
+
156
+ }
157
+
158
+ }
@@ -19,6 +19,7 @@ import { Event } from './event';
19
19
  import { KeySequence } from './keys';
20
20
  import { CancellationToken } from './cancellation';
21
21
  import { Severity } from './severity';
22
+ import { findSubstringIndex, matchRank } from './fuzzy-match-utils';
22
23
 
23
24
  export const quickPickServicePath = '/services/quickPick';
24
25
  export const QuickPickService = Symbol('QuickPickService');
@@ -303,24 +304,52 @@ export function filterItems(items: QuickPickItemOrSeparator[], filter: string):
303
304
  return items;
304
305
  }
305
306
 
306
- const filteredItems: QuickPickItemOrSeparator[] = [];
307
+ function matchesFilter(item: QuickPickItem): boolean {
308
+ return fuzzy.test(filter, item.label) ||
309
+ (!!item.description && fuzzy.test(filter, item.description)) ||
310
+ (!!item.detail && fuzzy.test(filter, item.detail));
311
+ }
312
+
313
+ function itemMatchRank(item: QuickPickItem): number {
314
+ return Math.min(
315
+ matchRank(item.label, filter),
316
+ item.description ? matchRank(item.description, filter) : 2,
317
+ item.detail ? matchRank(item.detail, filter) : 2
318
+ );
319
+ }
320
+
321
+ // Process items in separator groups, sorted by match rank within each group.
322
+ const result: QuickPickItemOrSeparator[] = [];
323
+ let currentSeparator: QuickPickSeparator | undefined;
324
+ let groupMatches: { item: QuickPickItem; rank: number }[] = [];
325
+
326
+ const flushGroup = (): void => {
327
+ if (groupMatches.length > 0) {
328
+ if (currentSeparator) {
329
+ result.push(currentSeparator);
330
+ }
331
+ groupMatches.sort((a, b) => a.rank - b.rank);
332
+ result.push(...groupMatches.map(m => m.item));
333
+ }
334
+ groupMatches = [];
335
+ };
336
+
307
337
  for (const item of items) {
308
338
  if (item.type === 'separator') {
309
- filteredItems.push(item);
310
- } else if (
311
- fuzzy.test(filter, item.label) ||
312
- (item.description && fuzzy.test(filter, item.description)) ||
313
- (item.detail && fuzzy.test(filter, item.detail))
314
- ) {
339
+ flushGroup();
340
+ currentSeparator = item;
341
+ } else if (matchesFilter(item)) {
315
342
  item.highlights = {
316
343
  label: findMatches(item.label, filter),
317
344
  description: item.description ? findMatches(item.description, filter) : undefined,
318
345
  detail: item.detail ? findMatches(item.detail, filter) : undefined
319
346
  };
320
- filteredItems.push(item);
347
+ groupMatches.push({ item, rank: itemMatchRank(item) });
321
348
  }
322
349
  }
323
- return filteredItems;
350
+ flushGroup();
351
+
352
+ return result;
324
353
  }
325
354
 
326
355
  /**
@@ -337,6 +366,12 @@ export function findMatches(word: string, pattern: string): Array<{ start: numbe
337
366
  return undefined;
338
367
  }
339
368
 
369
+ // Prefer a contiguous substring highlight over scattered fuzzy character highlights.
370
+ const substringIndex = findSubstringIndex(word, pattern);
371
+ if (substringIndex !== -1) {
372
+ return [{ start: substringIndex, end: substringIndex + pattern.length }];
373
+ }
374
+
340
375
  const delimiter = '\u0000'; // null byte that shouldn't appear in the input and is used to denote matches.
341
376
  const matchResult = fuzzy.match(pattern.replace(/\u0000/gu, ''), word, { pre: delimiter, post: delimiter });
342
377
  if (!matchResult) {
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { injectable, inject, postConstruct } from 'inversify';
18
- import { NewWindowOptions, WindowSearchParams } from '../../common/window';
18
+ import { NewWindowOptions } from '../../common/window';
19
19
  import { DefaultWindowService } from '../../browser/window/default-window-service';
20
20
  import { ElectronMainWindowService } from '../../electron-common/electron-main-window-service';
21
21
  import { ElectronWindowPreferences } from '../../electron-common/electron-window-preferences';
@@ -57,8 +57,12 @@ export class ElectronWindowService extends DefaultWindowService {
57
57
  return undefined;
58
58
  }
59
59
 
60
- override openNewDefaultWindow(params?: WindowSearchParams): void {
61
- this.delegate.openNewDefaultWindow(params);
60
+ override async openNewDefaultWindow(params?: WindowReloadOptions): Promise<number> {
61
+ return this.delegate.openNewDefaultWindow(params?.search);
62
+ }
63
+
64
+ override closeWindow(windowId: number): void {
65
+ this.delegate.closeWindow(windowId);
62
66
  }
63
67
 
64
68
  override focus(): void {
@@ -116,4 +120,3 @@ export class ElectronWindowService extends DefaultWindowService {
116
120
  }
117
121
  }
118
122
  }
119
-
@@ -20,5 +20,6 @@ export const electronMainWindowServicePath = '/services/electron-window';
20
20
  export const ElectronMainWindowService = Symbol('ElectronMainWindowService');
21
21
  export interface ElectronMainWindowService {
22
22
  openNewWindow(url: string, options?: NewWindowOptions): undefined;
23
- openNewDefaultWindow(params?: WindowSearchParams): void;
23
+ openNewDefaultWindow(params?: WindowSearchParams): Promise<number>;
24
+ closeWindow(windowId: number): void;
24
25
  }
@@ -502,6 +502,13 @@ export class ElectronMainApplication {
502
502
  };
503
503
  }
504
504
 
505
+ closeWindowById(webContentsId: number): void {
506
+ const window = this.windows.get(webContentsId);
507
+ if (window) {
508
+ window.close(StopReason.Close);
509
+ }
510
+ }
511
+
505
512
  async openDefaultWindow(params?: WindowSearchParams): Promise<BrowserWindow> {
506
513
  const options = this.getDefaultTheiaWindowOptions();
507
514
  const [uri, electronWindow] = await Promise.all([this.createWindowUri(params), this.reuseOrCreateWindow(options)]);
@@ -37,8 +37,13 @@ export class ElectronMainWindowServiceImpl implements ElectronMainWindowService
37
37
  return undefined;
38
38
  }
39
39
 
40
- openNewDefaultWindow(params?: WindowSearchParams): void {
41
- this.app.openDefaultWindow(params);
40
+ async openNewDefaultWindow(params?: WindowSearchParams): Promise<number> {
41
+ const electronWindow = await this.app.openDefaultWindow(params);
42
+ return electronWindow.webContents.id;
43
+ }
44
+
45
+ closeWindow(windowId: number): void {
46
+ this.app.closeWindowById(windowId);
42
47
  }
43
48
 
44
49
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"fuzzy-search.spec.d.ts","sourceRoot":"","sources":["../../../src/browser/tree/fuzzy-search.spec.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fuzzy-search.spec.js","sourceRoot":"","sources":["../../../src/browser/tree/fuzzy-search.spec.ts"],"names":[],"mappings":"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"}