提交 707a20f4 编写于 作者: R Rob Lourens

Change TextSearchResult API to only return a string relative path to the search folder

上级 501502c5
......@@ -83,7 +83,7 @@ export class RipgrepTextSearchEngine {
let stderr = '';
this.rgProc.stderr.on('data', data => {
const message = data.toString();
// onMessage({ message });
this.outputChannel.appendLine(message);
stderr += message;
});
......@@ -142,7 +142,7 @@ export class RipgrepParser extends EventEmitter {
public static readonly MATCH_START_MARKER = '\u001b[0m\u001b[31m';
public static readonly MATCH_END_MARKER = '\u001b[0m';
private currentFile: vscode.Uri;
private currentFile: string;
private remainder: string;
private isDone: boolean;
private stringDecoder: NodeStringDecoder;
......@@ -196,21 +196,13 @@ export class RipgrepParser extends EventEmitter {
// Line is a result - add to collected results for the current file path
this.handleMatchLine(outputLine, lineNum, matchText);
} else if (r = outputLine.match(RipgrepParser.FILE_REGEX)) {
this.currentFile = this.getFileUri(r[1]);
this.currentFile = r[1];
} else {
// Line is empty (or malformed)
}
}
}
private getFileUri(relativeOrAbsolutePath: string): vscode.Uri {
const absPath = path.isAbsolute(relativeOrAbsolutePath) ?
relativeOrAbsolutePath :
path.join(this.rootFolder, relativeOrAbsolutePath);
return vscode.Uri.file(absPath);
}
private handleMatchLine(outputLine: string, lineNum: number, lineText: string): void {
if (lineNum === 0) {
lineText = stripUTF8BOM(lineText);
......@@ -291,7 +283,7 @@ export class RipgrepParser extends EventEmitter {
lineMatches
.map(range => {
return <vscode.TextSearchResult>{
uri: this.currentFile,
path: this.currentFile,
range,
preview: {
text: preview,
......
......@@ -104,12 +104,17 @@ export interface IPatternInfo {
isSmartCase?: boolean;
}
export interface IFileMatch<U extends UriComponents = uri> {
export interface IFileMatch<U = uri> {
resource?: U;
lineMatches?: ILineMatch[];
}
export type IRawFileMatch2 = IFileMatch<UriComponents>;
export interface IPathInFolder {
folderIdx: number;
relativePath: string;
}
export type IRawFileMatch2 = IFileMatch<IPathInFolder>;
export interface ILineMatch {
preview: string;
......
......@@ -77,7 +77,7 @@ declare module 'vscode' {
export interface FileSearchOptions extends SearchOptions { }
export interface TextSearchResult {
uri: Uri;
path: string;
range: Range;
// For now, preview must be a single line of text
......
......@@ -4,12 +4,13 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as path from 'path';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import URI, { UriComponents } from 'vs/base/common/uri';
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { IFileMatch, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType, IRawFileMatch2, ISearchCompleteStats } from 'vs/platform/search/common/search';
import { IFileMatch, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType, IRawFileMatch2, ISearchCompleteStats, IFolderQuery } from 'vs/platform/search/common/search';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -57,6 +58,7 @@ class SearchOperation {
constructor(
readonly progress: (match: IFileMatch) => any,
readonly folders: IFolderQuery[],
readonly id: number = ++SearchOperation._idPool,
readonly matches = new Map<string, IFileMatch>()
) {
......@@ -110,7 +112,7 @@ class RemoteSearchProvider implements ISearchResultProvider {
return new PPromise((resolve, reject, report) => {
const search = new SearchOperation(report);
const search = new SearchOperation(report, query.folderQueries);
this._searches.set(search.id, search);
outer = query.type === QueryType.File
......@@ -140,8 +142,14 @@ class RemoteSearchProvider implements ISearchResultProvider {
const searchOp = this._searches.get(session);
if (Array.isArray(dataOrUri)) {
dataOrUri.forEach(m => {
const folderQuery = searchOp.folders[m.resource.folderIdx];
if (!folderQuery) {
return;
}
const fullUri = URI.file(path.join(folderQuery.folder.fsPath, m.resource.relativePath));
searchOp.addMatch({
resource: URI.revive(m.resource),
resource: fullUri,
lineMatches: m.lineMatches
});
});
......
......@@ -14,7 +14,7 @@ import * as strings from 'vs/base/common/strings';
import URI, { UriComponents } from 'vs/base/common/uri';
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { IItemAccessor, ScorerCache, compareItemsByScore, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
import { ICachedSearchStats, IFileMatch, IFolderQuery, IPatternInfo, IRawSearchQuery, ISearchQuery, ISearchCompleteStats } from 'vs/platform/search/common/search';
import { ICachedSearchStats, IRawFileMatch2, IFolderQuery, IPatternInfo, IRawSearchQuery, ISearchQuery, ISearchCompleteStats, IFileMatch } from 'vs/platform/search/common/search';
import * as vscode from 'vscode';
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from './extHost.protocol';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
......@@ -131,26 +131,29 @@ function reviveFolderQuery(rawFolderQuery: IFolderQuery<UriComponents>): IFolder
}
class TextSearchResultsCollector {
private _batchedCollector: BatchedCollector<IFileMatch>;
private _batchedCollector: BatchedCollector<IRawFileMatch2>;
private _currentFileMatch: IFileMatch;
private _currentFileMatch: IRawFileMatch2;
constructor(private _onResult: (result: IFileMatch[]) => void) {
this._batchedCollector = new BatchedCollector<IFileMatch>(512, items => this.sendItems(items));
constructor(private _onResult: (result: IRawFileMatch2[]) => void) {
this._batchedCollector = new BatchedCollector<IRawFileMatch2>(512, items => this.sendItems(items));
}
add(data: vscode.TextSearchResult): void {
add(data: vscode.TextSearchResult, folderIdx: number): void {
// Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector.
// This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search
// providers that send results in random order. We could do this step afterwards instead.
if (this._currentFileMatch && this._currentFileMatch.resource.toString() !== data.uri.toString()) {
if (this._currentFileMatch && (this._currentFileMatch.resource.folderIdx !== folderIdx || this._currentFileMatch.resource.relativePath !== data.path)) {
this.pushToCollector();
this._currentFileMatch = null;
}
if (!this._currentFileMatch) {
this._currentFileMatch = {
resource: data.uri,
resource: {
folderIdx,
relativePath: data.path
},
lineMatches: []
};
}
......@@ -176,7 +179,7 @@ class TextSearchResultsCollector {
this._batchedCollector.flush();
}
private sendItems(items: IFileMatch | IFileMatch[]): void {
private sendItems(items: IRawFileMatch2 | IRawFileMatch2[]): void {
this._onResult(Array.isArray(items) ? items : [items]);
}
}
......@@ -386,19 +389,19 @@ class TextSearchEngine {
this.activeCancellationTokens = new Set();
}
public search(): PPromise<{ limitHit: boolean }, IFileMatch[]> {
public search(): PPromise<{ limitHit: boolean }, IRawFileMatch2[]> {
const folderQueries = this.config.folderQueries;
return new PPromise<{ limitHit: boolean }, IFileMatch[]>((resolve, reject, _onResult) => {
return new PPromise<{ limitHit: boolean }, IRawFileMatch2[]>((resolve, reject, _onResult) => {
this.collector = new TextSearchResultsCollector(_onResult);
const onResult = (match: vscode.TextSearchResult) => {
const onResult = (match: vscode.TextSearchResult, folderIdx: number) => {
if (this.isCanceled) {
return;
}
this.resultCount++;
this.collector.add(match);
this.collector.add(match, folderIdx);
if (this.resultCount >= this.config.maxResults) {
this.isLimitHit = true;
......@@ -407,8 +410,8 @@ class TextSearchEngine {
};
// For each root folder
PPromise.join(folderQueries.map(fq => {
return this.searchInFolder(fq).then(null, null, onResult);
PPromise.join(folderQueries.map((fq, i) => {
return this.searchInFolder(fq).then(null, null, r => onResult(r, i));
})).then(() => {
this.collector.flush();
resolve({ limitHit: this.isLimitHit });
......@@ -427,15 +430,20 @@ class TextSearchEngine {
return new PPromise((resolve, reject, onResult) => {
const queryTester = new QueryGlobTester(this.config, folderQuery);
const folderStr = folderQuery.folder.fsPath;
const testingPs = [];
const progress = {
report: (result: vscode.TextSearchResult) => {
const relativePath = path.relative(folderStr, result.uri.fsPath);
const siblingFn = () => {
return this.readdir(path.dirname(path.join(folderQuery.folder.fsPath, result.path)));
};
testingPs.push(
queryTester.includedInQuery(relativePath, path.basename(relativePath), () => this.readdir(path.dirname(result.uri.fsPath)))
.then(included => included && onResult(result)));
queryTester.includedInQuery(result.path, path.basename(result.path), siblingFn)
.then(included => {
if (included) {
onResult(result);
}
}));
}
};
......
......@@ -9,7 +9,7 @@ import * as path from 'path';
import * as extfs from 'vs/base/node/extfs';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IRawFileMatch2, IRawSearchQuery, QueryType, ISearchQuery, IPatternInfo, IFileMatch } from 'vs/platform/search/common/search';
import { IRawFileMatch2, IRawSearchQuery, QueryType, ISearchQuery, IPatternInfo } from 'vs/platform/search/common/search';
import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol';
......@@ -78,7 +78,7 @@ suite('ExtHostSearch', () => {
return (<UriComponents[]>mockMainThreadSearch.results).map(r => URI.revive(r));
}
async function runTextSearch(pattern: IPatternInfo, query: IRawSearchQuery, cancel = false): TPromise<IFileMatch[]> {
async function runTextSearch(pattern: IPatternInfo, query: IRawSearchQuery, cancel = false): TPromise<IRawFileMatch2[]> {
try {
const p = extHostSearch.$provideTextSearchResults(mockMainThreadSearch.lastHandle, 0, pattern, query);
if (cancel) {
......@@ -95,12 +95,7 @@ suite('ExtHostSearch', () => {
}
await rpcProtocol.sync();
return (<IRawFileMatch2[]>mockMainThreadSearch.results).map(r => ({
...r,
...{
resource: URI.revive(r.resource)
}
}));
return <IRawFileMatch2[]>mockMainThreadSearch.results;
}
setup(() => {
......@@ -628,11 +623,11 @@ suite('ExtHostSearch', () => {
};
}
function makeTextResult(uri: URI): vscode.TextSearchResult {
function makeTextResult(relativePath: string): vscode.TextSearchResult {
return {
preview: makePreview('foo'),
range: new Range(0, 0, 0, 3),
uri
path: relativePath
};
}
......@@ -652,7 +647,7 @@ suite('ExtHostSearch', () => {
};
}
function assertResults(actual: IFileMatch[], expected: vscode.TextSearchResult[]) {
function assertResults(actual: IRawFileMatch2[], expected: vscode.TextSearchResult[]) {
const actualTextSearchResults: vscode.TextSearchResult[] = [];
for (let fileMatch of actual) {
for (let lineMatch of fileMatch.lineMatches) {
......@@ -660,7 +655,7 @@ suite('ExtHostSearch', () => {
actualTextSearchResults.push({
preview: { text: lineMatch.preview, match: null },
range: new Range(lineMatch.lineNumber, offset, lineMatch.lineNumber, length + offset),
uri: fileMatch.resource
path: fileMatch.resource.relativePath
});
}
}
......@@ -673,7 +668,7 @@ suite('ExtHostSearch', () => {
.map(r => ({
...r,
...{
uri: r.uri.toString(),
uri: r.path.toString(),
range: rangeToString(r.range),
preview: {
text: r.preview.text,
......@@ -700,8 +695,8 @@ suite('ExtHostSearch', () => {
test('basic results', async () => {
const providedResults: vscode.TextSearchResult[] = [
makeTextResult(makeAbsoluteURI(rootFolderA, 'file1.ts')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'file2.ts'))
makeTextResult('file1.ts'),
makeTextResult('file2.ts')
];
await registerTestSearchProvider({
......@@ -850,8 +845,8 @@ suite('ExtHostSearch', () => {
};
const providedResults: vscode.TextSearchResult[] = [
makeTextResult(makeAbsoluteURI(rootFolderA, 'file1.js')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'file1.ts'))
makeTextResult('file1.js'),
makeTextResult('file1.ts')
];
await registerTestSearchProvider({
......@@ -903,15 +898,15 @@ suite('ExtHostSearch', () => {
let reportedResults;
if (options.folder.fsPath === rootFolderA.fsPath) {
reportedResults = [
makeTextResult(makeAbsoluteURI(rootFolderA, 'folder/fileA.scss')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'folder/fileA.css')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'folder/file2.css'))
makeTextResult('folder/fileA.scss'),
makeTextResult('folder/fileA.css'),
makeTextResult('folder/file2.css')
];
} else {
reportedResults = [
makeTextResult(makeAbsoluteURI(rootFolderB, 'fileB.ts')),
makeTextResult(makeAbsoluteURI(rootFolderB, 'fileB.js')),
makeTextResult(makeAbsoluteURI(rootFolderB, 'file3.js'))
makeTextResult('fileB.ts'),
makeTextResult('fileB.js'),
makeTextResult('file3.js')
];
}
......@@ -949,17 +944,17 @@ suite('ExtHostSearch', () => {
const results = await runTextSearch(getPattern('foo'), query);
assertResults(results, [
makeTextResult(makeAbsoluteURI(rootFolderA, 'folder/fileA.scss')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'folder/file2.css')),
makeTextResult(makeAbsoluteURI(rootFolderB, 'fileB.ts')),
makeTextResult(makeAbsoluteURI(rootFolderB, 'fileB.js')),
makeTextResult(makeAbsoluteURI(rootFolderB, 'file3.js'))]);
makeTextResult('folder/fileA.scss'),
makeTextResult('folder/file2.css'),
makeTextResult('fileB.ts'),
makeTextResult('fileB.js'),
makeTextResult('file3.js')]);
});
test('max results = 1', async () => {
const providedResults: vscode.TextSearchResult[] = [
makeTextResult(makeAbsoluteURI(rootFolderA, 'file1.ts')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'file2.ts'))
makeTextResult('file1.ts'),
makeTextResult('file2.ts')
];
let wasCanceled = false;
......@@ -988,9 +983,9 @@ suite('ExtHostSearch', () => {
test('max results = 2', async () => {
const providedResults: vscode.TextSearchResult[] = [
makeTextResult(makeAbsoluteURI(rootFolderA, 'file1.ts')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'file2.ts')),
makeTextResult(makeAbsoluteURI(rootFolderA, 'file3.ts'))
makeTextResult('file1.ts'),
makeTextResult('file2.ts'),
makeTextResult('file3.ts')
];
let wasCanceled = false;
......@@ -1028,7 +1023,7 @@ suite('ExtHostSearch', () => {
'file1.ts',
'file2.ts',
'file3.ts',
].forEach(f => progress.report(makeTextResult(makeAbsoluteURI(options.folder, f))));
].forEach(f => progress.report(makeTextResult(f)));
});
}
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册