mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-18 06:09:20 +01:00
Make the fuzzy option an option for the file picker only
This commit is contained in:
@@ -136,31 +136,12 @@ export class QuickOpenEntry {
|
||||
/**
|
||||
* A good default sort implementation for quick open entries respecting highlight information
|
||||
* as well as associated resources.
|
||||
*
|
||||
* Supports fuzzy scoring when the option is enabled.
|
||||
*/
|
||||
public static compare(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, enableFuzzyScoring = false): number {
|
||||
public static compare(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number {
|
||||
|
||||
// Normalize
|
||||
if (lookFor) {
|
||||
lookFor = Strings.stripWildcards(lookFor);
|
||||
}
|
||||
|
||||
// Fuzzy scoring is special
|
||||
if (enableFuzzyScoring) {
|
||||
const labelAScore = Strings.score(elementA.getLabel(), lookFor);
|
||||
const labelBScore = Strings.score(elementB.getLabel(), lookFor);
|
||||
|
||||
if (labelAScore !== labelBScore) {
|
||||
return labelAScore > labelBScore ? -1 : 1;
|
||||
}
|
||||
|
||||
const descriptionAScore = Strings.score(elementA.getDescription(), lookFor);
|
||||
const descriptionBScore = Strings.score(elementB.getDescription(), lookFor);
|
||||
|
||||
if (descriptionAScore !== descriptionBScore) {
|
||||
return descriptionAScore > descriptionBScore ? -1 : 1;
|
||||
}
|
||||
lookFor = Strings.stripWildcards(lookFor).toLowerCase();
|
||||
}
|
||||
|
||||
// Give matches with label highlights higher priority over
|
||||
@@ -186,15 +167,13 @@ export class QuickOpenEntry {
|
||||
}
|
||||
}
|
||||
|
||||
return compareAnything(nameA, nameB, lookFor ? lookFor.toLowerCase() : lookFor);
|
||||
return compareAnything(nameA, nameB, lookFor);
|
||||
}
|
||||
|
||||
/**
|
||||
* A good default highlight implementation for an entry with label and description.
|
||||
*
|
||||
* Supports fuzzy matching when the option is enabled.
|
||||
*/
|
||||
public static highlight(entry: QuickOpenEntry, lookFor: string, enableFuzzyMatching = false): { labelHighlights: IHighlight[], descriptionHighlights: IHighlight[] } {
|
||||
public static highlight(entry: QuickOpenEntry, lookFor: string, enableSeparateSubstringMatching = false): { labelHighlights: IHighlight[], descriptionHighlights: IHighlight[] } {
|
||||
let labelHighlights: IHighlight[] = [];
|
||||
let descriptionHighlights: IHighlight[] = [];
|
||||
|
||||
@@ -203,24 +182,24 @@ export class QuickOpenEntry {
|
||||
|
||||
// Highlight only inside label
|
||||
if (lookFor.indexOf(Paths.nativeSep) < 0) {
|
||||
labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel(), enableFuzzyMatching);
|
||||
labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel(), enableSeparateSubstringMatching);
|
||||
}
|
||||
|
||||
// Highlight in label and description
|
||||
else {
|
||||
descriptionHighlights = Filters.matchesFuzzy(Strings.trim(lookFor, Paths.nativeSep), entry.getDescription(), enableFuzzyMatching);
|
||||
descriptionHighlights = Filters.matchesFuzzy(Strings.trim(lookFor, Paths.nativeSep), entry.getDescription(), enableSeparateSubstringMatching);
|
||||
|
||||
// If we have no highlights, assume that the match is split among name and parent folder
|
||||
if (!descriptionHighlights || !descriptionHighlights.length) {
|
||||
labelHighlights = Filters.matchesFuzzy(Paths.basename(lookFor), entry.getLabel(), enableFuzzyMatching);
|
||||
descriptionHighlights = Filters.matchesFuzzy(Strings.trim(Paths.dirname(lookFor), Paths.nativeSep), entry.getDescription(), enableFuzzyMatching);
|
||||
labelHighlights = Filters.matchesFuzzy(Paths.basename(lookFor), entry.getLabel(), enableSeparateSubstringMatching);
|
||||
descriptionHighlights = Filters.matchesFuzzy(Strings.trim(Paths.dirname(lookFor), Paths.nativeSep), entry.getDescription(), enableSeparateSubstringMatching);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight by label otherwise
|
||||
else {
|
||||
labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel(), enableFuzzyMatching);
|
||||
labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel(), enableSeparateSubstringMatching);
|
||||
}
|
||||
|
||||
return { labelHighlights, descriptionHighlights };
|
||||
|
||||
@@ -92,5 +92,6 @@ export class LineMatch implements ILineMatch {
|
||||
export interface ISearchConfiguration extends IFilesConfiguration {
|
||||
search: {
|
||||
exclude: glob.IExpression;
|
||||
fuzzyFilePicker: boolean;
|
||||
};
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import strings = require('vs/base/common/strings');
|
||||
import filters = require('vs/base/common/filters');
|
||||
import uuid = require('vs/base/common/uuid');
|
||||
import types = require('vs/base/common/types');
|
||||
import {ListenerUnbind} from 'vs/base/common/eventEmitter';
|
||||
import {Mode, IContext, IAutoFocus, IQuickNavigateConfiguration, IModel} from 'vs/base/parts/quickopen/browser/quickOpen';
|
||||
import {QuickOpenEntryItem, QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup} from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import {QuickOpenWidget} from 'vs/base/parts/quickopen/browser/quickOpenWidget';
|
||||
@@ -79,8 +78,6 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe
|
||||
private actionProvider = new ContributableActionProvider();
|
||||
private previousValue = '';
|
||||
private visibilityChangeTimeoutHandle: number;
|
||||
private fuzzyMatchingEnabled: boolean;
|
||||
private configurationListenerUnbind: ListenerUnbind;
|
||||
|
||||
constructor(
|
||||
private eventService: IEventService,
|
||||
@@ -102,22 +99,8 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe
|
||||
|
||||
this.inQuickOpenMode = keybindingService.createKey(QUICK_OPEN_MODE, false);
|
||||
|
||||
this.updateFuzzyMatching(contextService.getOptions().globalSettings.settings);
|
||||
|
||||
this._onShow = new EventSource<() => void>();
|
||||
this._onHide = new EventSource<() => void>();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Listen to configuration changes
|
||||
this.configurationListenerUnbind = this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.updateFuzzyMatching(e.config));
|
||||
}
|
||||
|
||||
private updateFuzzyMatching(configuration: any): void {
|
||||
this.fuzzyMatchingEnabled = configuration.picker && configuration.picker.enableFuzzy;
|
||||
}
|
||||
|
||||
public get onShow(): EventProvider<() => void> {
|
||||
@@ -136,10 +119,6 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe
|
||||
return this.editorHistoryModel;
|
||||
}
|
||||
|
||||
public isFuzzyMatchingEnabled(): boolean {
|
||||
return this.fuzzyMatchingEnabled;
|
||||
}
|
||||
|
||||
public create(): void {
|
||||
|
||||
// Listen on Editor Input Changes to show in MRU List
|
||||
@@ -852,10 +831,6 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe
|
||||
this.pickOpenWidget.dispose();
|
||||
}
|
||||
|
||||
if (this.configurationListenerUnbind) {
|
||||
this.configurationListenerUnbind();
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,19 +73,4 @@ configurationRegistry.registerConfiguration({
|
||||
'description': nls.localize('updateChannel', "Configure the update channel to receive updates from. Requires a restart after change.")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Picker Configuration
|
||||
configurationRegistry.registerConfiguration({
|
||||
'id': 'picker',
|
||||
'order': 11,
|
||||
'title': nls.localize('filterConfigurationTitle', "Picker configuration"),
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'picker.enableFuzzy': {
|
||||
'type': 'boolean',
|
||||
'default': false,
|
||||
'description': nls.localize('enableFuzzy', "Enable or disable fuzzy matching and sorting in the picker.")
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -14,6 +14,7 @@ import paths = require('vs/base/common/paths');
|
||||
import filters = require('vs/base/common/filters');
|
||||
import labels = require('vs/base/common/labels');
|
||||
import {IRange} from 'vs/editor/common/editorCommon';
|
||||
import {ListenerUnbind} from 'vs/base/common/eventEmitter';
|
||||
import {IAutoFocus} from 'vs/base/parts/quickopen/browser/quickOpen';
|
||||
import {QuickOpenEntry, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import {QuickOpenHandler} from 'vs/workbench/browser/quickopen';
|
||||
@@ -21,8 +22,10 @@ import {FileEntry, OpenFileHandler} from 'vs/workbench/parts/search/browser/open
|
||||
import {OpenSymbolHandler as _OpenSymbolHandler} from 'vs/workbench/parts/search/browser/openSymbolHandler';
|
||||
import {IMessageService, Severity} from 'vs/platform/message/common/message';
|
||||
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
|
||||
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
|
||||
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
|
||||
import {IQuickOpenService} from 'vs/workbench/services/quickopen/browser/quickOpenService';
|
||||
import {ISearchConfiguration} from 'vs/platform/search/common/search';
|
||||
import {IConfigurationService, IConfigurationServiceEvent, ConfigurationServiceEventTypes} from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
// OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load
|
||||
export const OpenSymbolHandler = _OpenSymbolHandler
|
||||
@@ -42,12 +45,15 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
private delayer: ThrottledDelayer<QuickOpenModel>;
|
||||
private pendingSearch: TPromise<QuickOpenModel>;
|
||||
private isClosed: boolean;
|
||||
private fuzzyMatchingEnabled: boolean;
|
||||
private configurationListenerUnbind: ListenerUnbind;
|
||||
|
||||
constructor(
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IConfigurationService private configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -60,6 +66,19 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
|
||||
this.resultsToSearchCache = Object.create(null);
|
||||
this.delayer = new ThrottledDelayer<QuickOpenModel>(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.search && configuration.search.fuzzyFilePicker;
|
||||
this.openFileHandler.setFuzzyMatchingEnabled(this.fuzzyMatchingEnabled);
|
||||
}
|
||||
|
||||
public getResults(searchValue: string): TPromise<QuickOpenModel> {
|
||||
@@ -144,7 +163,7 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
let result = [...results[0].entries, ...results[1].entries];
|
||||
|
||||
// Sort
|
||||
result.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue, this.quickOpenService.isFuzzyMatchingEnabled()));
|
||||
result.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled));
|
||||
|
||||
// Apply Range
|
||||
result.forEach((element) => {
|
||||
@@ -237,7 +256,6 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
// Pattern match on results and adjust highlights
|
||||
let results: QuickOpenEntry[] = [];
|
||||
const searchInPath = searchValue.indexOf(paths.nativeSep) >= 0;
|
||||
const enableFuzzy = this.quickOpenService.isFuzzyMatchingEnabled();
|
||||
for (let i = 0; i < cachedEntries.length; i++) {
|
||||
let entry = cachedEntries[i];
|
||||
|
||||
@@ -248,19 +266,19 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
|
||||
// Check if this entry is a match for the search value
|
||||
let targetToMatch = searchInPath ? labels.getPathLabel(entry.getResource(), this.contextService) : entry.getLabel();
|
||||
if (!filters.matchesFuzzy(searchValue, targetToMatch, enableFuzzy)) {
|
||||
if (!filters.matchesFuzzy(searchValue, targetToMatch, this.fuzzyMatchingEnabled)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply highlights
|
||||
const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, enableFuzzy);
|
||||
const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled);
|
||||
entry.setHighlights(labelHighlights, descriptionHighlights);
|
||||
|
||||
results.push(entry);
|
||||
}
|
||||
|
||||
// Sort
|
||||
results.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue, enableFuzzy));
|
||||
results.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled));
|
||||
|
||||
// Apply Range
|
||||
results.forEach((element) => {
|
||||
@@ -272,6 +290,28 @@ export class OpenAnythingHandler extends QuickOpenHandler {
|
||||
return results;
|
||||
}
|
||||
|
||||
private sort(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, enableFuzzyScoring): number {
|
||||
|
||||
// Fuzzy scoring is special
|
||||
if (enableFuzzyScoring) {
|
||||
const labelAScore = strings.score(elementA.getLabel(), lookFor);
|
||||
const labelBScore = strings.score(elementB.getLabel(), lookFor);
|
||||
|
||||
if (labelAScore !== labelBScore) {
|
||||
return labelAScore > labelBScore ? -1 : 1;
|
||||
}
|
||||
|
||||
const descriptionAScore = strings.score(elementA.getDescription(), lookFor);
|
||||
const descriptionBScore = strings.score(elementB.getDescription(), lookFor);
|
||||
|
||||
if (descriptionAScore !== descriptionBScore) {
|
||||
return descriptionAScore > descriptionBScore ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return QuickOpenEntry.compare(elementA, elementB, lookFor);
|
||||
}
|
||||
|
||||
public getGroupLabel(): string {
|
||||
return nls.localize('fileAndTypeResults', "file and symbol results");
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ export class OpenFileHandler extends QuickOpenHandler {
|
||||
private queryBuilder: QueryBuilder;
|
||||
private delayer: ThrottledDelayer<QuickOpenEntry[]>;
|
||||
private isStandalone: boolean;
|
||||
private fuzzyMatchingEnabled: boolean;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -113,6 +114,10 @@ export class OpenFileHandler extends QuickOpenHandler {
|
||||
this.isStandalone = standalone;
|
||||
}
|
||||
|
||||
public setFuzzyMatchingEnabled(enabled: boolean): void {
|
||||
this.fuzzyMatchingEnabled = enabled;
|
||||
}
|
||||
|
||||
public getResults(searchValue: string): TPromise<QuickOpenModel> {
|
||||
searchValue = searchValue.trim();
|
||||
let promise: TPromise<QuickOpenEntry[]>;
|
||||
@@ -135,7 +140,7 @@ export class OpenFileHandler extends QuickOpenHandler {
|
||||
rootResources.push(this.contextService.getWorkspace().resource);
|
||||
}
|
||||
|
||||
let query: IQueryOptions = { filePattern: searchValue, matchFuzzy: this.quickOpenService.isFuzzyMatchingEnabled(), rootResources: rootResources };
|
||||
let query: IQueryOptions = { filePattern: searchValue, matchFuzzy: this.fuzzyMatchingEnabled, rootResources: rootResources };
|
||||
|
||||
return this.queryBuilder.file(query).then((query) => this.searchService.search(query)).then((complete) => {
|
||||
|
||||
@@ -150,7 +155,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.quickOpenService.isFuzzyMatchingEnabled());
|
||||
let {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled);
|
||||
entry.setHighlights(labelHighlights, descriptionHighlights);
|
||||
|
||||
results.push(entry);
|
||||
@@ -158,7 +163,7 @@ export class OpenFileHandler extends QuickOpenHandler {
|
||||
|
||||
// Sort (standalone only)
|
||||
if (this.isStandalone) {
|
||||
results = results.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue, this.quickOpenService.isFuzzyMatchingEnabled()));
|
||||
results = results.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue));
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
@@ -197,6 +197,11 @@ configurationRegistry.registerConfiguration({
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'search.fuzzyFilePicker': {
|
||||
'type': 'boolean',
|
||||
'default': false,
|
||||
'description': nls.localize('enableFuzzy', "Enable or disable fuzzy matching and sorting in the file picker.")
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -125,9 +125,4 @@ export interface IQuickOpenService {
|
||||
* Allows to register on the event that quick open is hiding
|
||||
*/
|
||||
onHide: EventProvider<() => void>;
|
||||
|
||||
/**
|
||||
* A boolean to indicate if fuzzy matching is enabled or not.
|
||||
*/
|
||||
isFuzzyMatchingEnabled(): boolean;
|
||||
}
|
||||
@@ -505,10 +505,6 @@ export class TestQuickOpenService implements QuickOpenService.IQuickOpenService
|
||||
return null;
|
||||
}
|
||||
|
||||
public isFuzzyMatchingEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public removeEditorHistoryEntry(input: WorkbenchEditorCommon.EditorInput): void {}
|
||||
public dispose() {}
|
||||
public quickNavigate(): void {}
|
||||
|
||||
Reference in New Issue
Block a user