Compare commits

...

3 commits

Author SHA1 Message Date
Raymond Zhao 6d07c4e616
Remove ordering by value and description 2021-11-18 09:15:28 -08:00
Raymond Zhao 200ef2057c
Fix whole word matching strategy 2021-11-17 09:28:06 -08:00
Raymond Zhao fec1b869f2
Add match-type sorting to filterSettings 2021-11-12 15:32:11 -08:00
4 changed files with 62 additions and 11 deletions

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences';
import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting, SettingMatchType } from 'vs/workbench/services/preferences/common/preferences';
import { IRange } from 'vs/editor/common/core/range';
import { distinct, top } from 'vs/base/common/arrays';
import * as strings from 'vs/base/common/strings';
@ -114,7 +114,7 @@ export class LocalSearchProvider implements ISearchProvider {
let orderedScore = LocalSearchProvider.START_SCORE; // Sort is not stable
const settingMatcher = (setting: ISetting) => {
const matches = new SettingMatches(this._filter, setting, true, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches;
const { matches, matchType } = new SettingMatches(this._filter, setting, true, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting));
const score = this._filter === setting.key ?
LocalSearchProvider.EXACT_MATCH_SCORE :
orderedScore--;
@ -122,6 +122,7 @@ export class LocalSearchProvider implements ISearchProvider {
return matches && matches.length ?
{
matches,
matchType,
score
} :
null;
@ -210,7 +211,8 @@ class RemoteSearchProvider implements ISearchProvider {
return <ISettingMatch>{
setting,
score: remoteSetting.score,
matches: [] // TODO
matches: [], // TODO
matchType: SettingMatchType.None
};
});
@ -338,8 +340,8 @@ class RemoteSearchProvider implements ISearchProvider {
scoredResults[getSettingKey(setting.key, 'core')] || // core setting
scoredResults[getSettingKey(setting.key)]; // core setting from original prod endpoint
if (remoteSetting && remoteSetting.score >= minScore) {
const settingMatches = new SettingMatches(this.options.filter, setting, false, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches;
return { matches: settingMatches, score: remoteSetting.score };
const { matches, matchType } = new SettingMatches(this.options.filter, setting, false, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting));
return { matches, matchType, score: remoteSetting.score };
}
return null;
@ -448,6 +450,7 @@ export class SettingMatches {
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
readonly matches: IRange[];
matchType: SettingMatchType = SettingMatchType.None;
constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`);
@ -465,6 +468,8 @@ export class SettingMatches {
const subSettingValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettingValueRanges);
result.push(...subSettingMatches.matches);
this.refreshMatchType(keyRanges.length + subSettingKeyRanges.length);
this.matchType |= subSettingMatches.matchType;
}
}
return result;
@ -478,12 +483,14 @@ export class SettingMatches {
const settingKeyAsWords: string = setting.key.split('.').join(' ');
for (const word of words) {
// Whole word match attempts also take place within this loop.
if (this.searchDescription) {
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
const descriptionMatches = matchesWords(word, setting.description[lineIndex], true);
if (descriptionMatches) {
this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
}
this.checkForWholeWordMatchType(word, setting.description[lineIndex]);
}
}
@ -491,6 +498,7 @@ export class SettingMatches {
if (keyMatches) {
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
}
this.checkForWholeWordMatchType(word, settingKeyAsWords);
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
if (valueMatches) {
@ -498,6 +506,9 @@ export class SettingMatches {
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
this.valueMatchingWords.set(word, []);
}
if (typeof setting.value === 'string') {
this.checkForWholeWordMatchType(word, setting.value);
}
}
const descriptionRanges: IRange[] = [];
@ -522,9 +533,26 @@ export class SettingMatches {
valueRanges = this.valuesMatcher(searchString, setting);
}
this.refreshMatchType(keyRanges.length);
return [...descriptionRanges, ...keyRanges, ...valueRanges];
}
private checkForWholeWordMatchType(singleWordQuery: string, lineToSearch: string) {
// Trim excess ending characters off the query.
singleWordQuery = singleWordQuery.toLowerCase().replace(/[\s-\._]+$/, '');
lineToSearch = lineToSearch.toLowerCase();
const singleWordRegex = new RegExp(`\\b${singleWordQuery}\\b`);
if (singleWordRegex.test(lineToSearch)) {
this.matchType |= SettingMatchType.WholeWordMatch;
}
}
private refreshMatchType(keyRangesLength: number) {
if (keyRangesLength) {
this.matchType |= SettingMatchType.KeyMatch;
}
}
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
const result: IRange[] = [];
for (const word of words) {

View file

@ -46,7 +46,7 @@ import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browse
import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree';
import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, FEATURE_SETTING_TAG, ID_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, WORKSPACE_TRUST_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IOpenSettingsOptions, IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingValueType, validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
import { IOpenSettingsOptions, IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingMatchType, SettingValueType, validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
import { IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync';
@ -1262,7 +1262,7 @@ export class SettingsEditor2 extends EditorPane {
for (const g of this.defaultSettingsEditorModel.settingsGroups.slice(1)) {
for (const sect of g.sections) {
for (const setting of sect.settings) {
fullResult.filterMatches.push({ setting, matches: [], score: 0 });
fullResult.filterMatches.push({ setting, matches: [], matchType: SettingMatchType.None, score: 0 });
}
}
}

View file

@ -115,9 +115,21 @@ export interface IFilterResult {
exactMatch?: boolean;
}
/**
* The ways a setting could match a query,
* sorted in increasing order of relevance.
* For now, ignore description and value matches.
*/
export enum SettingMatchType {
None = 0,
WholeWordMatch = 1 << 0,
KeyMatch = 1 << 1
}
export interface ISettingMatch {
setting: ISetting;
matches: IRange[] | null;
matchType: SettingMatchType;
score: number;
}
@ -157,7 +169,7 @@ export interface IPreferencesEditorModel<T> {
}
export type IGroupFilter = (group: ISettingsGroup) => boolean | null;
export type ISettingMatcher = (setting: ISetting, group: ISettingsGroup) => { matches: IRange[], score: number } | null;
export type ISettingMatcher = (setting: ISetting, group: ISettingsGroup) => { matches: IRange[], matchType: SettingMatchType, score: number } | null;
export interface ISettingsEditorModel extends IPreferencesEditorModel<ISetting> {
readonly onDidChangeGroups: Event<void>;

View file

@ -19,7 +19,7 @@ import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationPrope
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Registry } from 'vs/platform/registry/common/platform';
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup, SettingMatchType } from 'vs/workbench/services/preferences/common/preferences';
import { withNullAsUndefined, isArray } from 'vs/base/common/types';
import { FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
import { createValidator } from 'vs/workbench/services/preferences/common/preferencesValidation';
@ -70,14 +70,25 @@ export abstract class AbstractSettingsModel extends EditorModel {
filterMatches.push({
setting,
matches: settingMatchResult && settingMatchResult.matches,
score: settingMatchResult ? settingMatchResult.score : 0
matchType: settingMatchResult?.matchType ?? SettingMatchType.None,
score: settingMatchResult?.score ?? 0
});
}
}
}
}
return filterMatches.sort((a, b) => b.score - a.score);
filterMatches.sort((a, b) => {
// Sort by match type if the match types are not equal.
// The priority of the match type is given by the SettingMatchType enum.
// If they're equal, fall back to the "stable sort" counter score.
if (a.matchType !== b.matchType) {
return b.matchType - a.matchType;
} else {
return b.score - a.score;
}
});
return filterMatches;
}
getPreference(key: string): ISetting | undefined {