diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index a23e64865b0120cfdb7a9b5731ee7e7ee6c7b481..73bdf48cc5984dbe64b8d8167f1716f408064d1c 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -6,6 +6,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; +import * as strings from 'vs/base/common/strings'; import { onUnexpectedError, isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors'; import * as DOM from 'vs/base/browser/dom'; import { Delayer, ThrottledDelayer } from 'vs/base/common/async'; @@ -25,7 +26,7 @@ import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IPreferencesService, ISettingsGroup, ISetting, IFilterResult, IPreferencesSearchService, - CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, IFilterMetadata, ISearchProvider, ISearchResult, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING + CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, ISearchProvider, ISearchResult, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -255,8 +256,7 @@ export class PreferencesEditor extends BaseEditor { if (result) { this.delayedFilterLogging.trigger(() => this.reportFilteringUsed( query, - result.defaultSettingsGroupCounts, - result.metadata)); + this.preferencesRenderers.lastFilterResult)); } }); } @@ -311,8 +311,26 @@ export class PreferencesEditor extends BaseEditor { } } - private reportFilteringUsed(filter: string, counts: IStringDictionary, metadata?: IStringDictionary): void { + private _countById(settingsGroups: ISettingsGroup[]): IStringDictionary { + const result = {}; + + for (const group of settingsGroups) { + let i = 0; + for (const section of group.sections) { + i += section.settings.length; + } + + result[group.id] = i; + } + + return result; + } + + private reportFilteringUsed(filter: string, filterResult: IFilterResult): void { if (filter && filter !== this._lastReportedFilter) { + const metadata = filterResult && filterResult.metadata; + const counts = filterResult && this._countById(filterResult.filteredGroups); + let durations: any; if (metadata) { durations = Object.create(null); @@ -355,11 +373,6 @@ class SettingsNavigator extends ArrayNavigator { } } -interface IFilterOrSearchResult { - defaultSettingsGroupCounts: IStringDictionary; - metadata: IStringDictionary; -} - interface IPreferencesCount { target?: SettingsTarget; count: number; @@ -380,7 +393,7 @@ class PreferencesRenderersController extends Disposable { private _currentLocalSearchProvider: ISearchProvider; private _currentRemoteSearchProvider: ISearchProvider; private _lastQuery: string; - private _lastFilterResult: IFilterOrSearchResult; + private _lastFilterResult: IFilterResult; private _onDidFilterResultsCountChange: Emitter = this._register(new Emitter()); public onDidFilterResultsCountChange: Event = this._onDidFilterResultsCountChange.event; @@ -394,7 +407,7 @@ class PreferencesRenderersController extends Disposable { super(); } - get lastFilterResult(): IFilterOrSearchResult { + get lastFilterResult(): IFilterResult { return this._lastFilterResult; } @@ -413,7 +426,10 @@ class PreferencesRenderersController extends Disposable { this._defaultPreferencesRendererDisposables = dispose(this._defaultPreferencesRendererDisposables); if (this._defaultPreferencesRenderer) { - this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables); + this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => { + this._editablePreferencesRenderer.updatePreference(key, value, source); + this._updatePreference(key, value, source); + }, this, this._defaultPreferencesRendererDisposables); this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables); this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables); } @@ -427,6 +443,8 @@ class PreferencesRenderersController extends Disposable { if (this._editablePreferencesRenderer) { (this._editablePreferencesRenderer.preferencesModel) .onDidChangeGroups(this._onEditableContentDidChange, this, this._editablePreferencesRendererDisposables); + + this._editablePreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, true), this, this._defaultPreferencesRendererDisposables); } } } @@ -474,25 +492,21 @@ class PreferencesRenderersController extends Disposable { private filterOrSearchPreferences(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number, editableContentOnly?: boolean): TPromise { this._lastQuery = query; - const filterPs = []; + const filterPs: TPromise[] = [this._filterOrSearchPreferences(query, this.editablePreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder)]; if (!editableContentOnly) { filterPs.push( this._filterOrSearchPreferences(query, this.defaultPreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder)); } - filterPs.push(this._filterOrSearchPreferences(query, this.editablePreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder), - this.searchAllSettingsTargets(query, searchProvider, groupId, groupLabel, groupOrder)); + filterPs.push(this.searchAllSettingsTargets(query, searchProvider, groupId, groupLabel, groupOrder)); return TPromise.join(filterPs).then(results => { - const [defaultFilterResult, editableFilterResult] = results; + const [editableFilterResult, defaultFilterResult] = results; this.consolidateAndUpdate(defaultFilterResult, editableFilterResult); - const result = { - metadata: defaultFilterResult && defaultFilterResult.metadata, - defaultSettingsGroupCounts: defaultFilterResult && this._countById(defaultFilterResult.filteredGroups) - }; - - this._lastFilterResult = result; + if (defaultFilterResult) { + this._lastFilterResult = defaultFilterResult; + } }); } @@ -598,13 +612,14 @@ class PreferencesRenderersController extends Disposable { } else { /* __GDPR__ "defaultSettings.searchError" : { - "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "filter": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ const message = getErrorMessage(err).trim(); if (message) { // Empty message = any generic network error - this.telemetryService.publicLog('defaultSettings.searchError', { message }); + this.telemetryService.publicLog('defaultSettings.searchError', { message, filter }); } return null; } @@ -668,10 +683,58 @@ class PreferencesRenderersController extends Disposable { } } - private _updatePreference(key: string, value: any, source: ISetting, preferencesRenderer: IPreferencesRenderer): void { - if (preferencesRenderer) { - preferencesRenderer.updatePreference(key, value, source); + private _updatePreference(key: string, value: any, source: ISetting, fromEditableSettings?: boolean): void { + const data = { + userConfigurationKeys: [key] + }; + + if (this.lastFilterResult) { + data['query'] = this.lastFilterResult.query; + data['editableSide'] = !!fromEditableSettings; + + const nlpMetadata = this.lastFilterResult.metadata && this.lastFilterResult.metadata['nlpResult']; + if (nlpMetadata) { + const sortedKeys = Object.keys(nlpMetadata.scoredResults).sort((a, b) => nlpMetadata.scoredResults[b].score - nlpMetadata.scoredResults[a].score); + const suffix = '##' + key; + data['nlpIndex'] = arrays.firstIndex(sortedKeys, key => strings.endsWith(key, suffix)); + } + + const settingLocation = this._findSetting(this.lastFilterResult, key); + if (settingLocation) { + data['groupId'] = this.lastFilterResult.filteredGroups[settingLocation.groupIdx].id; + data['displayIdx'] = settingLocation.overallSettingIdx; + } } + + /* __GDPR__ + "defaultSettingsActions.copySetting" : { + "userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "query" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "nlpIndex" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "groupId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "displayIdx" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "editableSide" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('defaultSettingsActions.copySetting', data); + } + + private _findSetting(filterResult: IFilterResult, key: string): { groupIdx: number, settingIdx: number, overallSettingIdx: number } { + let overallSettingIdx = 0; + + for (let groupIdx = 0; groupIdx < filterResult.filteredGroups.length; groupIdx++) { + const group = filterResult.filteredGroups[groupIdx]; + for (let settingIdx = 0; settingIdx < group.sections[0].settings.length; settingIdx++) { + const setting = group.sections[0].settings[settingIdx]; + if (key === setting.key) { + return { groupIdx, settingIdx, overallSettingIdx }; + } + + overallSettingIdx++; + } + } + + return null; } private _consolidateSettings(editableSettingsGroups: ISettingsGroup[], defaultSettingsGroups: ISettingsGroup[]): ISetting[] { @@ -691,21 +754,6 @@ class PreferencesRenderersController extends Disposable { return settings; } - private _countById(settingsGroups: ISettingsGroup[]): IStringDictionary { - const result = {}; - - for (const group of settingsGroups) { - let i = 0; - for (const section of group.sections) { - i += section.settings.length; - } - - result[group.id] = i; - } - - return result; - } - public dispose(): void { dispose(this._defaultPreferencesRendererDisposables); dispose(this._editablePreferencesRendererDisposables); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index c5619f82ea5437d19cce2943175a1f5ad5db6e13..85cb33132aa9e390c5be23fa0604848723521373 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -71,11 +71,13 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private _onClearFocusPreference: Emitter = new Emitter(); public readonly onClearFocusPreference: Event = this._onClearFocusPreference.event; + private _onUpdatePreference: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>(); + public readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event; + private filterResult: IFilterResult; constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel, @IPreferencesService protected preferencesService: IPreferencesService, - @ITelemetryService private telemetryService: ITelemetryService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService protected instantiationService: IInstantiationService ) { @@ -83,7 +85,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference)); this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter)); - this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this.updatePreference(key, value, source, true))); + this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this._updatePreference(key, value, source))); this._register(this.editor.getModel().onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged()))); this.createHeader(); @@ -109,34 +111,12 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend } } - public updatePreference(key: string, value: any, source: IIndexedSetting, fromEditableSettings?: boolean): void { - const data = { - userConfigurationKeys: [key] - }; - - if (this.filterResult) { - data['query'] = this.filterResult.query; - data['groupId'] = source.groupId; - data['editableSide'] = !!fromEditableSettings; - - const nlpMetadata = this.filterResult.metadata && this.filterResult.metadata['nlpResult']; - if (nlpMetadata) { - const sortedKeys = Object.keys(nlpMetadata.scoredResults).sort((a, b) => nlpMetadata.scoredResults[b].score - nlpMetadata.scoredResults[a].score); - const suffix = '##' + key; - data['nlpIndex'] = arrays.firstIndex(sortedKeys, key => strings.endsWith(key, suffix)); - } - } + private _updatePreference(key: string, value: any, source: IIndexedSetting): void { + this._onUpdatePreference.fire({ key, value, source }); + this.updatePreference(key, value, source); + } - /* __GDPR__ - "defaultSettingsActions.copySetting" : { - "userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "query" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "nlpIndex" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "groupId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "editableSide" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('defaultSettingsActions.copySetting', data); + public updatePreference(key: string, value: any, source: IIndexedSetting): void { const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null; const resource = this.preferencesModel.uri; this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget) @@ -213,7 +193,7 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, preferencesService, telemetryService, configurationService, instantiationService); + super(editor, preferencesModel, preferencesService, configurationService, instantiationService); this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel)); this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel)); } @@ -244,7 +224,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, preferencesService, telemetryService, configurationService, instantiationService); + super(editor, preferencesModel, preferencesService, configurationService, instantiationService); this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel)); }