#75079 Move preferences to browser
Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 194 B |
Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 194 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -16,7 +16,6 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
|||
import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
@ -30,10 +29,9 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
|
|||
import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor';
|
||||
import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL, OpenRemoteSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
|
||||
import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor';
|
||||
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution';
|
||||
import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch';
|
||||
import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/electron-browser/settingsEditor2';
|
||||
import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/browser/settingsEditor2';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
|
||||
|
@ -42,8 +40,6 @@ import { ILabelService } from 'vs/platform/label/common/label';
|
|||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
registerSingleton(IPreferencesSearchService, PreferencesSearchService, true);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
PreferencesEditor,
|
||||
|
@ -385,8 +381,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
|
|||
id: OpenGlobalKeybindingsAction.ID,
|
||||
title: OpenGlobalKeybindingsAction.LABEL,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
|
||||
}
|
||||
},
|
||||
when: ResourceContextKey.Resource.isEqualTo(URI.file(environmentService.appKeybindingsPath).toString()),
|
||||
|
@ -401,8 +397,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
|
|||
id: commandId,
|
||||
title: OpenSettings2Action.LABEL,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
|
||||
}
|
||||
},
|
||||
when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()),
|
||||
|
@ -442,8 +438,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
|
|||
id: commandId,
|
||||
title: OpenSettings2Action.LABEL,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
|
||||
}
|
||||
},
|
||||
when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')),
|
||||
|
@ -470,8 +466,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
|
|||
id: commandId,
|
||||
title: OpenSettings2Action.LABEL,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
|
||||
}
|
||||
},
|
||||
when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())),
|
||||
|
@ -537,8 +533,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
|||
id: OpenGlobalKeybindingsFileAction.ID,
|
||||
title: OpenGlobalKeybindingsFileAction.LABEL,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg`))
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg`))
|
||||
}
|
||||
},
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR),
|
||||
|
@ -775,8 +771,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
|||
id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON,
|
||||
title: nls.localize('openSettingsJson', "Open Settings (JSON)"),
|
||||
iconLocation: {
|
||||
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg')),
|
||||
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg'))
|
||||
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg')),
|
||||
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json.svg'))
|
||||
}
|
||||
},
|
||||
group: 'navigation',
|
|
@ -0,0 +1,219 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ISettingsEditorModel, ISetting, ISettingsGroup, ISearchResult, IGroupFilter } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IPreferencesSearchService, ISearchProvider } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export interface IEndpointDetails {
|
||||
urlBase?: string;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export class PreferencesSearchService extends Disposable implements IPreferencesSearchService {
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService protected readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getLocalSearchProvider(filter: string): LocalSearchProvider {
|
||||
return this.instantiationService.createInstance(LocalSearchProvider, filter);
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalSearchProvider implements ISearchProvider {
|
||||
static readonly EXACT_MATCH_SCORE = 10000;
|
||||
static readonly START_SCORE = 1000;
|
||||
|
||||
constructor(private _filter: string) {
|
||||
// Remove " and : which are likely to be copypasted as part of a setting name.
|
||||
// Leave other special characters which the user might want to search for.
|
||||
this._filter = this._filter
|
||||
.replace(/[":]/g, ' ')
|
||||
.replace(/ /g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise<ISearchResult | null> {
|
||||
if (!this._filter) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
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 score = this._filter === setting.key ?
|
||||
LocalSearchProvider.EXACT_MATCH_SCORE :
|
||||
orderedScore--;
|
||||
|
||||
return matches && matches.length ?
|
||||
{
|
||||
matches,
|
||||
score
|
||||
} :
|
||||
null;
|
||||
};
|
||||
|
||||
const filterMatches = preferencesModel.filterSettings(this._filter, this.getGroupFilter(this._filter), settingMatcher);
|
||||
if (filterMatches[0] && filterMatches[0].score === LocalSearchProvider.EXACT_MATCH_SCORE) {
|
||||
return Promise.resolve({
|
||||
filterMatches: filterMatches.slice(0, 1),
|
||||
exactMatch: true
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
filterMatches
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getGroupFilter(filter: string): IGroupFilter {
|
||||
const regex = strings.createRegExp(filter, false, { global: true });
|
||||
return (group: ISettingsGroup) => {
|
||||
return regex.test(group.title);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingMatches {
|
||||
|
||||
private readonly descriptionMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly keyMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
|
||||
readonly matches: IRange[];
|
||||
|
||||
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}_`);
|
||||
}
|
||||
|
||||
private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
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.requireFullQueryMatch, this.searchDescription, this.valuesMatcher);
|
||||
const 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]);
|
||||
const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]);
|
||||
const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
|
||||
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges);
|
||||
result.push(...subSettingMatches.matches);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
const schema: IJSONSchema = registry[setting.key];
|
||||
|
||||
const words = searchString.split(' ');
|
||||
const settingKeyAsWords: string = setting.key.split('.').join(' ');
|
||||
|
||||
for (const word of words) {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords);
|
||||
if (keyMatches) {
|
||||
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
|
||||
}
|
||||
|
||||
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
|
||||
if (valueMatches) {
|
||||
this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match)));
|
||||
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
|
||||
this.valueMatchingWords.set(word, []);
|
||||
}
|
||||
}
|
||||
|
||||
const descriptionRanges: IRange[] = [];
|
||||
if (this.searchDescription) {
|
||||
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
|
||||
const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || [];
|
||||
descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
|
||||
}
|
||||
if (descriptionRanges.length === 0) {
|
||||
descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords]));
|
||||
}
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key);
|
||||
const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]);
|
||||
|
||||
let valueRanges: IRange[] = [];
|
||||
if (setting.value && typeof setting.value === 'string') {
|
||||
const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value);
|
||||
valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]);
|
||||
} else {
|
||||
valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : [];
|
||||
}
|
||||
|
||||
return [...descriptionRanges, ...keyRanges, ...valueRanges];
|
||||
}
|
||||
|
||||
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
|
||||
const result: IRange[] = [];
|
||||
for (const word of words) {
|
||||
const ranges = from.get(word);
|
||||
if (ranges) {
|
||||
result.push(...ranges);
|
||||
} else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private toKeyRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.keyRange.startLineNumber,
|
||||
startColumn: setting.keyRange.startColumn + match.start,
|
||||
endLineNumber: setting.keyRange.startLineNumber,
|
||||
endColumn: setting.keyRange.startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange {
|
||||
return {
|
||||
startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber,
|
||||
startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start,
|
||||
endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber,
|
||||
endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toValueRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.valueRange.startLineNumber,
|
||||
startColumn: setting.valueRange.startColumn + match.start + 1,
|
||||
endLineNumber: setting.valueRange.startLineNumber,
|
||||
endColumn: setting.valueRange.startColumn + match.end + 1
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,18 +4,12 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { distinct, top } from 'vs/base/common/arrays';
|
||||
import { top } from 'vs/base/common/arrays';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IRequestService } from 'vs/platform/request/node/request';
|
||||
import { asJson } from 'vs/base/node/request';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
|
@ -24,25 +18,26 @@ import { canceled } from 'vs/base/common/errors';
|
|||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { PreferencesSearchService as LocalPreferencesSearchService, SettingMatches } from 'vs/workbench/contrib/preferences/browser/preferencesSearch';
|
||||
|
||||
export interface IEndpointDetails {
|
||||
urlBase?: string;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export class PreferencesSearchService extends Disposable implements IPreferencesSearchService {
|
||||
export class PreferencesSearchService extends LocalPreferencesSearchService implements IPreferencesSearchService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private _installedExtensions: Promise<ILocalExtension[]>;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
super();
|
||||
super(instantiationService);
|
||||
|
||||
// This request goes to the shared process but results won't change during a window's lifetime, so cache the results.
|
||||
this._installedExtensions = this.extensionManagementService.getInstalled(ExtensionType.User).then(exts => {
|
||||
|
@ -86,10 +81,6 @@ export class PreferencesSearchService extends Disposable implements IPreferences
|
|||
|
||||
return this.remoteSearchAllowed ? this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions) : undefined;
|
||||
}
|
||||
|
||||
getLocalSearchProvider(filter: string): LocalSearchProvider {
|
||||
return this.instantiationService.createInstance(LocalSearchProvider, filter);
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalSearchProvider implements ISearchProvider {
|
||||
|
@ -437,129 +428,4 @@ function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetti
|
|||
extensionName: remoteSetting.extensionName,
|
||||
extensionPublisher: remoteSetting.extensionPublisher
|
||||
};
|
||||
}
|
||||
|
||||
class SettingMatches {
|
||||
|
||||
private readonly descriptionMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly keyMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
|
||||
readonly matches: IRange[];
|
||||
|
||||
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}_`);
|
||||
}
|
||||
|
||||
private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
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.requireFullQueryMatch, this.searchDescription, this.valuesMatcher);
|
||||
const 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]);
|
||||
const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]);
|
||||
const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
|
||||
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges);
|
||||
result.push(...subSettingMatches.matches);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
const schema: IJSONSchema = registry[setting.key];
|
||||
|
||||
const words = searchString.split(' ');
|
||||
const settingKeyAsWords: string = setting.key.split('.').join(' ');
|
||||
|
||||
for (const word of words) {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords);
|
||||
if (keyMatches) {
|
||||
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
|
||||
}
|
||||
|
||||
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
|
||||
if (valueMatches) {
|
||||
this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match)));
|
||||
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
|
||||
this.valueMatchingWords.set(word, []);
|
||||
}
|
||||
}
|
||||
|
||||
const descriptionRanges: IRange[] = [];
|
||||
if (this.searchDescription) {
|
||||
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
|
||||
const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || [];
|
||||
descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
|
||||
}
|
||||
if (descriptionRanges.length === 0) {
|
||||
descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords]));
|
||||
}
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key);
|
||||
const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]);
|
||||
|
||||
let valueRanges: IRange[] = [];
|
||||
if (setting.value && typeof setting.value === 'string') {
|
||||
const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value);
|
||||
valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]);
|
||||
} else {
|
||||
valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : [];
|
||||
}
|
||||
|
||||
return [...descriptionRanges, ...keyRanges, ...valueRanges];
|
||||
}
|
||||
|
||||
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
|
||||
const result: IRange[] = [];
|
||||
for (const word of words) {
|
||||
const ranges = from.get(word);
|
||||
if (ranges) {
|
||||
result.push(...ranges);
|
||||
} else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private toKeyRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.keyRange.startLineNumber,
|
||||
startColumn: setting.keyRange.startColumn + match.start,
|
||||
endLineNumber: setting.keyRange.startLineNumber,
|
||||
endColumn: setting.keyRange.startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange {
|
||||
return {
|
||||
startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber,
|
||||
startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start,
|
||||
endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber,
|
||||
endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toValueRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.valueRange.startLineNumber,
|
||||
startColumn: setting.valueRange.startColumn + match.start + 1,
|
||||
endLineNumber: setting.valueRange.startLineNumber,
|
||||
endColumn: setting.valueRange.startColumn + match.end + 1
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -191,8 +191,11 @@ import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution';
|
|||
import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
|
||||
|
||||
// Preferences
|
||||
import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution';
|
||||
import 'vs/workbench/contrib/preferences/browser/preferences.contribution';
|
||||
import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution';
|
||||
import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch';
|
||||
registerSingleton(IPreferencesSearchService, PreferencesSearchService, true);
|
||||
|
||||
// Logs
|
||||
import 'vs/workbench/contrib/logs/common/logs.contribution';
|
||||
|
|
|
@ -194,8 +194,11 @@ import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution';
|
|||
// import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
|
||||
|
||||
// Preferences
|
||||
// import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution';
|
||||
import 'vs/workbench/contrib/preferences/browser/preferences.contribution';
|
||||
import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution';
|
||||
import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/browser/preferencesSearch';
|
||||
registerSingleton(IPreferencesSearchService, PreferencesSearchService, true);
|
||||
|
||||
// Logs
|
||||
import 'vs/workbench/contrib/logs/common/logs.contribution';
|
||||
|
|