Skip to content

Commit

Permalink
restructure textSearch for searchModel
Browse files Browse the repository at this point in the history
  • Loading branch information
andreamah committed Aug 22, 2023
1 parent 5525236 commit c705233
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ReplacePreviewContentProvider } from 'vs/workbench/contrib/search/brows
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { INotebookSearchService } from 'vs/workbench/contrib/search/browser/notebookSearch';
import { INotebookSearchService } from 'vs/workbench/contrib/search/common/notebookSearch';
import { NotebookSearchService } from 'vs/workbench/contrib/search/browser/notebookSearchService';

export function registerContributions(): void {
Expand Down
68 changes: 37 additions & 31 deletions src/vs/workbench/contrib/search/browser/notebookSearchService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/mode
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookExclusiveDocumentFilter, NotebookData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookSerializer, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookSearchService } from 'vs/workbench/contrib/search/browser/notebookSearch';
import { INotebookSearchService } from 'vs/workbench/contrib/search/common/notebookSearch';
import { IFileMatchWithCells, ICellMatch, CellSearchModel, contentMatchesToTextSearchMatches, webviewMatchesToTextSearchMatches, genericCellMatchesToTextSearchMatches } from 'vs/workbench/contrib/search/browser/searchNotebookHelpers';
import { IEditorResolverService, priorityToRank } from 'vs/workbench/services/editor/common/editorResolverService';
import { ITextQuery, IFileQuery, QueryType, ISearchProgressItem, ISearchComplete, ISearchConfigurationProperties, ISearchService } from 'vs/workbench/services/search/common/search';
import { ITextQuery, QueryType, ISearchProgressItem, ISearchComplete, ISearchConfigurationProperties, IFileQuery, ISearchService } from 'vs/workbench/services/search/common/search';
import * as arrays from 'vs/base/common/arrays';
import { isNumber } from 'vs/base/common/types';

Expand Down Expand Up @@ -123,61 +123,67 @@ export class NotebookSearchService implements INotebookSearchService {
return Array.from(uris.keys());
}

notebookSearch(query: ITextQuery, token: CancellationToken, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
notebookSearch(query: ITextQuery, token: CancellationToken | undefined, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
openFilesToScan: ResourceSet;
resultPromise: Promise<{ completeData: ISearchComplete; allScannedFiles: ResourceSet }>;
completeData: Promise<ISearchComplete>;
allScannedFiles: Promise<ResourceSet>;
} {

if (query.type !== QueryType.Text) {
return {
openFilesToScan: new ResourceSet(),
resultPromise: Promise.resolve({
completeData: {
messages: [],
limitHit: false,
results: [],
},
allScannedFiles: new ResourceSet()
})
completeData: Promise.resolve({
messages: [],
limitHit: false,
results: [],
}),
allScannedFiles: Promise.resolve(new ResourceSet()),
};
}

const localNotebookWidgets = this.getLocalNotebookWidgets();
const localNotebookFiles = localNotebookWidgets.map(widget => widget.viewModel!.uri);
const getAllResults = async () => {
const getAllResults = (): { completeData: Promise<ISearchComplete>; allScannedFiles: Promise<ResourceSet> } => {
const searchStart = Date.now();

const localResultPromise = this.getLocalNotebookResults(query, token, localNotebookWidgets, searchInstanceID);
const localResultPromise = this.getLocalNotebookResults(query, token ?? CancellationToken.None, localNotebookWidgets, searchInstanceID);
const searchLocalEnd = Date.now();

const experimentalNotebooksEnabled = this.configurationService.getValue<ISearchConfigurationProperties>('search').experimental?.closedNotebookRichContentResults ?? false;

let closedResultsPromise: Promise<INotebookSearchMatchResults | undefined> = Promise.resolve(undefined);
if (experimentalNotebooksEnabled) {
closedResultsPromise = this.getClosedNotebookResults(query, new ResourceSet(localNotebookFiles, uri => this.uriIdentityService.extUri.getComparisonKey(uri)), token);
closedResultsPromise = this.getClosedNotebookResults(query, new ResourceSet(localNotebookFiles, uri => this.uriIdentityService.extUri.getComparisonKey(uri)), token ?? CancellationToken.None);
}

const resolved = (await Promise.all([localResultPromise, closedResultsPromise])).filter((result): result is INotebookSearchMatchResults => !!result);
const resultArray = resolved.map(elem => elem.results);

const results = arrays.coalesce(resultArray.flatMap(map => Array.from(map.values())));
const scannedFiles = new ResourceSet(resultArray.flatMap(map => Array.from(map.keys())), uri => this.uriIdentityService.extUri.getComparisonKey(uri));
if (onProgress) {
results.forEach(onProgress);
}
this.logService.trace(`local notebook search time | ${searchLocalEnd - searchStart}ms`);
const promise = Promise.all([localResultPromise, closedResultsPromise]);
return {
completeData: {
messages: [],
limitHit: resolved.reduce((prev, cur) => prev || cur.limitHit, false),
results,
},
allScannedFiles: scannedFiles
completeData: promise.then(resolvedPromise => {
const resolved = resolvedPromise.filter((e): e is INotebookSearchMatchResults => !!e);
const resultArray = resolved.map(elem => elem.results);
const results = arrays.coalesce(resultArray.flatMap(map => Array.from(map.values())));
if (onProgress) {
results.forEach(onProgress);
}
this.logService.trace(`local notebook search time | ${searchLocalEnd - searchStart}ms`);
return <ISearchComplete>{
messages: [],
limitHit: resolved.reduce((prev, cur) => prev || cur.limitHit, false),
results,
};
}),
allScannedFiles: promise.then(resolvedPromise => {
const resolved = resolvedPromise.filter((e): e is INotebookSearchMatchResults => !!e);
const resultArray = resolved.map(elem => elem.results);
return new ResourceSet(resultArray.flatMap(map => Array.from(map.keys())), uri => this.uriIdentityService.extUri.getComparisonKey(uri));
})
};
};
const promiseResults = getAllResults();
return {
openFilesToScan: new ResourceSet(localNotebookFiles),
resultPromise: getAllResults()
completeData: promiseResults.completeData,
allScannedFiles: promiseResults.allScannedFiles
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
indexedCellOptions: element instanceof MatchInNotebook ? { cellIndex: element.cellIndex, selection: element.range } : undefined,
};
const preview = element.preview();
const previewText = ' ' + (preview.before + preview.inside + preview.after).trim().substring(0, 999);
const previewText = (preview.before + preview.inside + preview.after).trim().substring(0, 999);
const match: IMatch[] = [{
start: preview.before.length + 2,
end: preview.before.length + preview.inside.length + 2
start: preview.before.length,
end: preview.before.length + preview.inside.length
}];
picks.push({
label: `${previewText}`,
Expand Down Expand Up @@ -219,13 +219,11 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
};
}

const bleh = allMatches.asyncResults.then((asyncResults) => {
return this._getPicksFromMatches(asyncResults, MAX_FILES_SHOWN - matches.length);
});

return {
picks: syncResult,
additionalPicks: bleh
additionalPicks: allMatches.asyncResults.then((asyncResults) => {
return this._getPicksFromMatches(asyncResults, MAX_FILES_SHOWN - matches.length);
})
};

}
Expand Down
56 changes: 27 additions & 29 deletions src/vs/workbench/contrib/search/browser/searchModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import { CellFindMatchWithIndex, CellWebviewFindMatch, ICellViewModel } from 'vs
import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService';
import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookSearchService } from 'vs/workbench/contrib/search/browser/notebookSearch';
import { IReplaceService } from 'vs/workbench/contrib/search/browser/replace';
import { CellSearchModel, ICellMatch, contentMatchesToTextSearchMatches, isIFileMatchWithCells, rawCellPrefix, webviewMatchesToTextSearchMatches } from 'vs/workbench/contrib/search/browser/searchNotebookHelpers';
import { INotebookSearchService } from 'vs/workbench/contrib/search/common/notebookSearch';
import { ReplacePattern } from 'vs/workbench/services/search/common/replace';
import { IFileMatch, IPatternInfo, ISearchComplete, ISearchConfigurationProperties, ISearchProgressItem, ISearchRange, ISearchService, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchPreviewOptions, ITextSearchResult, ITextSearchStats, OneLineRange, resultIsMatch, SearchCompletionExitCode, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers';
Expand Down Expand Up @@ -2007,49 +2007,47 @@ export class SearchModel extends Disposable {
asyncResults: Promise<ISearchComplete>;
syncResults: IFileMatch<URI>[];
} {
const generateOnProgress = (sync: boolean) => {
return (p: ISearchProgressItem) => {
progressEmitter.fire();
if (sync) {
this.onSearchProgressSync(p, searchInstanceID);
} else {
this.onSearchProgress(p, searchInstanceID);
}

onProgress?.(p);
};
const asyncGenerateOnProgress = async (p: ISearchProgressItem) => {
progressEmitter.fire();
this.onSearchProgress(p, searchInstanceID);
onProgress?.(p);
};
const asyncGenerateOnProgress = generateOnProgress(false);
const syncGenerateOnProgress = generateOnProgress(true);

const syncGenerateOnProgress = (p: ISearchProgressItem) => {
progressEmitter.fire();
this.onSearchProgressSync(p, searchInstanceID);
onProgress?.(p);
};
const tokenSource = this.currentCancelTokenSource = callerTokenSource ?? new CancellationTokenSource();
const notebookResult = this.notebookSearchService.notebookSearch(query, this.currentCancelTokenSource.token, searchInstanceID, asyncGenerateOnProgress);

const notebookResult = this.notebookSearchService.notebookSearch(query, tokenSource.token, searchInstanceID, onProgress);
const textResult = this.searchService.textSearchSplitSyncAsync(
searchQuery,
this.currentCancelTokenSource.token, asyncGenerateOnProgress);
this.currentCancelTokenSource.token, asyncGenerateOnProgress,
notebookResult.openFilesToScan,
notebookResult.allScannedFiles,
);

const syncResults = textResult.syncResults.results.filter(e => !notebookResult.openFilesToScan.has(e.resource));
const syncResults = textResult.syncResults.results;
syncResults.forEach(p => { if (p) { syncGenerateOnProgress(p); } });

const getAsyncResults = async (): Promise<ISearchComplete> => {
const searchStart = Date.now();

// resolve async parts of search
const [resolvedNotebookResult, resolvedTextResults] = await Promise.all([notebookResult.resultPromise, textResult.asyncResults]);
const allResults = [
...resolvedNotebookResult.completeData.results,
...resolvedTextResults.results.filter((e) => !resolvedNotebookResult.allScannedFiles.has(e.resource))
];
const allClosedEditorResults = await textResult.asyncResults;
const resolvedNotebookResults = await notebookResult.completeData;
tokenSource.dispose();
const searchLength = Date.now() - searchStart;
this.logService.trace(`whole search time | ${searchLength}ms`);
return {
results: allResults,
messages: resolvedTextResults.messages.concat(resolvedNotebookResult.completeData.messages),
limitHit: resolvedTextResults.limitHit || resolvedNotebookResult.completeData.limitHit,
exit: resolvedTextResults.exit,
stats: resolvedTextResults.stats,
const resolvedResult = <ISearchComplete>{
results: [...allClosedEditorResults.results, ...resolvedNotebookResults.results],
messages: [...allClosedEditorResults.messages, ...resolvedNotebookResults.messages],
limitHit: allClosedEditorResults.limitHit || resolvedNotebookResults.limitHit,
exit: allClosedEditorResults.exit,
stats: allClosedEditorResults.stats,
};
this.logService.trace(`whole search time | ${searchLength}ms`);
return resolvedResult;
};
return {
asyncResults: getAsyncResults(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import { ITextQuery, ISearchProgressItem, ISearchComplete } from 'vs/workbench/s

export const INotebookSearchService = createDecorator<INotebookSearchService>('notebookSearchService');


export interface INotebookSearchService {

readonly _serviceBrand: undefined;


notebookSearch(query: ITextQuery, token: CancellationToken, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
notebookSearch(query: ITextQuery, token: CancellationToken | undefined, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
openFilesToScan: ResourceSet;
resultPromise: Promise<{ completeData: ISearchComplete; allScannedFiles: ResourceSet }>;
completeData: Promise<ISearchComplete>;
allScannedFiles: Promise<ResourceSet>;
};
}
21 changes: 10 additions & 11 deletions src/vs/workbench/contrib/search/test/browser/searchModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBr
import { FindMatch, IReadonlyTextBuffer } from 'vs/editor/common/model';
import { ResourceMap, ResourceSet } from 'vs/base/common/map';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookSearchService } from 'vs/workbench/contrib/search/browser/notebookSearch';
import { INotebookSearchService } from 'vs/workbench/contrib/search/common/notebookSearch';

const nullEvent = new class {
id: number = -1;
Expand Down Expand Up @@ -212,9 +212,10 @@ suite('SearchModel', () => {
function notebookSearchServiceWithInfo(results: IFileMatchWithCells[], tokenSource: CancellationTokenSource | undefined): INotebookSearchService {
return <INotebookSearchService>{
_serviceBrand: undefined,
notebookSearch(query: ITextQuery, token: CancellationToken, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
notebookSearch(query: ITextQuery, token: CancellationToken | undefined, searchInstanceID: string, onProgress?: (result: ISearchProgressItem) => void): {
openFilesToScan: ResourceSet;
resultPromise: Promise<{ completeData: ISearchComplete; allScannedFiles: ResourceSet }>;
completeData: Promise<ISearchComplete>;
allScannedFiles: Promise<ResourceSet>;
} {
token?.onCancellationRequested(() => tokenSource?.cancel());
const localResults = new ResourceMap<IFileMatchWithCells | null>(uri => uri.path);
Expand All @@ -228,14 +229,12 @@ suite('SearchModel', () => {
}
return {
openFilesToScan: new ResourceSet([...localResults.keys()]),
resultPromise: Promise.resolve({
completeData: {
messages: [],
results: arrays.coalesce([...localResults.values()]),
limitHit: false
},
allScannedFiles: new ResourceSet([]),
})
completeData: Promise.resolve({
messages: [],
results: arrays.coalesce([...localResults.values()]),
limitHit: false
}),
allScannedFiles: Promise.resolve(new ResourceSet()),
};
}
};
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/services/search/common/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as paths from 'vs/base/common/path';
import { isCancellationError } from 'vs/base/common/errors';
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
import { isThenable } from 'vs/base/common/async';
import { ResourceSet } from 'vs/base/common/map';

export { TextSearchCompleteMessageType };

Expand All @@ -42,7 +43,7 @@ export const ISearchService = createDecorator<ISearchService>('searchService');
export interface ISearchService {
readonly _serviceBrand: undefined;
textSearch(query: ITextQuery, token?: CancellationToken, onProgress?: (result: ISearchProgressItem) => void): Promise<ISearchComplete>;
textSearchSplitSyncAsync(query: ITextQuery, token?: CancellationToken | undefined, onProgress?: ((result: ISearchProgressItem) => void) | undefined): { syncResults: ISearchComplete; asyncResults: Promise<ISearchComplete> };
textSearchSplitSyncAsync(query: ITextQuery, token?: CancellationToken | undefined, onProgress?: ((result: ISearchProgressItem) => void) | undefined, notebookFilesToIgnore?: ResourceSet, asyncNotebookFilesToIgnore?: Promise<ResourceSet>): { syncResults: ISearchComplete; asyncResults: Promise<ISearchComplete> };
fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete>;
clearCache(cacheKey: string): Promise<void>;
registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable;
Expand Down
Loading

0 comments on commit c705233

Please sign in to comment.