From 723b3348e5620c79cd0fe165a819c08ffefd7a45 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 30 Nov 2017 11:17:32 -0800 Subject: [PATCH] Add literal match highlighting to NL settings search --- .../parts/preferences/common/preferences.ts | 4 +- .../preferences/common/preferencesModels.ts | 50 +++++++++++-------- .../electron-browser/preferencesSearch.ts | 44 ++++++++-------- 3 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index f46423135ee..6407647bd2c 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -86,13 +86,13 @@ export interface IPreferencesEditorModel { } export type IGroupFilter = (group: ISettingsGroup) => boolean; -export type ISettingFilter = (setting: ISetting) => IRange[]; +export type ISettingMatcher = (setting: ISetting) => IRange[]; export interface ISettingsEditorModel extends IPreferencesEditorModel { readonly onDidChangeGroups: Event; settingsGroups: ISettingsGroup[]; groupsTerms: string[]; - filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult; + filterSettings(filter: string, groupFilter: IGroupFilter, settingMatcher: ISettingMatcher, mostRelevantSettings?: string[]): IFilterResult; findValueMatches(filter: string, setting: ISetting): IRange[]; } diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index cac74613246..384fb885805 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -14,7 +14,7 @@ import { visit, JSONVisitor } from 'vs/base/common/json'; import { IModel } from 'vs/editor/common/editorCommon'; import { EditorModel } from 'vs/workbench/common/editor'; import { IConfigurationNode, IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN, IConfigurationPropertySchema, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingFilter } from 'vs/workbench/parts/preferences/common/preferences'; +import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingMatcher } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -26,7 +26,7 @@ export abstract class AbstractSettingsModel extends EditorModel { return this.settingsGroups.map(group => '@' + group.id); } - protected doFilterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { + protected doFilterSettings(filter: string, groupFilter: IGroupFilter, settingMatcher: ISettingMatcher): IFilterResult { const allGroups = this.settingsGroups; if (!filter) { @@ -56,7 +56,7 @@ export abstract class AbstractSettingsModel extends EditorModel { for (const section of group.sections) { const settings: ISetting[] = []; for (const setting of section.settings) { - const settingMatches = settingFilter(setting); + const settingMatches = settingMatcher(setting); if (groupMatched || settingMatches && settingMatches.length) { settings.push(setting); } @@ -108,6 +108,8 @@ export abstract class AbstractSettingsModel extends EditorModel { } public abstract settingsGroups: ISettingsGroup[]; + + public abstract findValueMatches(filter: string, setting: ISetting): IRange[]; } export class SettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { @@ -147,8 +149,8 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti return this.settingsModel.getValue(); } - public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { - return this.doFilterSettings(filter, groupFilter, settingFilter); + public filterSettings(filter: string, groupFilter: IGroupFilter, settingMatcher: ISettingMatcher): IFilterResult { + return this.doFilterSettings(filter, groupFilter, settingMatcher); } public findValueMatches(filter: string, setting: ISetting): IRange[] { @@ -388,24 +390,13 @@ export class DefaultSettings extends Disposable { this.initAllSettingsMap(settingsGroups); const mostCommonlyUsed = this.getMostCommonlyUsedSettings(settingsGroups); this._allSettingsGroups = [mostCommonlyUsed, ...settingsGroups]; - - const builder = new SettingsContentBuilder(); - builder.pushLine('['); - builder.pushGroups([mostCommonlyUsed]); - builder.pushLine(','); - builder.pushGroups(settingsGroups); - builder.pushLine(']'); - this._content = builder.getContent(); - + this._content = this.toContent(this._allSettingsGroups, true); return this._content; } get raw(): string { if (!DefaultSettings._RAW) { - const settingsGroups = this.getRegisteredGroups(); - const builder = new SettingsContentBuilder(); - builder.pushGroups(settingsGroups); - DefaultSettings._RAW = builder.getContent(); + DefaultSettings._RAW = this.toContent(this.getRegisteredGroups(), false); } return DefaultSettings._RAW; } @@ -543,6 +534,18 @@ export class DefaultSettings extends Disposable { return c1.order - c2.order; } + private toContent(settingsGroups: ISettingsGroup[], asArray: boolean): string { + const builder = new SettingsContentBuilder(); + if (asArray) { + builder.pushLine('['); + } + builder.pushGroups(settingsGroups); + if (asArray) { + builder.pushLine(']'); + } + return builder.getContent(); + } + } export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { @@ -576,20 +579,25 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return this.defaultSettings.settingsGroups; } - public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult { + public filterSettings(filter: string, groupFilter: IGroupFilter, settingMatcher: ISettingMatcher, mostRelevantSettings?: string[]): IFilterResult { if (mostRelevantSettings) { const mostRelevantGroup = this.renderMostRelevantSettings(mostRelevantSettings); + // calculate match ranges + const matches = mostRelevantGroup.sections[0].settings.reduce((prev, s) => { + return prev.concat(settingMatcher(s)); + }, []); + return { allGroups: [...this.settingsGroups, mostRelevantGroup], filteredGroups: mostRelevantGroup.sections[0].settings.length ? [mostRelevantGroup] : [], - matches: [], + matches, query: filter }; } else { // Do local search and add empty 'most relevant' group const mostRelevantGroup = this.renderMostRelevantSettings([]); - const result = this.doFilterSettings(filter, groupFilter, settingFilter); + const result = this.doFilterSettings(filter, groupFilter, settingMatcher); result.allGroups = [...result.allGroups, mostRelevantGroup]; return result; } diff --git a/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts b/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts index da0c0a10ffb..1c5ebbab752 100644 --- a/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts +++ b/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts @@ -128,11 +128,11 @@ class LocalSearchProvider { return regex.test(group.title); }; - const settingFilter = (setting: ISetting) => { - return new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + const settingMatcher = (setting: ISetting) => { + return new SettingMatches(this._filter, setting, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; }; - return TPromise.wrap(preferencesModel.filterSettings(this._filter, groupFilter, settingFilter)); + return TPromise.wrap(preferencesModel.filterSettings(this._filter, groupFilter, settingMatcher)); } } @@ -150,19 +150,6 @@ class RemoteSearchProvider { filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { return this._remoteSearchP.then(remoteResult => { - const settingFilter = (setting: ISetting) => { - if (!!remoteResult.scoredResults[setting.key]) { - const settingMatches = new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; - if (settingMatches.length) { - return settingMatches; - } else { - return [new Range(setting.keyRange.startLineNumber, setting.keyRange.startColumn, setting.keyRange.endLineNumber, setting.keyRange.startColumn)]; - } - } else { - return null; - } - }; - if (remoteResult) { let sortedNames = Object.keys(remoteResult.scoredResults).sort((a, b) => remoteResult.scoredResults[b] - remoteResult.scoredResults[a]); if (sortedNames.length) { @@ -170,7 +157,8 @@ class RemoteSearchProvider { sortedNames = sortedNames.filter(name => remoteResult.scoredResults[name] >= highScore / 2); } - const result = preferencesModel.filterSettings(this._filter, group => null, settingFilter, sortedNames); + const settingMatcher = this.getRemoteSettingMatcher(sortedNames, preferencesModel); + const result = preferencesModel.filterSettings(this._filter, group => null, settingMatcher, sortedNames); result.metadata = remoteResult; return result; } else { @@ -226,6 +214,22 @@ class RemoteSearchProvider { return TPromise.as(p as any); } + + private getRemoteSettingMatcher(names: string[], preferencesModel: ISettingsEditorModel): any { + const resultSet = new Set(); + names.forEach(name => resultSet.add(name)); + + return (setting: ISetting) => { + if (resultSet.has(setting.key)) { + const settingMatches = new SettingMatches(this._filter, setting, false, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + if (settingMatches.length) { + return settingMatches; + } + } + + return []; + }; + } } const API_VERSION = 'api-version=2016-09-01-Preview'; @@ -275,7 +279,7 @@ class SettingMatches { public readonly matches: IRange[]; - constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { + constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); } @@ -283,7 +287,7 @@ class SettingMatches { const result = this._doFindMatchesInSetting(searchString, setting); if (setting.overrides && setting.overrides.length) { for (const subSetting of setting.overrides) { - const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher); + const subSettingMatches = new SettingMatches(searchString, subSetting, this.requireFullQueryMatch, this.valuesMatcher); let words = searchString.split(' '); const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); @@ -353,7 +357,7 @@ class SettingMatches { const ranges = from.get(word); if (ranges) { result.push(...ranges); - } else if (others.every(o => !o.has(word))) { + } else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) { return []; } } -- GitLab