#30955 Implement virtual editor for workspace settings in MR workspace
This commit is contained in:
parent
f4208eff49
commit
600e0dbc10
|
@ -35,6 +35,10 @@
|
||||||
"fileMatch": "vscode://defaultsettings/settings.json",
|
"fileMatch": "vscode://defaultsettings/settings.json",
|
||||||
"url": "vscode://schemas/settings"
|
"url": "vscode://schemas/settings"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fileMatch": "vscode://settings/workspaceSettings.json",
|
||||||
|
"url": "vscode://schemas/settings"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
|
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
|
||||||
"url": "vscode://schemas/settings"
|
"url": "vscode://schemas/settings"
|
||||||
|
|
|
@ -422,13 +422,13 @@ class SideBySidePreferencesWidget extends Widget {
|
||||||
|
|
||||||
this.defaultPreferencesEditorContainer = DOM.append(parentElement, DOM.$('.default-preferences-editor-container'));
|
this.defaultPreferencesEditorContainer = DOM.append(parentElement, DOM.$('.default-preferences-editor-container'));
|
||||||
this.defaultPreferencesEditorContainer.style.position = 'absolute';
|
this.defaultPreferencesEditorContainer.style.position = 'absolute';
|
||||||
this.defaultPreferencesEditor = this.instantiationService.createInstance(DefaultPreferencesEditor);
|
this.defaultPreferencesEditor = this._register(this.instantiationService.createInstance(DefaultPreferencesEditor));
|
||||||
this.defaultPreferencesEditor.create(new Builder(this.defaultPreferencesEditorContainer));
|
this.defaultPreferencesEditor.create(new Builder(this.defaultPreferencesEditorContainer));
|
||||||
this.defaultPreferencesEditor.setVisible(true);
|
this.defaultPreferencesEditor.setVisible(true);
|
||||||
|
|
||||||
this.editablePreferencesEditorContainer = DOM.append(parentElement, DOM.$('.editable-preferences-editor-container'));
|
this.editablePreferencesEditorContainer = DOM.append(parentElement, DOM.$('.editable-preferences-editor-container'));
|
||||||
this.editablePreferencesEditorContainer.style.position = 'absolute';
|
this.editablePreferencesEditorContainer.style.position = 'absolute';
|
||||||
this.editablePreferencesEditor = this.instantiationService.createInstance(EditableSettingsEditor);
|
this.editablePreferencesEditor = this._register(this.instantiationService.createInstance(EditableSettingsEditor));
|
||||||
this.editablePreferencesEditor.create(new Builder(this.editablePreferencesEditorContainer));
|
this.editablePreferencesEditor.create(new Builder(this.editablePreferencesEditorContainer));
|
||||||
this.editablePreferencesEditor.setVisible(true);
|
this.editablePreferencesEditor.setVisible(true);
|
||||||
|
|
||||||
|
@ -582,14 +582,22 @@ export class EditableSettingsEditor extends BaseTextEditor {
|
||||||
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearInput(): void {
|
||||||
|
this.modelDisposables = dispose(this.modelDisposables);
|
||||||
|
super.clearInput();
|
||||||
|
}
|
||||||
|
|
||||||
private onDidModelChange(): void {
|
private onDidModelChange(): void {
|
||||||
this.modelDisposables = dispose(this.modelDisposables);
|
this.modelDisposables = dispose(this.modelDisposables);
|
||||||
const model = getCodeEditor(this).getModel();
|
const model = getCodeEditor(this).getModel();
|
||||||
this.modelDisposables.push(model.onDidChangeContent(() => this.save(model.uri)));
|
if (model) {
|
||||||
}
|
this.preferencesService.createPreferencesEditorModel(model.uri)
|
||||||
|
.then(preferencesEditorModel => {
|
||||||
private save(resource: URI): void {
|
const settingsEditorModel = <SettingsEditorModel>preferencesEditorModel;
|
||||||
this.textFileService.save(resource);
|
this.modelDisposables.push(settingsEditorModel);
|
||||||
|
this.modelDisposables.push(model.onDidChangeContent(() => settingsEditorModel.save()));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { ResourceMap } from 'vs/base/common/map';
|
||||||
import * as labels from 'vs/base/common/labels';
|
import * as labels from 'vs/base/common/labels';
|
||||||
import * as strings from 'vs/base/common/strings';
|
import * as strings from 'vs/base/common/strings';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { EditorInput } from 'vs/workbench/common/editor';
|
import { EditorInput } from 'vs/workbench/common/editor';
|
||||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
|
@ -28,7 +29,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||||
import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences';
|
import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences';
|
||||||
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||||
import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor';
|
import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor';
|
||||||
|
@ -57,6 +58,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
private defaultPreferencesEditorModels: ResourceMap<TPromise<IPreferencesEditorModel<any>>>;
|
private defaultPreferencesEditorModels: ResourceMap<TPromise<IPreferencesEditorModel<any>>>;
|
||||||
private lastOpenedSettingsInput: PreferencesEditorInput = null;
|
private lastOpenedSettingsInput: PreferencesEditorInput = null;
|
||||||
|
|
||||||
|
private _onDispose: Emitter<void> = new Emitter<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||||
@IEditorGroupService private editorGroupService: IEditorGroupService,
|
@IEditorGroupService private editorGroupService: IEditorGroupService,
|
||||||
|
@ -99,6 +102,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
|
|
||||||
readonly defaultSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/settings.json' });
|
readonly defaultSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/settings.json' });
|
||||||
readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' });
|
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 {
|
get userSettingsResource(): URI {
|
||||||
return this.getEditableSettingsURI(ConfigurationTarget.USER);
|
return this.getEditableSettingsURI(ConfigurationTarget.USER);
|
||||||
|
@ -108,6 +112,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
|
return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveContent(uri: URI): TPromise<string> {
|
||||||
|
const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
|
||||||
|
if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) {
|
||||||
|
return this.resolveSettingsContentFromWorkspaceConfiguration();
|
||||||
|
}
|
||||||
|
return this.createPreferencesEditorModel(uri)
|
||||||
|
.then(preferencesEditorModel => preferencesEditorModel ? preferencesEditorModel.content : null);
|
||||||
|
}
|
||||||
|
|
||||||
createPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel<any>> {
|
createPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel<any>> {
|
||||||
let promise = this.defaultPreferencesEditorModels.get(uri);
|
let promise = this.defaultPreferencesEditorModels.get(uri);
|
||||||
if (promise) {
|
if (promise) {
|
||||||
|
@ -132,6 +145,12 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.workspaceConfigSettingsResource.fsPath === uri.fsPath) {
|
||||||
|
promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE);
|
||||||
|
this.defaultPreferencesEditorModels.set(uri, promise);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.getEditableSettingsURI(ConfigurationTarget.USER).fsPath === uri.fsPath) {
|
if (this.getEditableSettingsURI(ConfigurationTarget.USER).fsPath === uri.fsPath) {
|
||||||
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER);
|
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER);
|
||||||
}
|
}
|
||||||
|
@ -243,12 +262,29 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget): TPromise<SettingsEditorModel> {
|
private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget): TPromise<SettingsEditorModel> {
|
||||||
const settingsUri = this.getEditableSettingsURI(configurationTarget);
|
const settingsUri = this.getEditableSettingsURI(configurationTarget);
|
||||||
if (settingsUri) {
|
if (settingsUri) {
|
||||||
|
if (settingsUri.fsPath === this.workspaceConfigSettingsResource.fsPath) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
return this.textModelResolverService.createModelReference(settingsUri)
|
return this.textModelResolverService.createModelReference(settingsUri)
|
||||||
.then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget));
|
.then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget));
|
||||||
}
|
}
|
||||||
return TPromise.wrap<SettingsEditorModel>(null);
|
return TPromise.wrap<SettingsEditorModel>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resolveSettingsContentFromWorkspaceConfiguration(): TPromise<string> {
|
||||||
|
if (this.contextService.hasMultiFolderWorkspace()) {
|
||||||
|
return this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration)
|
||||||
|
.then(reference => {
|
||||||
|
const model = reference.object.textEditorModel;
|
||||||
|
const settingsContent = WorkspaceConfigModel.getSettingsContentFromConfigContent(model.getValue());
|
||||||
|
reference.dispose();
|
||||||
|
return TPromise.as(settingsContent ? settingsContent : this.getEmptyEditableSettingsContent(ConfigurationTarget.WORKSPACE));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return TPromise.as(null);
|
||||||
|
}
|
||||||
|
|
||||||
private getEmptyEditableSettingsContent(target: ConfigurationTarget | URI): string {
|
private getEmptyEditableSettingsContent(target: ConfigurationTarget | URI): string {
|
||||||
if (target === ConfigurationTarget.USER) {
|
if (target === ConfigurationTarget.USER) {
|
||||||
const emptySettingsHeader = nls.localize('emptySettingsHeader', "Place your settings in this file to overwrite the default settings");
|
const emptySettingsHeader = nls.localize('emptySettingsHeader', "Place your settings in this file to overwrite the default settings");
|
||||||
|
@ -275,7 +311,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
return this.toResource(paths.join('.vscode', 'settings.json'), workspace.roots[0]);
|
return this.toResource(paths.join('.vscode', 'settings.json'), workspace.roots[0]);
|
||||||
}
|
}
|
||||||
if (this.contextService.hasMultiFolderWorkspace()) {
|
if (this.contextService.hasMultiFolderWorkspace()) {
|
||||||
return workspace.configuration;
|
return this.workspaceConfigSettingsResource;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -289,9 +325,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
private createSettingsIfNotExists(target: ConfigurationTarget | URI): TPromise<void> {
|
private createSettingsIfNotExists(target: ConfigurationTarget | URI): TPromise<void> {
|
||||||
const resource = this.getEditableSettingsURI(target);
|
const resource = this.getEditableSettingsURI(target);
|
||||||
if (this.contextService.hasMultiFolderWorkspace() && target === ConfigurationTarget.WORKSPACE) {
|
if (this.contextService.hasMultiFolderWorkspace() && target === ConfigurationTarget.WORKSPACE) {
|
||||||
if (!this.configurationService.keys().workspace.length) {
|
|
||||||
return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(null, () => { });
|
|
||||||
}
|
|
||||||
return TPromise.as(null);
|
return TPromise.as(null);
|
||||||
}
|
}
|
||||||
const editableSettingsEmptyContent = this.getEmptyEditableSettingsContent(target);
|
const editableSettingsEmptyContent = this.getEmptyEditableSettingsContent(target);
|
||||||
|
@ -367,6 +400,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
this._onDispose.fire();
|
||||||
this.defaultPreferencesEditorModels.clear();
|
this.defaultPreferencesEditorModels.clear();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ export interface IPreferencesService {
|
||||||
workspaceSettingsResource: URI;
|
workspaceSettingsResource: URI;
|
||||||
defaultKeybindingsResource: URI;
|
defaultKeybindingsResource: URI;
|
||||||
|
|
||||||
|
resolveContent(uri: URI): TPromise<string>;
|
||||||
createPreferencesEditorModel<T>(uri: URI): TPromise<IPreferencesEditorModel<T>>;
|
createPreferencesEditorModel<T>(uri: URI): TPromise<IPreferencesEditorModel<T>>;
|
||||||
|
|
||||||
openSettings(target: ConfigurationTarget | URI): TPromise<IEditor>;
|
openSettings(target: ConfigurationTarget | URI): TPromise<IEditor>;
|
||||||
|
|
|
@ -47,12 +47,11 @@ export class PreferencesContentProvider implements IWorkbenchContribution {
|
||||||
return TPromise.as(this.modelService.createModel(modelContent, mode, uri));
|
return TPromise.as(this.modelService.createModel(modelContent, mode, uri));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.preferencesService.createPreferencesEditorModel(uri)
|
return this.preferencesService.resolveContent(uri)
|
||||||
.then(preferencesModel => {
|
.then(content => {
|
||||||
if (preferencesModel) {
|
if (content !== null && content !== void 0) {
|
||||||
let mode = this.modeService.getOrCreateMode('json');
|
let mode = this.modeService.getOrCreateMode('json');
|
||||||
const model = this.modelService.createModel(preferencesModel.content, mode, uri);
|
const model = this.modelService.createModel(content, mode, uri);
|
||||||
preferencesModel.dispose();
|
|
||||||
return TPromise.as(model);
|
return TPromise.as(model);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { assign } from 'vs/base/common/objects';
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { IReference } from 'vs/base/common/lifecycle';
|
import { IReference } from 'vs/base/common/lifecycle';
|
||||||
|
import Event from 'vs/base/common/event';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { visit, JSONVisitor } from 'vs/base/common/json';
|
import { visit, JSONVisitor } from 'vs/base/common/json';
|
||||||
import { IModel } from 'vs/editor/common/editorCommon';
|
import { IModel } from 'vs/editor/common/editorCommon';
|
||||||
|
@ -19,8 +20,12 @@ import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||||
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
|
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
|
||||||
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
|
import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
import { IRange } from 'vs/editor/common/core/range';
|
||||||
|
import { ITextFileService, StateChange } from "vs/workbench/services/textfile/common/textfiles";
|
||||||
|
import { TPromise } from "vs/base/common/winjs.base";
|
||||||
|
import { Queue } from "vs/base/common/async";
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
|
||||||
class SettingMatches {
|
class SettingMatches {
|
||||||
|
|
||||||
|
@ -233,19 +238,21 @@ export abstract class AbstractSettingsModel extends EditorModel {
|
||||||
export class SettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel {
|
export class SettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel {
|
||||||
|
|
||||||
private _settingsGroups: ISettingsGroup[];
|
private _settingsGroups: ISettingsGroup[];
|
||||||
private model: IModel;
|
protected settingsModel: IModel;
|
||||||
|
private queue: Queue<void>;
|
||||||
|
|
||||||
constructor(reference: IReference<ITextEditorModel>, private _configurationTarget: ConfigurationTarget) {
|
constructor(reference: IReference<ITextEditorModel>, private _configurationTarget: ConfigurationTarget, @ITextFileService protected textFileService: ITextFileService) {
|
||||||
super();
|
super();
|
||||||
this.model = reference.object.textEditorModel;
|
this.settingsModel = reference.object.textEditorModel;
|
||||||
this._register(this.onDispose(() => reference.dispose()));
|
this._register(this.onDispose(() => reference.dispose()));
|
||||||
this._register(this.model.onDidChangeContent(() => {
|
this._register(this.settingsModel.onDidChangeContent(() => {
|
||||||
this._settingsGroups = null;
|
this._settingsGroups = null;
|
||||||
}));
|
}));
|
||||||
|
this.queue = new Queue<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get uri(): URI {
|
public get uri(): URI {
|
||||||
return this.model.uri;
|
return this.settingsModel.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get configurationTarget(): ConfigurationTarget {
|
public get configurationTarget(): ConfigurationTarget {
|
||||||
|
@ -260,19 +267,27 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti
|
||||||
}
|
}
|
||||||
|
|
||||||
public get content(): string {
|
public get content(): string {
|
||||||
return this.model.getValue();
|
return this.settingsModel.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public filterSettings(filter: string): IFilterResult {
|
public filterSettings(filter: string): IFilterResult {
|
||||||
return this.doFilterSettings(filter, this.settingsGroups);
|
return this.doFilterSettings(filter, this.settingsGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public save(): TPromise<any> {
|
||||||
|
return this.queue.queue(() => this.doSave());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doSave(): TPromise<any> {
|
||||||
|
return this.textFileService.save(this.uri);
|
||||||
|
}
|
||||||
|
|
||||||
protected findValueMatches(filter: string, setting: ISetting): IRange[] {
|
protected findValueMatches(filter: string, setting: ISetting): IRange[] {
|
||||||
return this.model.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range);
|
return this.settingsModel.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parse() {
|
private parse() {
|
||||||
const model = this.model;
|
const model = this.settingsModel;
|
||||||
const settings: ISetting[] = [];
|
const settings: ISetting[] = [];
|
||||||
let overrideSetting: ISetting = null;
|
let overrideSetting: ISetting = null;
|
||||||
|
|
||||||
|
@ -439,6 +454,144 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WorkspaceConfigModel extends SettingsEditorModel implements ISettingsEditorModel {
|
||||||
|
|
||||||
|
private workspaceConfigModel: IModel;
|
||||||
|
private workspaceConfigEtag: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
reference: IReference<ITextEditorModel>,
|
||||||
|
workspaceConfigModelReference: IReference<ITextEditorModel>,
|
||||||
|
_configurationTarget: ConfigurationTarget,
|
||||||
|
onDispose: Event<void>,
|
||||||
|
@IFileService private fileService: IFileService,
|
||||||
|
@ITextModelService private textModelResolverService: ITextModelService,
|
||||||
|
@ITextFileService textFileService: ITextFileService
|
||||||
|
) {
|
||||||
|
super(reference, _configurationTarget, textFileService);
|
||||||
|
|
||||||
|
this._register(workspaceConfigModelReference);
|
||||||
|
this.workspaceConfigModel = workspaceConfigModelReference.object.textEditorModel;
|
||||||
|
|
||||||
|
// Only listen to state changes. Content changes without saving are not synced.
|
||||||
|
this._register(this.textFileService.models.get(this.workspaceConfigModel.uri).onDidStateChange(statChange => this._onWorkspaceConfigFileStateChanged(statChange)));
|
||||||
|
this.onDispose(() => super.dispose());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doSave(): TPromise<any> {
|
||||||
|
if (this.textFileService.isDirty(this.workspaceConfigModel.uri)) {
|
||||||
|
// Throw an error?
|
||||||
|
return TPromise.as(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = this.createWorkspaceConfigContentFromSettingsModel();
|
||||||
|
if (content !== this.workspaceConfigModel.getValue()) {
|
||||||
|
return this.fileService.updateContent(this.workspaceConfigModel.uri, content)
|
||||||
|
.then(stat => this.workspaceConfigEtag = stat.etag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TPromise.as(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createWorkspaceConfigContentFromSettingsModel(): string {
|
||||||
|
const workspaceConfigContent = this.workspaceConfigModel.getValue();
|
||||||
|
const { settingsPropertyEndsAt, nodeAfterSettingStartsAt } = WorkspaceConfigModel.parseWorkspaceConfigContent(workspaceConfigContent);
|
||||||
|
const workspaceConfigEndsAt = workspaceConfigContent.lastIndexOf('}');
|
||||||
|
|
||||||
|
// Settings property exist in Workspace Configuration and has Ending Brace
|
||||||
|
if (settingsPropertyEndsAt !== -1 && workspaceConfigEndsAt > settingsPropertyEndsAt) {
|
||||||
|
|
||||||
|
// Place settings at the end
|
||||||
|
let from = workspaceConfigContent.indexOf(':', settingsPropertyEndsAt) + 1;
|
||||||
|
let to = workspaceConfigEndsAt;
|
||||||
|
let settingsContent = this.settingsModel.getValue();
|
||||||
|
|
||||||
|
// There is a node after settings property
|
||||||
|
// Place settings before that node
|
||||||
|
if (nodeAfterSettingStartsAt !== -1) {
|
||||||
|
settingsContent += ',';
|
||||||
|
to = nodeAfterSettingStartsAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return workspaceConfigContent.substring(0, from) + settingsContent + workspaceConfigContent.substring(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings property does not exist. Place it at the end
|
||||||
|
return workspaceConfigContent.substring(0, workspaceConfigEndsAt) + `,\n"settings": ${this.settingsModel.getValue()}\n` + workspaceConfigContent.substring(workspaceConfigEndsAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onWorkspaceConfigFileStateChanged(stateChange: StateChange): void {
|
||||||
|
let hasToUpdate = false;
|
||||||
|
switch (stateChange) {
|
||||||
|
case StateChange.SAVED:
|
||||||
|
hasToUpdate = this.workspaceConfigEtag !== this.textFileService.models.get(this.workspaceConfigModel.uri).getETag();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (hasToUpdate) {
|
||||||
|
this.onWorkspaceConfigFileContentChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onWorkspaceConfigFileContentChanged(): void {
|
||||||
|
this.workspaceConfigEtag = this.textFileService.models.get(this.workspaceConfigModel.uri).getETag();
|
||||||
|
const settingsValue = WorkspaceConfigModel.getSettingsContentFromConfigContent(this.workspaceConfigModel.getValue());
|
||||||
|
if (settingsValue) {
|
||||||
|
this.settingsModel.setValue(settingsValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
// Not disposable by default
|
||||||
|
}
|
||||||
|
|
||||||
|
static getSettingsContentFromConfigContent(workspaceConfigContent: string): string {
|
||||||
|
const { settingsPropertyEndsAt, nodeAfterSettingStartsAt } = WorkspaceConfigModel.parseWorkspaceConfigContent(workspaceConfigContent);
|
||||||
|
|
||||||
|
const workspaceConfigEndsAt = workspaceConfigContent.lastIndexOf('}');
|
||||||
|
|
||||||
|
if (settingsPropertyEndsAt !== -1) {
|
||||||
|
const from = workspaceConfigContent.indexOf(':', settingsPropertyEndsAt) + 1;
|
||||||
|
const to = nodeAfterSettingStartsAt !== -1 ? nodeAfterSettingStartsAt : workspaceConfigEndsAt;
|
||||||
|
return workspaceConfigContent.substring(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseWorkspaceConfigContent(content: string): { settingsPropertyEndsAt: number, nodeAfterSettingStartsAt: number } {
|
||||||
|
|
||||||
|
let settingsPropertyEndsAt = -1;
|
||||||
|
let nodeAfterSettingStartsAt = -1;
|
||||||
|
|
||||||
|
let rootProperties = [];
|
||||||
|
let ancestors = [];
|
||||||
|
let currentProperty = '';
|
||||||
|
|
||||||
|
visit(content, <JSONVisitor>{
|
||||||
|
onObjectProperty: (name: string, offset: number, length: number) => {
|
||||||
|
currentProperty = name;
|
||||||
|
if (ancestors.length === 1) {
|
||||||
|
rootProperties.push(name);
|
||||||
|
if (rootProperties[rootProperties.length - 1] === 'settings') {
|
||||||
|
settingsPropertyEndsAt = offset + length;
|
||||||
|
}
|
||||||
|
if (rootProperties[rootProperties.length - 2] === 'settings') {
|
||||||
|
nodeAfterSettingStartsAt = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onObjectBegin: (offset: number, length: number) => {
|
||||||
|
ancestors.push(currentProperty);
|
||||||
|
},
|
||||||
|
onObjectEnd: (offset: number, length: number) => {
|
||||||
|
ancestors.pop();
|
||||||
|
}
|
||||||
|
}, { allowTrailingComma: true });
|
||||||
|
|
||||||
|
return { settingsPropertyEndsAt, nodeAfterSettingStartsAt };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel {
|
export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel {
|
||||||
|
|
||||||
private _allSettingsGroups: ISettingsGroup[];
|
private _allSettingsGroups: ISettingsGroup[];
|
||||||
|
|
Loading…
Reference in a new issue