diff --git a/.vscode/settings.json b/.vscode/settings.json index e258a2c4154..7acd2c0fbe4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,5 @@ ".build/**": true, "out*/**": true, "extensions/**/out/**": true - }, - "filePicker.alternateFileNameMatching": true + } } \ No newline at end of file diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index a2fb67ac785..948ab502279 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -29,7 +29,6 @@ export interface IQueryOptions { includePattern?: glob.IExpression; maxResults?: number; fileEncoding?: string; - matchFuzzy?: boolean; } export interface ISearchQuery extends IQueryOptions { @@ -94,8 +93,4 @@ export interface ISearchConfiguration extends IFilesConfiguration { search: { exclude: glob.IExpression; }; - - filePicker: { - alternateFileNameMatching: boolean; - }; } \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 9be3fc9d455..f352f0f799b 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -51,8 +51,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { private delayer: ThrottledDelayer; private pendingSearch: TPromise; private isClosed: boolean; - private scorerCache: {[key: string]: number}; - private fuzzyMatchingEnabled: boolean; + private scorerCache: { [key: string]: number }; private configurationListenerUnbind: ListenerUnbind; constructor( @@ -73,19 +72,6 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.resultsToSearchCache = Object.create(null); this.scorerCache = Object.create(null); this.delayer = new ThrottledDelayer(OpenAnythingHandler.SEARCH_DELAY); - - this.updateFuzzyMatching(contextService.getOptions().globalSettings.settings); - - this.registerListeners(); - } - - private registerListeners(): void { - this.configurationListenerUnbind = this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.updateFuzzyMatching(e.config)); - } - - private updateFuzzyMatching(configuration: ISearchConfiguration): void { - this.fuzzyMatchingEnabled = configuration.filePicker && configuration.filePicker.alternateFileNameMatching; - this.openFileHandler.setFuzzyMatchingEnabled(this.fuzzyMatchingEnabled); } public getResults(searchValue: string): TPromise { @@ -172,7 +158,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { let result = [...results[0].entries, ...results[1].entries]; // Sort - result.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled)); + result.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue)); // Apply Range result.forEach((element) => { @@ -271,7 +257,6 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Pattern match on results and adjust highlights let results: QuickOpenEntry[] = []; - const searchInPath = this.fuzzyMatchingEnabled || searchValue.indexOf(paths.nativeSep) >= 0; for (let i = 0; i < cachedEntries.length; i++) { let entry = cachedEntries[i]; @@ -282,20 +267,20 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Check if this entry is a match for the search value const resource = entry.getResource(); // can be null for symbol results! - let targetToMatch = searchInPath && resource ? labels.getPathLabel(resource, this.contextService) : entry.getLabel(); - if (!filters.matchesFuzzy(searchValue, targetToMatch, this.fuzzyMatchingEnabled)) { + let targetToMatch = resource ? labels.getPathLabel(resource, this.contextService) : entry.getLabel(); + if (!filters.matchesFuzzy(searchValue, targetToMatch, true /* separate substring matching */)) { continue; } // Apply highlights - const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled); + const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, true /* fuzzy highlight */); entry.setHighlights(labelHighlights, descriptionHighlights); results.push(entry); } // Sort - results.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled)); + results.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue)); // Apply Range results.forEach((element) => { @@ -310,55 +295,51 @@ export class OpenAnythingHandler extends QuickOpenHandler { return viewResults; } - private sort(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, enableFuzzyScoring: boolean): number { + private sort(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number { + const labelA = elementA.getLabel(); + const labelB = elementB.getLabel(); - // Fuzzy scoring is special - if (enableFuzzyScoring) { - const labelA = elementA.getLabel(); - const labelB = elementB.getLabel(); + // treat prefix matches highest in any case + const prefixCompare = compareByPrefix(labelA, labelB, lookFor); + if (prefixCompare) { + return prefixCompare; + } - // treat prefix matches highest in any case - const prefixCompare = compareByPrefix(labelA, labelB, lookFor); - if (prefixCompare) { - return prefixCompare; - } + // Give higher importance to label score + const labelAScore = scorer.score(labelA, lookFor, this.scorerCache); + const labelBScore = scorer.score(labelB, lookFor, this.scorerCache); - // Give higher importance to label score - const labelAScore = scorer.score(labelA, lookFor, this.scorerCache); - const labelBScore = scorer.score(labelB, lookFor, this.scorerCache); + // Useful for understanding the scoring + // elementA.setPrefix(labelAScore + ' '); + // elementB.setPrefix(labelBScore + ' '); + + if (labelAScore !== labelBScore) { + return labelAScore > labelBScore ? -1 : 1; + } + + // Score on full resource path comes next (can be null for symbols!) + let resourceA = elementA.getResource(); + let resourceB = elementB.getResource(); + if (resourceA && resourceB) { + const resourceAScore = scorer.score(resourceA.fsPath, lookFor, this.scorerCache); + const resourceBScore = scorer.score(resourceB.fsPath, lookFor, this.scorerCache); // Useful for understanding the scoring - // elementA.setPrefix(labelAScore + ' '); - // elementB.setPrefix(labelBScore + ' '); + // elementA.setPrefix(elementA.getPrefix() + ' ' + resourceAScore + ': '); + // elementB.setPrefix(elementB.getPrefix() + ' ' + resourceBScore + ': '); - if (labelAScore !== labelBScore) { - return labelAScore > labelBScore ? -1 : 1; + if (resourceAScore !== resourceBScore) { + return resourceAScore > resourceBScore ? -1 : 1; } + } - // Score on full resource path comes next (can be null for symbols!) - let resourceA = elementA.getResource(); - let resourceB = elementB.getResource(); - if (resourceA && resourceB) { - const resourceAScore = scorer.score(resourceA.fsPath, lookFor, this.scorerCache); - const resourceBScore = scorer.score(resourceB.fsPath, lookFor, this.scorerCache); + // At this place, the scores are identical so we check for string lengths and favor shorter ones + if (labelA.length !== labelB.length) { + return labelA.length < labelB.length ? -1 : 1; + } - // Useful for understanding the scoring - // elementA.setPrefix(elementA.getPrefix() + ' ' + resourceAScore + ': '); - // elementB.setPrefix(elementB.getPrefix() + ' ' + resourceBScore + ': '); - - if (resourceAScore !== resourceBScore) { - return resourceAScore > resourceBScore ? -1 : 1; - } - } - - // At this place, the scores are identical so we check for string lengths and favor shorter ones - if (labelA.length !== labelB.length) { - return labelA.length < labelB.length ? -1 : 1; - } - - if (resourceA && resourceB && resourceA.fsPath.length !== resourceB.fsPath.length) { - return resourceA.fsPath.length < resourceB.fsPath.length ? -1 : 1; - } + if (resourceA && resourceB && resourceA.fsPath.length !== resourceB.fsPath.length) { + return resourceA.fsPath.length < resourceB.fsPath.length ? -1 : 1; } return QuickOpenEntry.compare(elementA, elementB, lookFor); diff --git a/src/vs/workbench/parts/search/browser/openFileHandler.ts b/src/vs/workbench/parts/search/browser/openFileHandler.ts index 9ce631cb8a7..58983e0622d 100644 --- a/src/vs/workbench/parts/search/browser/openFileHandler.ts +++ b/src/vs/workbench/parts/search/browser/openFileHandler.ts @@ -88,7 +88,6 @@ export class OpenFileHandler extends QuickOpenHandler { private queryBuilder: QueryBuilder; private delayer: ThrottledDelayer; private isStandalone: boolean; - private fuzzyMatchingEnabled: boolean; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -111,10 +110,6 @@ export class OpenFileHandler extends QuickOpenHandler { this.isStandalone = standalone; } - public setFuzzyMatchingEnabled(enabled: boolean): void { - this.fuzzyMatchingEnabled = enabled; - } - public getResults(searchValue: string): TPromise { searchValue = searchValue.trim(); let promise: TPromise; @@ -135,8 +130,7 @@ export class OpenFileHandler extends QuickOpenHandler { let query: IQueryOptions = { folderResources: this.contextService.getWorkspace() ? [this.contextService.getWorkspace().resource] : [], extraFileResources: this.textFileService.getWorkingFilesModel().getOutOfWorkspaceContextEntries().map(e => e.resource), - filePattern: searchValue, - matchFuzzy: this.fuzzyMatchingEnabled + filePattern: searchValue }; return this.queryBuilder.file(query).then((query) => this.searchService.search(query)).then((complete) => { @@ -152,7 +146,7 @@ export class OpenFileHandler extends QuickOpenHandler { let entry = this.instantiationService.createInstance(FileEntry, label, description, fileMatch.resource); // Apply highlights - let {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled); + let {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, true /* fuzzy highlight */); entry.setHighlights(labelHighlights, descriptionHighlights); results.push(entry); diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index b2aeae9ba8f..80f95d078b7 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -196,11 +196,6 @@ configurationRegistry.registerConfiguration({ } ] } - }, - 'filePicker.alternateFileNameMatching': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('enableFuzzy', "Experimental support for fuzzy matching of file names in the file picker.") } } }); \ No newline at end of file diff --git a/src/vs/workbench/parts/search/common/searchQuery.ts b/src/vs/workbench/parts/search/common/searchQuery.ts index bc89acffe06..ae2a715cc70 100644 --- a/src/vs/workbench/parts/search/common/searchQuery.ts +++ b/src/vs/workbench/parts/search/common/searchQuery.ts @@ -60,8 +60,7 @@ export class QueryBuilder { includePattern: options.includePattern, maxResults: options.maxResults, fileEncoding: options.fileEncoding, - contentPattern: contentPattern, - matchFuzzy: options.matchFuzzy + contentPattern: contentPattern }; }); } diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 66c341f0ab1..867accd89a5 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -28,14 +28,12 @@ export class FileWalker { private resultCount: number; private isCanceled: boolean; private searchInPath: boolean; - private matchFuzzy: boolean; private walkedPaths: { [path: string]: boolean; }; constructor(config: IRawSearch) { this.config = config; this.filePattern = config.filePattern; - this.matchFuzzy = config.matchFuzzy; this.excludePattern = config.excludePattern; this.includePattern = config.includePattern; this.maxResults = config.maxResults || null; @@ -231,7 +229,7 @@ export class FileWalker { // Check for search pattern if (this.filePattern) { - const res = filters.matchesFuzzy(this.filePattern, this.matchFuzzy || this.searchInPath ? path : name, this.matchFuzzy); + const res = filters.matchesFuzzy(this.filePattern, path, true /* separate substring matching */); return !!res && res.length > 0; } diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index cc73b8b574f..61c950e8f07 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -20,7 +20,6 @@ export interface IRawSearch { rootFolders: string[]; extraFiles?: string[]; filePattern?: string; - matchFuzzy?: boolean; excludePattern?: glob.IExpression; includePattern?: glob.IExpression; contentPattern?: IPatternInfo; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index a53ea294876..6526b0468ae 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -218,8 +218,7 @@ class DiskSearch { filePattern: query.filePattern, excludePattern: query.excludePattern, includePattern: query.includePattern, - maxResults: query.maxResults, - matchFuzzy: query.matchFuzzy + maxResults: query.maxResults }; if (query.type === QueryType.Text) { diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index f1a70e0d505..2b3a2b5598a 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -73,8 +73,7 @@ suite('Search', () => { test('Files: examples (fuzzy)', function(done: () => void) { let engine = new FileSearchEngine({ rootFolders: rootfolders(), - filePattern: 'xl', - matchFuzzy: true + filePattern: 'xl' }); let count = 0;