diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index b10f56273b42a4026cbcf138a30cd79201e1f890..e900dfd9d1b22bd8af3b4626b4173710af4a360b 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -17,7 +17,7 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, ISettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferences'; -import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { SettingsEditorModel, DefaultSettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView'; import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget, DefaultSettingsHeaderWidget, FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; @@ -1221,11 +1221,11 @@ class WorkspaceConfigurationRenderer extends Disposable { } public render(): void { - if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.workspaceSettingsEditorModel instanceof WorkspaceConfigurationEditorModel) { this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, [])); const ranges: IRange[] = []; - for (const settingsGroup of this.workspaceSettingsEditorModel.settingsGroups) { + for (const settingsGroup of this.workspaceSettingsEditorModel.configurationGroups) { for (const section of settingsGroup.sections) { for (const setting of section.settings) { if (setting.key !== 'settings') { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index b7860ec16de86b96310408dbb64e2962b2727338..17fbf389edb9f1b76f79a4edac0c938ee61536e3 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -26,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, DefaultSettingsModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettingsModel, WorkspaceConfigurationEditorModel } 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'; @@ -96,7 +96,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic } readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' }); - private readonly workspaceConfigSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'settings', path: '/workspaceSettings.json' }); get userSettingsResource(): URI { return this.getEditableSettingsURI(ConfigurationTarget.USER); @@ -137,10 +136,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createDefaultSettingsEditorModel(uri); } - if (this.workspaceConfigSettingsResource.toString() === uri.toString()) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); - } - if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri); } @@ -279,9 +274,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): TPromise { const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); if (settingsUri) { - if (settingsUri.toString() === this.workspaceConfigSettingsResource.toString()) { - return TPromise.join([this.textModelResolverService.createModelReference(settingsUri), this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration)]) - .then(([reference, workspaceConfigReference]) => this.instantiationService.createInstance(WorkspaceConfigModel, reference, workspaceConfigReference, configurationTarget, this._onDispose.event)); + const workspace = this.contextService.getWorkspace(); + if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { + return this.textModelResolverService.createModelReference(settingsUri) + .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); } return this.textModelResolverService.createModelReference(settingsUri) .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index be2916808ee642582c5eb84d6e3780e96303dc8f..e75d3ec9f634f3df7e2fd80d1e07458a989eb507 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -126,9 +126,7 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti super(); this.settingsModel = reference.object.textEditorModel; this._register(this.onDispose(() => reference.dispose())); - this._register(this.settingsModel.onDidChangeContent(() => { - this._settingsGroups = null; - })); + this._register(this.settingsModel.onDidChangeContent(() => this._settingsGroups = null)); this.queue = new Queue(); } @@ -163,176 +161,204 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti return this.queue.queue(() => this.doSave()); } + protected isSettingsProperty(property: string, previousParents: string[]): boolean { + return previousParents.length === 0; // Settings is root + } + protected doSave(): TPromise { return this.textFileService.save(this.uri); } - private parse() { - const model = this.settingsModel; - const settings: ISetting[] = []; - let overrideSetting: ISetting = null; - - let currentProperty: string = null; - let currentParent: any = []; - let previousParents: any[] = []; - let range = { - startLineNumber: 0, - startColumn: 0, - endLineNumber: 0, - endColumn: 0 - }; + protected parse(): void { + this._settingsGroups = parse(this.settingsModel, (property: string, previousParents: string[]): boolean => this.isSettingsProperty(property, previousParents)); + } +} - function onValue(value: any, offset: number, length: number) { - if (Array.isArray(currentParent)) { - (currentParent).push(value); - } else if (currentProperty) { - currentParent[currentProperty] = value; +function parse(model: IModel, isSettingsProperty: (currentProperty: string, previousParents: string[]) => boolean): ISettingsGroup[] { + const settings: ISetting[] = []; + let overrideSetting: ISetting = null; + + let currentProperty: string = null; + let currentParent: any = []; + let previousParents: any[] = []; + let settingsPropertyIndex: number = -1; + let range = { + startLineNumber: 0, + startColumn: 0, + endLineNumber: 0, + endColumn: 0 + }; + + function onValue(value: any, offset: number, length: number) { + if (Array.isArray(currentParent)) { + (currentParent).push(value); + } else if (currentProperty) { + currentParent[currentProperty] = value; + } + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // settings value started + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + if (setting) { + let valueStartPosition = model.getPositionAt(offset); + let valueEndPosition = model.getPositionAt(offset + length); + setting.value = value; + setting.valueRange = { + startLineNumber: valueStartPosition.lineNumber, + startColumn: valueStartPosition.column, + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }; + setting.range = assign(setting.range, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); + } + } + } + let visitor: JSONVisitor = { + onObjectBegin: (offset: number, length: number) => { + if (isSettingsProperty(currentProperty, previousParents)) { + // Settings started + settingsPropertyIndex = previousParents.length; + let position = model.getPositionAt(offset); + range.startLineNumber = position.lineNumber; + range.startColumn = position.column; + } + let object = {}; + onValue(object, offset, length); + currentParent = object; + currentProperty = null; + previousParents.push(currentParent); + }, + onObjectProperty: (name: string, offset: number, length: number) => { + currentProperty = name; + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting started + let settingStartPosition = model.getPositionAt(offset); + const setting: ISetting = { + description: [], + key: name, + keyRange: { + startLineNumber: settingStartPosition.lineNumber, + startColumn: settingStartPosition.column + 1, + endLineNumber: settingStartPosition.lineNumber, + endColumn: settingStartPosition.column + length + }, + range: { + startLineNumber: settingStartPosition.lineNumber, + startColumn: settingStartPosition.column, + endLineNumber: 0, + endColumn: 0 + }, + value: null, + valueRange: null, + descriptionRanges: null, + overrides: [], + overrideOf: overrideSetting + }; + if (previousParents.length === settingsPropertyIndex + 1) { + settings.push(setting); + if (OVERRIDE_PROPERTY_PATTERN.test(name)) { + overrideSetting = setting; + } + } else { + overrideSetting.overrides.push(setting); + } } - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // settings value started - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + }, + onObjectEnd: (offset: number, length: number) => { + currentParent = previousParents.pop(); + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting ended + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; if (setting) { - let valueStartPosition = model.getPositionAt(offset); let valueEndPosition = model.getPositionAt(offset + length); - setting.value = value; - setting.valueRange = { - startLineNumber: valueStartPosition.lineNumber, - startColumn: valueStartPosition.column, + setting.valueRange = assign(setting.valueRange, { endLineNumber: valueEndPosition.lineNumber, endColumn: valueEndPosition.column - }; + }); setting.range = assign(setting.range, { endLineNumber: valueEndPosition.lineNumber, endColumn: valueEndPosition.column }); } - } - } - let visitor: JSONVisitor = { - onObjectBegin: (offset: number, length: number) => { - if (previousParents.length === 0) { - // Settings started - let position = model.getPositionAt(offset); - range.startLineNumber = position.lineNumber; - range.startColumn = position.column; - } - let object = {}; - onValue(object, offset, length); - currentParent = object; - currentProperty = null; - previousParents.push(currentParent); - }, - onObjectProperty: (name: string, offset: number, length: number) => { - currentProperty = name; - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting started - let settingStartPosition = model.getPositionAt(offset); - const setting: ISetting = { - description: [], - key: name, - keyRange: { - startLineNumber: settingStartPosition.lineNumber, - startColumn: settingStartPosition.column + 1, - endLineNumber: settingStartPosition.lineNumber, - endColumn: settingStartPosition.column + length - }, - range: { - startLineNumber: settingStartPosition.lineNumber, - startColumn: settingStartPosition.column, - endLineNumber: 0, - endColumn: 0 - }, - value: null, - valueRange: null, - descriptionRanges: null, - overrides: [], - overrideOf: overrideSetting - }; - if (previousParents.length === 1) { - settings.push(setting); - if (OVERRIDE_PROPERTY_PATTERN.test(name)) { - overrideSetting = setting; - } - } else { - overrideSetting.overrides.push(setting); - } - } - }, - onObjectEnd: (offset: number, length: number) => { - currentParent = previousParents.pop(); - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting ended - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; - if (setting) { - let valueEndPosition = model.getPositionAt(offset + length); - setting.valueRange = assign(setting.valueRange, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - setting.range = assign(setting.range, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - } - if (previousParents.length === 1) { - overrideSetting = null; - } - } - if (previousParents.length === 0) { - // settings ended - let position = model.getPositionAt(offset); - range.endLineNumber = position.lineNumber; - range.endColumn = position.column; - } - }, - onArrayBegin: (offset: number, length: number) => { - let array: any[] = []; - onValue(array, offset, length); - previousParents.push(currentParent); - currentParent = array; - currentProperty = null; - }, - onArrayEnd: (offset: number, length: number) => { - currentParent = previousParents.pop(); - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting value ended - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; - if (setting) { - let valueEndPosition = model.getPositionAt(offset + length); - setting.valueRange = assign(setting.valueRange, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - setting.range = assign(setting.range, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - } + if (previousParents.length === settingsPropertyIndex + 1) { + overrideSetting = null; } - }, - onLiteralValue: onValue, - onError: (error) => { - const setting = settings[settings.length - 1]; - if (setting && (!setting.range || !setting.keyRange || !setting.valueRange)) { - settings.pop(); + } + if (previousParents.length === settingsPropertyIndex) { + // settings ended + let position = model.getPositionAt(offset); + range.endLineNumber = position.lineNumber; + range.endColumn = position.column; + } + }, + onArrayBegin: (offset: number, length: number) => { + let array: any[] = []; + onValue(array, offset, length); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: (offset: number, length: number) => { + currentParent = previousParents.pop(); + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting value ended + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + if (setting) { + let valueEndPosition = model.getPositionAt(offset + length); + setting.valueRange = assign(setting.valueRange, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); + setting.range = assign(setting.range, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); } } - }; - if (!model.isDisposed()) { - visit(model.getValue(), visitor); + }, + onLiteralValue: onValue, + onError: (error) => { + const setting = settings[settings.length - 1]; + if (setting && (!setting.range || !setting.keyRange || !setting.valueRange)) { + settings.pop(); + } } - this._settingsGroups = settings.length > 0 ? [{ - sections: [ - { - settings - } - ], - title: null, - titleRange: null, - range - }] : []; + }; + if (!model.isDisposed()) { + visit(model.getValue(), visitor); } + return settings.length > 0 ? [{ + sections: [ + { + settings + } + ], + title: null, + titleRange: null, + range + }] : []; +} + +export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { + + private _configurationGroups: ISettingsGroup[]; + + get configurationGroups(): ISettingsGroup[] { + return this._configurationGroups; + } + + protected parse(): void { + super.parse(); + this._configurationGroups = parse(this.settingsModel, (property: string, previousParents: string[]): boolean => previousParents.length === 0); + } + + protected isSettingsProperty(property: string, previousParents: string[]): boolean { + return property === 'settings' && previousParents.length === 1; + } + } export class WorkspaceConfigModel extends SettingsEditorModel implements ISettingsEditorModel {