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
This commit is contained in:
Sandeep Somavarapu committed 2017-10-23 18:11:14 +02:00
1 parent 347b04f667
commit bc2aeda370
5 files changed
+202 -170

No files matched your search

@@ -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((<ResourceEditorModel>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();
}
});
@@ -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));
@@ -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<TPromise<IPreferencesEditorModel<any>>>;
private lastOpenedSettingsInput: PreferencesEditorInput = null;
private _onDispose: Emitter<void> = new Emitter<void>();
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<TPromise<IPreferencesEditorModel<any>>>();
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<IModel> {
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<IPreferencesEditorModel<any>> {
let promise = this.defaultPreferencesEditorModels.get(uri);
if (promise) {
return promise;
}
if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) {
promise = TPromise.join<any>([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<SettingsEditorModel>(null);
}
private createDefaultSettingsEditorModel(defaultSettingsUri: URI): TPromise<DefaultSettingsEditorModel> {
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<string[]> {
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<IPosition> {
@@ -400,7 +411,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic
public dispose(): void {
this._onDispose.fire();
this.defaultPreferencesEditorModels.clear();
super.dispose();
}
}
@@ -69,15 +69,10 @@ export interface IFilterMetadata {
export interface IPreferencesEditorModel<T> {
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[];
@@ -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<string, ISetting>;
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 <ISetting>{
description: setting.description,
key: setting.key,
value: setting.value,
range: null,
valueRange: null,
overrides: []
};
}
return null;
}).filter(setting => !!setting);
return <ISettingsGroup>{
id: 'mostRelevant',
range: null,
title: nls.localize('mostRelevant', "Most Relevant"),
titleRange: null,
sections: [
{
settings
}
]
};
}
private parse() {
const configurations = Registry.as<IConfigurationRegistry>(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<string, ISetting>;
constructor(
private _uri: URI,
reference: IReference<ITextEditorModel>,
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<string, ISetting>();
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 <ISetting>{
description: setting.description,
key: setting.key,
value: setting.value,
range: null,
valueRange: null,
overrides: []
};
}
return null;
}).filter(setting => !!setting);
return <ISettingsGroup>{
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<any>, IDefaultPreferencesEditorModel {
export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel<any> {
private _content: string;
private _model: IModel;