Skip to content

Commit bfdcaa5

Browse files
committed
siw: Add support for search in outside workspace content
+ Search results from outside workspace editor are displayed and grouped under `Other files ` node in search view. Signed-off-by: Duc Nguyen <duc.a.nguyen@ericsson.com>
1 parent bdc9aa2 commit bfdcaa5

File tree

2 files changed

+53
-22
lines changed

2 files changed

+53
-22
lines changed

packages/search-in-workspace/src/browser/search-in-workspace-result-tree-widget.tsx

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
106106
protected _showReplaceButtons = false;
107107
protected _replaceTerm = '';
108108
protected searchTerm = '';
109+
protected readonly outsideWorkspaceRootUri = 'Other files';
110+
protected hasOutsideWorkspaceResult = false;
109111

110112
protected appliedDecorations = new Map<string, string[]>();
111113

@@ -305,8 +307,12 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
305307
const matches = this.findMatches(searchTerm, widget, searchOptions);
306308
numberOfResults += matches.length;
307309
const fileUri: string = widget.editor.uri.toString();
308-
const root: string = this.workspaceService.getWorkspaceRootUri(widget.editor.uri)!.toString();
309-
searchResults.push({ root, fileUri, matches });
310+
const root: string | undefined = this.workspaceService.getWorkspaceRootUri(widget.editor.uri)?.toString();
311+
searchResults.push({
312+
root: root ? root : this.outsideWorkspaceRootUri,
313+
fileUri,
314+
matches
315+
});
310316
});
311317

312318
return {
@@ -324,7 +330,12 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
324330
return;
325331
}
326332
const collapseValue: string = this.searchInWorkspacePreferences['search.collapseResults'];
327-
const { path } = this.filenameAndPath(result.root, result.fileUri);
333+
let path: string;
334+
if (result.root === this.outsideWorkspaceRootUri) {
335+
path = new URI(result.fileUri).path.dir.toString();
336+
} else {
337+
path = this.filenameAndPath(result.root, result.fileUri).path;
338+
}
328339
const tree = this.resultTree;
329340
let rootFolderNode = tree.get(result.root);
330341
if (!rootFolderNode) {
@@ -345,13 +356,37 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
345356
this.collapseFileNode(fileNode, collapseValue);
346357
}
347358

359+
/**
360+
* Handle when searching completed.
361+
*/
362+
protected handleSearchCompleted(cancelIndicator: CancellationTokenSource): void {
363+
cancelIndicator.cancel();
364+
this.sortResultTree();
365+
this.refreshModelChildren();
366+
}
367+
368+
/**
369+
* Sort the result tree by URIs.
370+
*/
371+
protected sortResultTree(): void {
372+
// Sort the result map by folder URI.
373+
this.resultTree = new Map([...this.resultTree]
374+
.sort((a: [string, SearchInWorkspaceRootFolderNode], b: [string, SearchInWorkspaceRootFolderNode]) => this.compare(a[1].folderUri, b[1].folderUri)));
375+
// Update the list of children nodes, sorting them by their file URI.
376+
Array.from(this.resultTree.values())
377+
.forEach((folder: SearchInWorkspaceRootFolderNode) => {
378+
folder.children = folder.children.sort((a: SearchInWorkspaceFileNode, b: SearchInWorkspaceFileNode) => this.compare(a.fileUri, b.fileUri));
379+
});
380+
}
381+
348382
async search(searchTerm: string, searchOptions: SearchInWorkspaceOptions): Promise<void> {
349383
this.searchTerm = searchTerm;
350384
searchOptions = {
351385
...searchOptions,
352386
exclude: this.getExcludeGlobs(searchOptions.exclude)
353387
};
354388
this.resultTree.clear();
389+
this.hasOutsideWorkspaceResult = false;
355390
if (this.cancelIndicator) {
356391
this.cancelIndicator.cancel();
357392
}
@@ -373,8 +408,9 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
373408
});
374409

375410
// Collect search results for opened editors which otherwise may not be found by ripgrep (ex: dirty editors).
376-
const { numberOfResults: monacoNumberOfResults, matches: monacoMatches } = this.searchInOpenEditors(searchTerm, searchOptions);
377-
monacoMatches.forEach(m => {
411+
const { numberOfResults, matches } = this.searchInOpenEditors(searchTerm, searchOptions);
412+
this.hasOutsideWorkspaceResult = matches.some(m => m.root === this.outsideWorkspaceRootUri);
413+
matches.forEach(m => {
378414
this.appendToResultTree(m);
379415
// Exclude pattern beginning with './' works after the fix of #8469.
380416
const { name, path } = this.filenameAndPath(m.root, m.fileUri);
@@ -385,7 +421,7 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
385421

386422
// Reduce `maxResults` due to editor results.
387423
if (searchOptions.maxResults) {
388-
searchOptions.maxResults -= monacoNumberOfResults;
424+
searchOptions.maxResults -= numberOfResults;
389425
}
390426

391427
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -402,18 +438,11 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
402438
pendingRefreshTimeout = setTimeout(() => this.refreshModelChildren(), 100);
403439
},
404440
onDone: () => {
405-
cancelIndicator.cancel();
406-
// Sort the result map by folder URI.
407-
this.resultTree = new Map([...this.resultTree]
408-
.sort((a: [string, SearchInWorkspaceRootFolderNode], b: [string, SearchInWorkspaceRootFolderNode]) => this.compare(a[1].folderUri, b[1].folderUri)));
409-
// Update the list of children nodes, sorting them by their file URI.
410-
Array.from(this.resultTree.values())
411-
.forEach((folder: SearchInWorkspaceRootFolderNode) => {
412-
folder.children = folder.children.sort((a: SearchInWorkspaceFileNode, b: SearchInWorkspaceFileNode) => this.compare(a.fileUri, b.fileUri));
413-
});
414-
this.refreshModelChildren();
441+
this.handleSearchCompleted(cancelIndicator);
415442
}
416-
}, searchOptions).catch(() => undefined);
443+
}, searchOptions).catch(() => {
444+
this.handleSearchCompleted(cancelIndicator);
445+
});
417446
}
418447

419448
focusFirstResult(): void {
@@ -491,7 +520,7 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
491520
expanded: true,
492521
id: rootUri,
493522
parent: this.model.root as SearchInWorkspaceRoot,
494-
visible: this.workspaceService.isMultiRootWorkspaceOpened
523+
visible: (this.hasOutsideWorkspaceResult && this.workspaceService.opened) || this.workspaceService.isMultiRootWorkspaceOpened
495524
};
496525
}
497526

@@ -740,9 +769,11 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
740769
<span className={'file-name'}>
741770
{this.toNodeName(node)}
742771
</span>
743-
<span className={'file-path'}>
744-
{node.path}
745-
</span>
772+
{node.path !== '/' + this.outsideWorkspaceRootUri &&
773+
<span className={'file-path'}>
774+
{node.path}
775+
</span>
776+
}
746777
</div>
747778
</div>
748779
<span className='notification-count-container highlighted-count-container'>

packages/search-in-workspace/src/browser/search-in-workspace-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export class SearchInWorkspaceService implements SearchInWorkspaceClient {
109109

110110
// Start a search of the string "what" in the workspace.
111111
async search(what: string, callbacks: SearchInWorkspaceCallbacks, opts?: SearchInWorkspaceOptions): Promise<number> {
112-
if (!this.workspaceService.open) {
112+
if (!this.workspaceService.opened) {
113113
throw new Error('Search failed: no workspace root.');
114114
}
115115

0 commit comments

Comments
 (0)