From eb869ee358b5c018e458fa9b9bc4e288620aaec5 Mon Sep 17 00:00:00 2001 From: Gabriel Bodeen Date: Fri, 19 Nov 2021 23:28:06 +0100 Subject: [PATCH] Search additional roots Signed-off-by: Gabriel Bodeen --- examples/api-tests/src/file-search.spec.js | 4 ++-- packages/file-search/package.json | 1 + .../src/browser/quick-file-open.ts | 19 +++++++++++++++---- packages/file-search/tsconfig.json | 3 +++ packages/search-in-workspace/package.json | 1 + .../search-in-workspace-preferences.ts | 6 ++++++ .../browser/search-in-workspace-service.ts | 15 +++++++++++++-- packages/search-in-workspace/tsconfig.json | 3 +++ 8 files changed, 44 insertions(+), 8 deletions(-) diff --git a/examples/api-tests/src/file-search.spec.js b/examples/api-tests/src/file-search.spec.js index f20d6b7b436b0..07c336a35624f 100644 --- a/examples/api-tests/src/file-search.spec.js +++ b/examples/api-tests/src/file-search.spec.js @@ -64,8 +64,8 @@ describe('file-search', function () { assert.equal(filterAndRange, quickFileOpenService['filterAndRangeDefault']); }); - it('should update when searching', () => { - quickFileOpenService['getPicks']('a:2:1', new CancellationTokenSource().token); // perform a mock search. + it('should update when searching', async () => { + await quickFileOpenService['getPicks']('a:2:1', new CancellationTokenSource().token); // perform a mock search. const filterAndRange = quickFileOpenService['filterAndRange']; assert.equal(filterAndRange.filter, 'a'); assert.deepEqual(filterAndRange.range, { start: { line: 1, character: 0 }, end: { line: 1, character: 0 } }); diff --git a/packages/file-search/package.json b/packages/file-search/package.json index 965d5842910e8..aab2056cb47ff 100644 --- a/packages/file-search/package.json +++ b/packages/file-search/package.json @@ -8,6 +8,7 @@ "@theia/filesystem": "1.20.0", "@theia/monaco": "1.20.0", "@theia/process": "1.20.0", + "@theia/variable-resolver": "1.20.0", "@theia/workspace": "1.20.0", "vscode-ripgrep": "^1.2.4" }, diff --git a/packages/file-search/src/browser/quick-file-open.ts b/packages/file-search/src/browser/quick-file-open.ts index e2f0da6509aba..773b0cc77193c 100644 --- a/packages/file-search/src/browser/quick-file-open.ts +++ b/packages/file-search/src/browser/quick-file-open.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { inject, injectable, optional, postConstruct } from '@theia/core/shared/inversify'; -import { OpenerService, KeybindingRegistry, QuickAccessRegistry, QuickAccessProvider, CommonCommands } from '@theia/core/lib/browser'; +import { OpenerService, KeybindingRegistry, QuickAccessRegistry, QuickAccessProvider, CommonCommands, PreferenceService } from '@theia/core/lib/browser'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import URI from '@theia/core/lib/common/uri'; import { FileSearchService, WHITESPACE_QUERY_SEPARATOR } from '../common/file-search-service'; @@ -27,6 +27,7 @@ import { MessageService } from '@theia/core/lib/common/message-service'; import { FileSystemPreferences } from '@theia/filesystem/lib/browser'; import { EditorOpenerOptions, EditorWidget, Position, Range } from '@theia/editor/lib/browser'; import { findMatches, QuickInputService, QuickPickItem, QuickPicks } from '@theia/core/lib/browser/quick-input/quick-input-service'; +import { VariableResolverService } from '@theia/variable-resolver/lib/browser'; export const quickFileOpen = Command.toDefaultLocalizedCommand({ id: 'file-search.openFile', @@ -66,6 +67,10 @@ export class QuickFileOpenService implements QuickAccessProvider { protected readonly messageService: MessageService; @inject(FileSystemPreferences) protected readonly fsPreferences: FileSystemPreferences; + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + @inject(VariableResolverService) + protected readonly variableResolverService: VariableResolverService; registerQuickAccessProvider(): void { this.quickAccessRegistry.registerQuickAccessProvider({ @@ -153,9 +158,14 @@ export class QuickFileOpenService implements QuickAccessProvider { return undefined; } - async getPicks(filter: string, token: CancellationToken): Promise { - const roots = this.workspaceService.tryGetRoots(); + async getRoots(): Promise { + const workspaceRoots = this.workspaceService.tryGetRoots().map(r => r.resource.toString()); + const additionalSearchRoots: string[] = this.preferenceService.get('search.additionalRoots') ?? []; + const resolvedAdditionalSearchRoots = await this.variableResolverService.resolveArray(additionalSearchRoots); + return [...workspaceRoots, ...resolvedAdditionalSearchRoots]; + } + async getPicks(filter: string, token: CancellationToken): Promise { this.filterAndRange = this.splitFilterAndRange(filter); const fileFilter = this.filterAndRange.filter; @@ -176,6 +186,7 @@ export class QuickFileOpenService implements QuickAccessProvider { } } + const roots = await this.getRoots(); if (fileFilter.length > 0) { const handler = async (results: string[]) => { if (token.isCancellationRequested || results.length <= 0) { @@ -207,7 +218,7 @@ export class QuickFileOpenService implements QuickAccessProvider { }; return this.fileSearchService.find(fileFilter, { - rootUris: roots.map(r => r.resource.toString()), + rootUris: roots, fuzzyMatch: true, limit: 200, useGitIgnore: this.hideIgnoredFiles, diff --git a/packages/file-search/tsconfig.json b/packages/file-search/tsconfig.json index 1fdba749bb46d..4f3b18d7f5934 100644 --- a/packages/file-search/tsconfig.json +++ b/packages/file-search/tsconfig.json @@ -24,6 +24,9 @@ { "path": "../process" }, + { + "path": "../variable-resolver" + }, { "path": "../workspace" } diff --git a/packages/search-in-workspace/package.json b/packages/search-in-workspace/package.json index c07f9e05f0bfa..3b80583145109 100644 --- a/packages/search-in-workspace/package.json +++ b/packages/search-in-workspace/package.json @@ -8,6 +8,7 @@ "@theia/filesystem": "1.20.0", "@theia/navigator": "1.20.0", "@theia/process": "1.20.0", + "@theia/variable-resolver": "1.20.0", "@theia/workspace": "1.20.0", "minimatch": "^3.0.4", "vscode-ripgrep": "^1.2.4" diff --git a/packages/search-in-workspace/src/browser/search-in-workspace-preferences.ts b/packages/search-in-workspace/src/browser/search-in-workspace-preferences.ts index 0b65c5615290f..6936f3bf6a431 100644 --- a/packages/search-in-workspace/src/browser/search-in-workspace-preferences.ts +++ b/packages/search-in-workspace/src/browser/search-in-workspace-preferences.ts @@ -58,6 +58,11 @@ export const searchInWorkspacePreferencesSchema: PreferenceSchema = { description: nls.localizeByDefault('Controls whether to follow symlinks while searching.'), default: true, type: 'boolean', + }, + 'search.additionalRoots': { + description: nls.localize('theia/search-in-workspace/additionalRoots', 'Directories outside the current workspace that should be included in searches.'), + default: [], + type: 'array', } } }; @@ -70,6 +75,7 @@ export class SearchInWorkspaceConfiguration { 'search.searchOnEditorModification': boolean; 'search.smartCase': boolean; 'search.followSymlinks': boolean; + 'search.additionalRoots': string[]; } export const SearchInWorkspacePreferenceContribution = Symbol('SearchInWorkspacePreferenceContribution'); diff --git a/packages/search-in-workspace/src/browser/search-in-workspace-service.ts b/packages/search-in-workspace/src/browser/search-in-workspace-service.ts index 60eb9b2bda010..cc22cb54e80a5 100644 --- a/packages/search-in-workspace/src/browser/search-in-workspace-service.ts +++ b/packages/search-in-workspace/src/browser/search-in-workspace-service.ts @@ -23,6 +23,8 @@ import { } from '../common/search-in-workspace-interface'; import { WorkspaceService } from '@theia/workspace/lib/browser'; import { ILogger } from '@theia/core'; +import { SearchInWorkspacePreferences } from './search-in-workspace-preferences'; +import { VariableResolverService } from '@theia/variable-resolver/lib/browser'; /** * Class that will receive the search results from the server. This is separate @@ -72,6 +74,8 @@ export class SearchInWorkspaceService implements SearchInWorkspaceClient { @inject(SearchInWorkspaceClientImpl) protected readonly client: SearchInWorkspaceClientImpl; @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; @inject(ILogger) protected readonly logger: ILogger; + @inject(SearchInWorkspacePreferences) protected readonly searchInWorkspacePreferences: SearchInWorkspacePreferences; + @inject(VariableResolverService) protected readonly variableResolverService: VariableResolverService; @postConstruct() protected init(): void { @@ -113,8 +117,15 @@ export class SearchInWorkspaceService implements SearchInWorkspaceClient { throw new Error('Search failed: no workspace root.'); } - const roots = await this.workspaceService.roots; - return this.doSearch(what, roots.map(r => r.resource.toString()), callbacks, opts); + const roots = await this.getRoots(); + return this.doSearch(what, roots, callbacks, opts); + } + + async getRoots(): Promise { + const workspaceRoots = (await this.workspaceService.roots).map(r => r.resource.toString()); + const additionalSearchRoots = this.searchInWorkspacePreferences.get('search.additionalRoots'); + const resolvedAdditionalSearchRoots = await this.variableResolverService.resolveArray(additionalSearchRoots); + return [...workspaceRoots, ...resolvedAdditionalSearchRoots]; } protected async doSearch(what: string, rootsUris: string[], callbacks: SearchInWorkspaceCallbacks, opts?: SearchInWorkspaceOptions): Promise { diff --git a/packages/search-in-workspace/tsconfig.json b/packages/search-in-workspace/tsconfig.json index 97bac275fed4c..ded52ecaa1d78 100644 --- a/packages/search-in-workspace/tsconfig.json +++ b/packages/search-in-workspace/tsconfig.json @@ -24,6 +24,9 @@ { "path": "../process" }, + { + "path": "../variable-resolver" + }, { "path": "../workspace" }