From bc2aeda370382d58b6b034b8c4d98daa13f3c488 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 23 Oct 2017 18:11:14 +0200 Subject: [PATCH] Separete default settings model and default settings editor model so that the latter can reuse the former. Have a complete dipose cycle for all editor models --- .../preferences/browser/preferencesEditor.ts | 12 + .../browser/preferencesRenderers.ts | 1 - .../preferences/browser/preferencesService.ts | 88 +++--- .../parts/preferences/common/preferences.ts | 5 - .../preferences/common/preferencesModels.ts | 266 ++++++++++-------- 5 files changed, 202 insertions(+), 170 deletions(-) diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 33c7f01149b1..18fffe2091fb 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -606,6 +606,9 @@ class SideBySidePreferencesWidget extends Widget { } public clearInput(): void { + if (this.defaultPreferencesEditor) { + this.defaultPreferencesEditor.clearInput(); + } if (this.editablePreferencesEditor) { this.editablePreferencesEditor.clearInput(); } @@ -821,6 +824,14 @@ export class DefaultPreferencesEditor extends BaseTextEditor { .then(editorModel => this.getControl().setModel((editorModel).textEditorModel))); } + public clearInput(): void { + // Clear Model + this.getControl().setModel(null); + + // Pass to super + super.clearInput(); + } + public layout(dimension: Dimension) { this.getControl().layout(dimension); } @@ -910,6 +921,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { if (preferencesRenderer.associatedPreferencesModel) { preferencesRenderer.associatedPreferencesModel.dispose(); } + preferencesRenderer.preferencesModel.dispose(); preferencesRenderer.dispose(); } }); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index b0a40c12347b..15395240b208 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -77,7 +77,6 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend @IInstantiationService protected instantiationService: IInstantiationService ) { super(); - this._register(preferencesModel); 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)); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 5860143398db..a75a1792f79e 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -8,7 +8,6 @@ import * as network from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; -import { ResourceMap } from 'vs/base/common/map'; import * as labels from 'vs/base/common/labels'; import * as strings from 'vs/base/common/strings'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -27,7 +26,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; -import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel, DefaultSettingsModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor'; @@ -48,14 +47,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic _serviceBrand: any; - // TODO:@sandy merge these models into editor inputs by extending resource editor model - private defaultPreferencesEditorModels: ResourceMap>>; private lastOpenedSettingsInput: PreferencesEditorInput = null; private _onDispose: Emitter = new Emitter(); private _defaultSettingsUriCounter = 0; + private _defaultSettingsContentModel; private _defaultResourceSettingsUriCounter = 0; + private _defaultResourceSettingsContentModel; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -77,7 +76,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic @IModeService private modeService: IModeService ) { super(); - this.defaultPreferencesEditorModels = new ResourceMap>>(); this.editorGroupService.onEditorsChanged(() => { const activeEditorInput = this.editorService.getActiveEditorInput(); if (activeEditorInput instanceof PreferencesEditorInput) { @@ -113,47 +111,37 @@ export class PreferencesService extends Disposable implements IPreferencesServic } resolveModel(uri: URI): TPromise { - return this.createPreferencesEditorModel(uri) - .then(preferencesEditorModel => { - if (preferencesEditorModel instanceof DefaultSettingsEditorModel || preferencesEditorModel instanceof DefaultKeybindingsEditorModel) { - return preferencesEditorModel.model; - } else { - // This provider only handles the Default model types - return null; - } - }); + if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { + return this.extensionService.onReady() + .then(() => { + const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + const settingsModel = this.getDefaultSettingsModel(scope); + const mode = this.modeService.getOrCreateMode('json'); + const model = this._register(this.modelService.createModel(settingsModel.content, mode, uri)); + return model; + }); + } + + if (this.defaultKeybindingsResource.toString() === uri.toString()) { + return this.extensionService.onReady() + .then(() => this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri).model); + } + + return TPromise.as(null); } createPreferencesEditorModel(uri: URI): TPromise> { - let promise = this.defaultPreferencesEditorModels.get(uri); - if (promise) { - return promise; - } - if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { - promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) - .then(result => { - const mostCommonSettings = result[1]; - const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; - const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings, scope); - model.onDispose(() => this.defaultPreferencesEditorModels.delete(uri)); - return model; - }); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; + return this.createDefaultSettingsEditorModel(uri); } if (this.defaultKeybindingsResource.toString() === uri.toString()) { const model = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); - promise = TPromise.wrap(model); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; + return TPromise.wrap(model); } if (this.workspaceConfigSettingsResource.toString() === uri.toString()) { - promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); } if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { @@ -304,6 +292,29 @@ export class PreferencesService extends Disposable implements IPreferencesServic return TPromise.wrap(null); } + private createDefaultSettingsEditorModel(defaultSettingsUri: URI): TPromise { + return this.textModelResolverService.createModelReference(defaultSettingsUri) + .then(reference => { + const scope = this.isDefaultSettingsResource(defaultSettingsUri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettingsModel(scope).settingsGroups); + }); + } + + private getDefaultSettingsModel(scope: ConfigurationScope): DefaultSettingsModel { + switch (scope) { + case ConfigurationScope.WINDOW: + if (!this._defaultSettingsContentModel) { + this._defaultSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultSettingsContentModel; + case ConfigurationScope.RESOURCE: + if (!this._defaultResourceSettingsContentModel) { + this._defaultResourceSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultResourceSettingsContentModel; + } + } + private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI { switch (configurationTarget) { case ConfigurationTarget.USER: @@ -342,8 +353,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private fetchMostCommonlyUsedSettings(): TPromise { - return TPromise.wrap([ + private getMostCommonlyUsedSettings(): string[] { + return [ 'files.autoSave', 'editor.fontSize', 'editor.fontFamily', @@ -355,7 +366,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic 'editor.wordWrap', 'files.exclude', 'files.associations' - ]); + ]; } private getPosition(language: string, codeEditor: ICommonCodeEditor): TPromise { @@ -400,7 +411,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic public dispose(): void { this._onDispose.fire(); - this.defaultPreferencesEditorModels.clear(); super.dispose(); } } diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 5d9bda6518da..05c4ff4ffe15 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -69,15 +69,10 @@ export interface IFilterMetadata { export interface IPreferencesEditorModel { uri: URI; - content: string; getPreference(key: string): T; dispose(): void; } -export interface IDefaultPreferencesEditorModel { - model: IModel; -} - export type IGroupFilter = (group: ISettingsGroup) => boolean; export type ISettingFilter = (setting: ISetting) => IRange[]; diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index 6fe66fb6d666..5bc906678c82 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -5,7 +5,6 @@ import * as nls from 'vs/nls'; import { assign } from 'vs/base/common/objects'; -import * as arrays from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; import URI from 'vs/base/common/uri'; import { IReference } from 'vs/base/common/lifecycle'; @@ -15,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, IDefaultPreferencesEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingFilter } from 'vs/workbench/parts/preferences/common/preferences'; +import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingFilter } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -476,36 +475,16 @@ export class WorkspaceConfigModel extends SettingsEditorModel implements ISettin } } -export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel, IDefaultPreferencesEditorModel { - - public static MOST_RELEVANT_SECTION_LENGTH = 100; - public static MOST_RELEVANT_START_LINE = 4; - public static MOST_RELEVANT_END_LINE = DefaultSettingsEditorModel.MOST_RELEVANT_SECTION_LENGTH - 1; - private static MOST_RELEVANT_CONTENT_LENGTH = DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE - DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE + 1; +export class DefaultSettingsModel { private _allSettingsGroups: ISettingsGroup[]; private _content: string; - private _model: IModel; private _settingsByName: Map; constructor( - private _uri: URI, private _mostCommonlyUsedSettingsKeys: string[], readonly configurationScope: ConfigurationScope, - @IModeService private modeService: IModeService, - @IModelService private modelService: IModelService) { - super(); - - const mode = this.modeService.getOrCreateMode('json'); - this._model = this._register(this.modelService.createModel(this.content, mode, this._uri)); - } - - public get model(): IModel { - return this._model; - } - - public get uri(): URI { - return this._uri; + ) { } public get content(): string { @@ -522,109 +501,13 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return this._allSettingsGroups; } - public get mostCommonlyUsedSettings(): ISettingsGroup { - return this.settingsGroups[0]; - } - - public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult { - if (mostRelevantSettings) { - const group = this.getMostRelevantSettings(mostRelevantSettings); - const builder = new SettingsContentBuilder(DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE - 1); - builder.pushGroup(group, false); - - const lines = builder.getTrimmedLines(DefaultSettingsEditorModel.MOST_RELEVANT_CONTENT_LENGTH); - if (!lines.length) { - lines.push(''); - } - - const mostRelevantContent = lines.join('\n'); - const settingsTextEndLine = DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE + lines.length - 1; - this.model.applyEdits([ - { - text: mostRelevantContent, - forceMoveMarkers: false, - range: new Range(DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE, 0, settingsTextEndLine, 0), - identifier: { major: 1, minor: 0 } - } - ]); - - if (settingsTextEndLine < DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE) { - this.model.applyEdits([ - { - text: strings.repeat('\n', DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE - settingsTextEndLine), - forceMoveMarkers: false, - range: new Range(settingsTextEndLine + 1, 0, DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE + 1, 0), - identifier: { major: 1, minor: 0 } - } - ]); - } - - return { - allGroups: this._allSettingsGroups, - filteredGroups: group.sections[0].settings.length ? [group] : [], - matches: [], - query: filter - }; - } else { - // local - return this.doFilterSettings(filter, groupFilter, settingFilter); - } - } - - public findValueMatches(filter: string, setting: ISetting): IRange[] { - return []; - } - - public getPreference(key: string): ISetting { - for (const group of this.settingsGroups) { - for (const section of group.sections) { - for (const setting of section.settings) { - if (setting.key === key) { - return setting; - } - } - } - } - return null; - } - - private getMostRelevantSettings(rankedSettingNames: string[]): ISettingsGroup { - const settings = rankedSettingNames.map(key => { - const setting = this._settingsByName.get(key); - if (setting) { - return { - description: setting.description, - key: setting.key, - value: setting.value, - range: null, - valueRange: null, - overrides: [] - }; - } - return null; - }).filter(setting => !!setting); - - return { - id: 'mostRelevant', - range: null, - title: nls.localize('mostRelevant', "Most Relevant"), - titleRange: null, - sections: [ - { - settings - } - ] - }; - } - private parse() { const configurations = Registry.as(Extensions.Configuration).getConfigurations().slice(); const settingsGroups = this.removeEmptySettingsGroups(configurations.sort(this.compareConfigurationNodes).reduce((result, config, index, array) => this.parseConfig(config, result, array), [])); this.initAllSettingsMap(settingsGroups); const mostCommonlyUsed = this.getMostCommonlyUsedSettings(settingsGroups); - const mostRelevant = this.getMostRelevantSettings([]); - this._allSettingsGroups = [mostRelevant, mostCommonlyUsed, ...settingsGroups]; - this._content = this.toContent(mostRelevant, mostCommonlyUsed, settingsGroups); + this._allSettingsGroups = [mostCommonlyUsed, ...settingsGroups]; + this._content = this.toContent(mostCommonlyUsed, settingsGroups); } private initAllSettingsMap(allSettingsGroups: ISettingsGroup[]): void { @@ -753,14 +636,16 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return c1.order - c2.order; } - private toContent(mostRelevant: ISettingsGroup, mostCommonlyUsed: ISettingsGroup, settingsGroups: ISettingsGroup[]): string { + private toContent(mostCommonlyUsed: ISettingsGroup, settingsGroups: ISettingsGroup[]): string { const builder = new SettingsContentBuilder(); builder.pushLine('['); + /* builder.pushLine('{'); const mostRelevantSectionContent = arrays.fill(DefaultSettingsEditorModel.MOST_RELEVANT_SECTION_LENGTH - 3, () => ''); builder.pushGroup(mostRelevant, false, mostRelevantSectionContent); // Empty at this point builder.pushLine('}'); builder.pushLine(','); + */ builder.pushGroups([mostCommonlyUsed]); builder.pushLine(','); builder.pushGroups(settingsGroups); @@ -768,7 +653,138 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return builder.getContent(); } - public dispose(): void { +} + +export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { + + public static MOST_RELEVANT_SECTION_LENGTH = 100; + public static MOST_RELEVANT_START_LINE = 4; + public static MOST_RELEVANT_END_LINE = DefaultSettingsEditorModel.MOST_RELEVANT_SECTION_LENGTH - 1; + public static MOST_RELEVANT_CONTENT_LENGTH = DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE - DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE + 1; + + private model: IModel; + private _settingsByName: Map; + + constructor( + private _uri: URI, + reference: IReference, + readonly configurationScope: ConfigurationScope, + readonly settingsGroups: ISettingsGroup[] + ) { + super(); + this.model = reference.object.textEditorModel; + this._register(this.onDispose(() => reference.dispose())); + + this.initAllSettingsMap(); + } + + public get uri(): URI { + return this._uri; + } + + public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult { + if (mostRelevantSettings) { + const group = this.getMostRelevantSettings(mostRelevantSettings); + const builder = new SettingsContentBuilder(DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE - 1); + builder.pushGroup(group, false); + + const lines = builder.getTrimmedLines(DefaultSettingsEditorModel.MOST_RELEVANT_CONTENT_LENGTH); + if (!lines.length) { + lines.push(''); + } + + const mostRelevantContent = lines.join('\n'); + const settingsTextEndLine = DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE + lines.length - 1; + this.model.applyEdits([ + { + text: mostRelevantContent, + forceMoveMarkers: false, + range: new Range(DefaultSettingsEditorModel.MOST_RELEVANT_START_LINE, 0, settingsTextEndLine, 0), + identifier: { major: 1, minor: 0 } + } + ]); + + if (settingsTextEndLine < DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE) { + this.model.applyEdits([ + { + text: strings.repeat('\n', DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE - settingsTextEndLine), + forceMoveMarkers: false, + range: new Range(settingsTextEndLine + 1, 0, DefaultSettingsEditorModel.MOST_RELEVANT_END_LINE + 1, 0), + identifier: { major: 1, minor: 0 } + } + ]); + } + + return { + allGroups: this.settingsGroups, + filteredGroups: group.sections[0].settings.length ? [group] : [], + matches: [], + query: filter + }; + } else { + // local + return this.doFilterSettings(filter, groupFilter, settingFilter); + } + } + + public findValueMatches(filter: string, setting: ISetting): IRange[] { + return []; + } + + public getPreference(key: string): ISetting { + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + if (setting.key === key) { + return setting; + } + } + } + } + return null; + } + + private initAllSettingsMap(): void { + this._settingsByName = new Map(); + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + this._settingsByName.set(setting.key, setting); + } + } + } + } + + private getMostRelevantSettings(rankedSettingNames: string[]): ISettingsGroup { + const settings = rankedSettingNames.map(key => { + const setting = this._settingsByName.get(key); + if (setting) { + return { + description: setting.description, + key: setting.key, + value: setting.value, + range: null, + valueRange: null, + overrides: [] + }; + } + return null; + }).filter(setting => !!setting); + + return { + id: 'mostRelevant', + range: null, + title: nls.localize('mostRelevant', "Most Relevant"), + titleRange: null, + sections: [ + { + settings + } + ] + }; + } + + dispose(): void { super.dispose(); } } @@ -921,7 +937,7 @@ export function defaultKeybindingsContents(keybindingService: IKeybindingService return defaultsHeader + '\n' + keybindingService.getDefaultKeybindingsContent(); } -export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel, IDefaultPreferencesEditorModel { +export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel { private _content: string; private _model: IModel;