Keep search code sync when possible

This commit is contained in:
Rob Lourens 2021-08-16 20:47:34 -06:00
parent 9ef2f07234
commit 3673539e09
3 changed files with 43 additions and 23 deletions

View file

@ -290,3 +290,7 @@ export function NotImplementedProxy<T>(name: string): { new(): T } {
export function assertNever(value: never, message = 'Unreachable') {
throw new Error(message);
}
export function isPromise<T>(obj: unknown): obj is Promise<T> {
return !!obj && typeof (obj as Promise<T>).then === 'function' && typeof (obj as Promise<T>).catch === 'function';
}

View file

@ -18,6 +18,7 @@ import { Event } from 'vs/base/common/event';
import * as paths from 'vs/base/common/path';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
import { isPromise } from 'vs/base/common/types';
export { TextSearchCompleteMessageType };
@ -655,22 +656,29 @@ export class QueryGlobTester {
}
/**
* Guaranteed async.
* Evaluating the exclude expression is only async if it includes sibling clauses. As an optimization, avoid doing anything with Promises
* unless the expression is async.
*/
includedInQuery(testPath: string, basename?: string, hasSibling?: (name: string) => boolean | Promise<boolean>): Promise<boolean> {
const excludeP = Promise.resolve(this._parsedExcludeExpression(testPath, basename, hasSibling)).then(result => !!result);
return excludeP.then(excluded => {
if (excluded) {
return false;
}
includedInQuery(testPath: string, basename?: string, hasSibling?: (name: string) => boolean | Promise<boolean>): Promise<boolean> | boolean {
const excluded = this._parsedExcludeExpression(testPath, basename, hasSibling);
const isIncluded = () => {
return this._parsedIncludeExpression ?
Promise.resolve(this._parsedIncludeExpression(testPath, basename, hasSibling)).then(result => !!result) :
Promise.resolve(true);
}).then(included => {
return included;
});
!!(this._parsedIncludeExpression(testPath, basename, hasSibling)) :
true;
};
if (isPromise(excluded)) {
return excluded.then(excluded => {
if (excluded) {
return false;
}
return isIncluded();
});
}
return isIncluded();
}
hasSiblingExcludeClauses(): boolean {

View file

@ -3,17 +3,17 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'vs/base/common/path';
import { flatten, mapArrayOrNot } from 'vs/base/common/arrays';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import * as resources from 'vs/base/common/resources';
import * as glob from 'vs/base/common/glob';
import { Schemas } from 'vs/base/common/network';
import * as path from 'vs/base/common/path';
import * as resources from 'vs/base/common/resources';
import { isArray, isPromise } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/common/search';
import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComplete, Range, TextSearchOptions, TextSearchQuery } from 'vs/workbench/services/search/common/searchExtTypes';
import { Schemas } from 'vs/base/common/network';
import { isArray } from 'vs/base/common/types';
import { Range, TextSearchComplete, TextSearchMatch, TextSearchOptions, TextSearchProvider, TextSearchQuery, TextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes';
export interface IFileUtils {
readdir: (resource: URI) => Promise<string[]>;
@ -131,20 +131,28 @@ export class TextSearchManager {
const relativePath = resources.relativePath(folderQuery.folder, result.uri);
if (relativePath) {
testingPs.push(
queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling)
.then(included => {
if (included) {
// This method is only async when the exclude contains sibling clauses
const included = queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling);
if (isPromise(included)) {
testingPs.push(
included.then(isIncluded => {
if (isIncluded) {
onResult(result);
}
}));
} else if (included) {
onResult(result);
}
}
}
};
const searchOptions = this.getSearchOptionsForFolder(folderQuery);
const result = await this.provider.provideTextSearchResults(patternInfoToQuery(this.query.contentPattern), searchOptions, progress, token);
await Promise.all(testingPs);
if (testingPs.length) {
await Promise.all(testingPs);
}
return result;
}