Skip to content

Commit

Permalink
siw: Add support for search in outside workspace content
Browse files Browse the repository at this point in the history
+ Search results from outside workspace editor are displayed and grouped under `Other
files ` node in search view.

Signed-off-by: Duc Nguyen <[email protected]>
  • Loading branch information
DucNgn committed Nov 5, 2020
1 parent bdc9aa2 commit 39d5c48
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
protected _replaceTerm = '';
protected searchTerm = '';

// The default root name to add external search results in the case that a workspace is opened.
protected readonly defaultRootName = 'Other files';
protected forceVisibleRootNode = false;

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

cancelIndicator?: CancellationTokenSource;
Expand Down Expand Up @@ -305,8 +309,12 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
const matches = this.findMatches(searchTerm, widget, searchOptions);
numberOfResults += matches.length;
const fileUri: string = widget.editor.uri.toString();
const root: string = this.workspaceService.getWorkspaceRootUri(widget.editor.uri)!.toString();
searchResults.push({ root, fileUri, matches });
const root: string | undefined = this.workspaceService.getWorkspaceRootUri(widget.editor.uri)?.toString();
searchResults.push({
root: root ?? this.defaultRootName,
fileUri,
matches
});
});

return {
Expand All @@ -324,7 +332,12 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
return;
}
const collapseValue: string = this.searchInWorkspacePreferences['search.collapseResults'];
const { path } = this.filenameAndPath(result.root, result.fileUri);
let path: string;
if (result.root === this.defaultRootName) {
path = new URI(result.fileUri).path.dir.toString();
} else {
path = this.filenameAndPath(result.root, result.fileUri).path;
}
const tree = this.resultTree;
let rootFolderNode = tree.get(result.root);
if (!rootFolderNode) {
Expand All @@ -345,13 +358,37 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
this.collapseFileNode(fileNode, collapseValue);
}

/**
* Handle when searching completed.
*/
protected handleSearchCompleted(cancelIndicator: CancellationTokenSource): void {
cancelIndicator.cancel();
this.sortResultTree();
this.refreshModelChildren();
}

/**
* Sort the result tree by URIs.
*/
protected sortResultTree(): void {
// Sort the result map by folder URI.
this.resultTree = new Map([...this.resultTree]
.sort((a: [string, SearchInWorkspaceRootFolderNode], b: [string, SearchInWorkspaceRootFolderNode]) => this.compare(a[1].folderUri, b[1].folderUri)));
// Update the list of children nodes, sorting them by their file URI.
Array.from(this.resultTree.values())
.forEach((folder: SearchInWorkspaceRootFolderNode) => {
folder.children = folder.children.sort((a: SearchInWorkspaceFileNode, b: SearchInWorkspaceFileNode) => this.compare(a.fileUri, b.fileUri));
});
}

async search(searchTerm: string, searchOptions: SearchInWorkspaceOptions): Promise<void> {
this.searchTerm = searchTerm;
searchOptions = {
...searchOptions,
exclude: this.getExcludeGlobs(searchOptions.exclude)
};
this.resultTree.clear();
this.forceVisibleRootNode = false;
if (this.cancelIndicator) {
this.cancelIndicator.cancel();
}
Expand All @@ -373,8 +410,12 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
});

// Collect search results for opened editors which otherwise may not be found by ripgrep (ex: dirty editors).
const { numberOfResults: monacoNumberOfResults, matches: monacoMatches } = this.searchInOpenEditors(searchTerm, searchOptions);
monacoMatches.forEach(m => {
const { numberOfResults, matches } = this.searchInOpenEditors(searchTerm, searchOptions);
// Root node is forced to be visible if outside workspace results found, inside workspace results found, and workspace root(s) presents.
this.forceVisibleRootNode = matches.some(m => m.root === this.defaultRootName)
&& matches.some(m => m.root !== this.defaultRootName && m.matches.length > 0)
&& this.workspaceService.opened;
matches.forEach(m => {
this.appendToResultTree(m);
// Exclude pattern beginning with './' works after the fix of #8469.
const { name, path } = this.filenameAndPath(m.root, m.fileUri);
Expand All @@ -385,7 +426,7 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {

// Reduce `maxResults` due to editor results.
if (searchOptions.maxResults) {
searchOptions.maxResults -= monacoNumberOfResults;
searchOptions.maxResults -= numberOfResults;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -402,18 +443,11 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
pendingRefreshTimeout = setTimeout(() => this.refreshModelChildren(), 100);
},
onDone: () => {
cancelIndicator.cancel();
// Sort the result map by folder URI.
this.resultTree = new Map([...this.resultTree]
.sort((a: [string, SearchInWorkspaceRootFolderNode], b: [string, SearchInWorkspaceRootFolderNode]) => this.compare(a[1].folderUri, b[1].folderUri)));
// Update the list of children nodes, sorting them by their file URI.
Array.from(this.resultTree.values())
.forEach((folder: SearchInWorkspaceRootFolderNode) => {
folder.children = folder.children.sort((a: SearchInWorkspaceFileNode, b: SearchInWorkspaceFileNode) => this.compare(a.fileUri, b.fileUri));
});
this.refreshModelChildren();
this.handleSearchCompleted(cancelIndicator);
}
}, searchOptions).catch(() => undefined);
}, searchOptions).catch(() => {
this.handleSearchCompleted(cancelIndicator);
});
}

focusFirstResult(): void {
Expand Down Expand Up @@ -491,7 +525,7 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
expanded: true,
id: rootUri,
parent: this.model.root as SearchInWorkspaceRoot,
visible: this.workspaceService.isMultiRootWorkspaceOpened
visible: this.forceVisibleRootNode || this.workspaceService.isMultiRootWorkspaceOpened
};
}

Expand Down Expand Up @@ -740,9 +774,11 @@ export class SearchInWorkspaceResultTreeWidget extends TreeWidget {
<span className={'file-name'}>
{this.toNodeName(node)}
</span>
<span className={'file-path'}>
{node.path}
</span>
{node.path !== '/' + this.defaultRootName &&
<span className={'file-path'}>
{node.path}
</span>
}
</div>
</div>
<span className='notification-count-container highlighted-count-container'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class SearchInWorkspaceService implements SearchInWorkspaceClient {

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

Expand Down

0 comments on commit 39d5c48

Please sign in to comment.