Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -12,9 +12,7 @@ import gracefulFs = require('graceful-fs');
gracefulFs.gracefulify(fs);
import arrays = require('vs/base/common/arrays');
import { compareByScore } from 'vs/base/common/comparers';
import objects = require('vs/base/common/objects');
import scorer = require('vs/base/common/scorer');
import strings = require('vs/base/common/strings');
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { FileWalker, Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch';
@@ -22,8 +20,10 @@ import { MAX_FILE_SIZE } from 'vs/platform/files/common/files';
import { RipgrepEngine } from 'vs/workbench/services/search/node/ripgrepTextSearch';
import { Engine as TextSearchEngine } from 'vs/workbench/services/search/node/textSearch';
import { TextSearchWorkerProvider } from 'vs/workbench/services/search/node/textSearchWorkerProvider';
import { IRawSearchService, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchProgressItem, ISerializedSearchComplete, ISearchEngine, IFileSearchProgressItem } from './search';
import { IRawSearchService, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchProgressItem, ISerializedSearchComplete, ISearchEngine, IFileSearchProgressItem, ITelemetryEvent } from './search';
import { ICachedSearchStats, IProgress } from 'vs/platform/search/common/search';
import { fuzzyContains } from 'vs/base/common/strings';
import { compareItemsByScore, IItemAccessor, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
export class SearchService implements IRawSearchService {
@@ -33,6 +33,8 @@ export class SearchService implements IRawSearchService {
private textSearchWorkerProvider: TextSearchWorkerProvider;
private telemetryPipe: (event: ITelemetryEvent) => void;
public fileSearch(config: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem> {
return this.doFileSearch(FileSearchEngine, config, SearchService.BATCH_SIZE);
}
@@ -81,6 +83,7 @@ export class SearchService implements IRawSearchService {
includePattern: config.includePattern,
excludePattern: config.excludePattern,
filePattern: config.filePattern,
useRipgrep: false,
maxFilesize: MAX_FILE_SIZE
}),
this.textSearchWorkerProvider);
@@ -140,6 +143,12 @@ export class SearchService implements IRawSearchService {
searchPromise = this.doSearch(engine, -1)
.then(result => {
c([result, results]);
if (this.telemetryPipe) {
this.telemetryPipe({
eventName: 'fileSearch',
data: result.stats
});
}
}, e, progress => {
if (Array.isArray(progress)) {
results = progress;
@@ -161,23 +170,26 @@ export class SearchService implements IRawSearchService {
allResultsPromise = this.preventCancellation(allResultsPromise);
}
let chained: TPromise<void>;
return new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => {
allResultsPromise.then(([result, results]) => {
chained = allResultsPromise.then(([result, results]) => {
const scorerCache: ScorerCache = cache ? cache.scorerCache : Object.create(null);
const unsortedResultTime = Date.now();
const sortedResults = this.sortResults(config, results, scorerCache);
const sortedResultTime = Date.now();
return this.sortResults(config, results, scorerCache)
.then(sortedResults => {
const sortedResultTime = Date.now();
c([{
stats: objects.assign({}, result.stats, {
unsortedResultTime,
sortedResultTime
}),
limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults
}, sortedResults]);
c([{
stats: objects.assign({}, result.stats, {
unsortedResultTime,
sortedResultTime
}),
limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults
}, sortedResults]);
});
}, e, p);
}, () => {
allResultsPromise.cancel();
chained.cancel();
});
}
@@ -198,47 +210,54 @@ export class SearchService implements IRawSearchService {
const cacheLookupStartTime = Date.now();
const cached = this.getResultsFromCache(cache, config.filePattern);
if (cached) {
let chained: TPromise<void>;
return new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => {
cached.then(([result, results, cacheStats]) => {
chained = cached.then(([result, results, cacheStats]) => {
const cacheLookupResultTime = Date.now();
const sortedResults = this.sortResults(config, results, cache.scorerCache);
const sortedResultTime = Date.now();
return this.sortResults(config, results, cache.scorerCache)
.then(sortedResults => {
const sortedResultTime = Date.now();
const stats: ICachedSearchStats = {
fromCache: true,
cacheLookupStartTime: cacheLookupStartTime,
cacheFilterStartTime: cacheStats.cacheFilterStartTime,
cacheLookupResultTime: cacheLookupResultTime,
cacheEntryCount: cacheStats.cacheFilterResultCount,
resultCount: results.length
};
if (config.sortByScore) {
stats.unsortedResultTime = cacheLookupResultTime;
stats.sortedResultTime = sortedResultTime;
}
if (!cacheStats.cacheWasResolved) {
stats.joined = result.stats;
}
c([
{
limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults,
stats: stats
},
sortedResults
]);
const stats: ICachedSearchStats = {
fromCache: true,
cacheLookupStartTime: cacheLookupStartTime,
cacheFilterStartTime: cacheStats.cacheFilterStartTime,
cacheLookupResultTime: cacheLookupResultTime,
cacheEntryCount: cacheStats.cacheFilterResultCount,
resultCount: results.length
};
if (config.sortByScore) {
stats.unsortedResultTime = cacheLookupResultTime;
stats.sortedResultTime = sortedResultTime;
}
if (!cacheStats.cacheWasResolved) {
stats.joined = result.stats;
}
c([
{
limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults,
stats: stats
},
sortedResults
]);
});
}, e, p);
}, () => {
cached.cancel();
chained.cancel();
});
}
return undefined;
}
private sortResults(config: IRawSearch, results: IRawFileMatch[], scorerCache: ScorerCache): IRawFileMatch[] {
const filePattern = config.filePattern;
const normalizedSearchValue = strings.stripWildcards(filePattern).toLowerCase();
const compare = (elementA: IRawFileMatch, elementB: IRawFileMatch) => compareByScore(elementA, elementB, FileMatchAccessor, filePattern, normalizedSearchValue, scorerCache);
return arrays.top(results, compare, config.maxResults);
private sortResults(config: IRawSearch, results: IRawFileMatch[], scorerCache: ScorerCache): TPromise<IRawFileMatch[]> {
// we use the same compare function that is used later when showing the results using fuzzy scoring
// this is very important because we are also limiting the number of results by config.maxResults
// and as such we want the top items to be included in this result set if the number of items
// exceeds config.maxResults.
const query = prepareQuery(config.filePattern);
const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache);
return arrays.topAsync(results, compare, config.maxResults, 10000);
}
private sendProgress(results: ISerializedFileMatch[], progressCb: (batch: ISerializedFileMatch[]) => void, batchSize: number) {
@@ -291,7 +310,7 @@ export class SearchService implements IRawSearchService {
let entry = cachedEntries[i];
// Check if this entry is a match for the search value
if (!scorer.matches(entry.relativePath, normalizedSearchValueLowercase)) {
if (!fuzzyContains(entry.relativePath, normalizedSearchValueLowercase)) {
continue;
}
@@ -369,6 +388,14 @@ export class SearchService implements IRawSearchService {
return TPromise.as(undefined);
}
public fetchTelemetry(): PPromise<void, ITelemetryEvent> {
return new PPromise((c, e, p) => {
this.telemetryPipe = p;
}, () => {
this.telemetryPipe = null;
});
}
private preventCancellation<C, P>(promise: PPromise<C, P>): PPromise<C, P> {
return new PPromise<C, P>((c, e, p) => {
// Allow for piled up cancellations to come through first.
@@ -388,20 +415,20 @@ class Cache {
public scorerCache: ScorerCache = Object.create(null);
}
interface ScorerCache {
[key: string]: number;
}
const FileMatchItemAccessor = new class implements IItemAccessor<IRawFileMatch> {
class FileMatchAccessor {
public static getLabel(match: IRawFileMatch): string {
return match.basename;
public getItemLabel(match: IRawFileMatch): string {
return match.basename; // e.g. myFile.txt
}
public static getResourcePath(match: IRawFileMatch): string {
return match.relativePath;
public getItemDescription(match: IRawFileMatch): string {
return match.relativePath.substr(0, match.relativePath.length - match.basename.length - 1); // e.g. some/path/to/file
}
}
public getItemPath(match: IRawFileMatch): string {
return match.relativePath; // e.g. some/path/to/file/myFile.txt
}
};
interface CacheStats {
cacheWasResolved: boolean;