提交 2bac5fd0 编写于 作者: S Sandeep Somavarapu

#29462 Indicate unsupported settings on a folder level

上级 adf73b89
......@@ -213,6 +213,10 @@
background: url('edit_inverse.svg') center center no-repeat;
}
.monaco-editor .invalidSetting {
color: #b1b1b1;
}
.monaco-editor .floating-click-widget {
padding: 10px;
border-radius: 5px;
......
......@@ -12,6 +12,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
import { IPreferencesService, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences';
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
import { ConfigurationTarget } from "vs/workbench/services/configuration/common/configurationEditing";
export class OpenGlobalSettingsAction extends Action {
......@@ -106,7 +107,7 @@ export class OpenFolderSettingsAction extends Action {
public run(): TPromise<any> {
const picks: IPickOpenEntry[] = this.workspaceContextService.getWorkspace().roots.map((root, index) => {
return <IPickOpenEntry>{
label: getSettingsTargetName(root, this.workspaceContextService),
label: getSettingsTargetName(ConfigurationTarget.FOLDER, root, this.workspaceContextService),
id: `${index}`
};
});
......@@ -114,7 +115,7 @@ export class OpenFolderSettingsAction extends Action {
return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickFolder', "Select Folder") })
.then(pick => {
if (pick) {
return this.preferencesService.openSettings(this.workspaceContextService.getWorkspace().roots[parseInt(pick.id)]);
return this.preferencesService.openFolderSettings(this.workspaceContextService.getWorkspace().roots[parseInt(pick.id)]);
}
return undefined;
});
......
......@@ -43,7 +43,7 @@ import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { VSash } from 'vs/base/browser/ui/sash/sash';
import { Widget } from 'vs/base/browser/ui/widget';
import { IPreferencesRenderer, DefaultSettingsRenderer, UserSettingsRenderer, WorkspaceSettingsRenderer } from 'vs/workbench/parts/preferences/browser/preferencesRenderers';
import { IPreferencesRenderer, DefaultSettingsRenderer, UserSettingsRenderer, WorkspaceSettingsRenderer, FolderSettingsRenderer } from 'vs/workbench/parts/preferences/browser/preferencesRenderers';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
......@@ -147,7 +147,7 @@ export class PreferencesEditor extends BaseEditor {
this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget));
this.lastFocusedWidget = this.searchWidget;
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, this.headerContainer, this.preferencesService.userSettingsResource));
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, this.headerContainer, this.preferencesService.userSettingsResource, ConfigurationTarget.USER));
this._register(this.settingsTargetsWidget.onDidTargetChange(target => this.switchSettings(target)));
const editorsContainer = DOM.append(parentElement, DOM.$('.preferences-editors-container'));
......@@ -211,7 +211,8 @@ export class PreferencesEditor extends BaseEditor {
}
private updateInput(oldInput: PreferencesEditorInput, newInput: PreferencesEditorInput, options?: EditorOptions): TPromise<void> {
this.settingsTargetsWidget.setTarget(this.getSettingsConfigurationTarget(newInput));
const resource = toResource(newInput.master);
this.settingsTargetsWidget.setTarget(resource, this.getSettingsConfigurationTarget(resource));
return this.sideBySidePreferencesWidget.setInput(<DefaultPreferencesEditorInput>newInput.details, <EditorInput>newInput.master, options).then(({ defaultPreferencesRenderer, editablePreferencesRenderer }) => {
this.preferencesRenderers.defaultPreferencesRenderer = defaultPreferencesRenderer;
......@@ -220,24 +221,26 @@ export class PreferencesEditor extends BaseEditor {
});
}
private getSettingsConfigurationTarget(preferencesEditorInput: PreferencesEditorInput): ConfigurationTarget | URI {
const resource = toResource(preferencesEditorInput.master);
private getSettingsConfigurationTarget(resource: URI): ConfigurationTarget {
if (this.preferencesService.userSettingsResource.fsPath === resource.fsPath) {
return ConfigurationTarget.USER;
}
if (this.preferencesService.workspaceSettingsResource.fsPath === resource.fsPath) {
return ConfigurationTarget.WORKSPACE;
}
return this.workspaceContextService.getRoot(resource);
if (this.workspaceContextService.getRoot(resource)) {
return ConfigurationTarget.FOLDER;
}
return null;
}
private switchSettings(target: ConfigurationTarget | URI): void {
private switchSettings(resource: URI): void {
// Focus the editor if this editor is not active editor
if (this.editorService.getActiveEditor() !== this) {
this.focus();
}
const promise = this.input.isDirty() ? this.input.save() : TPromise.as(true);
promise.done(value => this.preferencesService.switchSettings(target));
promise.done(value => this.preferencesService.switchSettings(this.getSettingsConfigurationTarget(resource), resource));
}
private filterPreferences(filter: string) {
......@@ -811,10 +814,14 @@ class SettingsEditorContribution extends Disposable implements ISettingsEditorCo
this.preferencesRenderer = TPromise.join<any>([this.preferencesService.createPreferencesEditorModel(this.preferencesService.defaultSettingsResource), this.preferencesService.createPreferencesEditorModel(this.editor.getModel().uri)])
.then(([defaultSettingsModel, settingsModel]) => {
if (settingsModel instanceof SettingsEditorModel) {
if (ConfigurationTarget.USER === settingsModel.configurationTarget) {
return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel, defaultSettingsModel);
switch (settingsModel.configurationTarget) {
case ConfigurationTarget.USER:
return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel, defaultSettingsModel);
case ConfigurationTarget.WORKSPACE:
return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel, defaultSettingsModel);
case ConfigurationTarget.FOLDER:
return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel, defaultSettingsModel);
}
return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel, defaultSettingsModel);
}
return null;
})
......
......@@ -13,7 +13,7 @@ import Event, { Emitter } from 'vs/base/common/event';
import { Registry } from 'vs/platform/registry/common/platform';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { Range, IRange } from 'vs/editor/common/core/range';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } 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';
......@@ -94,7 +94,8 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
public updatePreference(key: string, value: any, source: ISetting): void {
this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] });
const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value }, { donotSave: this.textFileService.isDirty(this.preferencesModel.uri), donotNotifyError: true, scopes: { overrideIdentifier } })
const resource = this.preferencesModel.uri;
this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value }, { donotSave: this.textFileService.isDirty(resource), donotNotifyError: true, scopes: { overrideIdentifier, resource } })
.then(() => this.onSettingUpdated(source), error => {
this.messageService.show(Severity.Error, this.toErrorMessage(error, this.preferencesModel.configurationTarget));
});
......@@ -183,6 +184,28 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I
}
}
export class FolderSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer<ISetting> {
private unsupportedWorkbenchSettingsRenderer: UnsupportedWorkbenchSettingsRenderer;
constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, associatedPreferencesModel: IPreferencesEditorModel<ISetting>,
@IPreferencesService preferencesService: IPreferencesService,
@ITelemetryService telemetryService: ITelemetryService,
@ITextFileService textFileService: ITextFileService,
@IConfigurationEditingService configurationEditingService: IConfigurationEditingService,
@IMessageService messageService: IMessageService,
@IInstantiationService instantiationService: IInstantiationService
) {
super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationEditingService, messageService, instantiationService);
this.unsupportedWorkbenchSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedWorkbenchSettingsRenderer, editor, preferencesModel));
}
public render(): void {
super.render();
this.unsupportedWorkbenchSettingsRenderer.render();
}
}
export class DefaultSettingsRenderer extends Disposable implements IPreferencesRenderer<ISetting> {
private _associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
......@@ -929,4 +952,62 @@ class UnsupportedWorkspaceSettingsRenderer extends Disposable {
this.markerService.remove('preferencesEditor', [this.workspaceSettingsEditorModel.uri]);
super.dispose();
}
}
class UnsupportedWorkbenchSettingsRenderer extends Disposable {
private decorationIds: string[] = [];
constructor(private editor: editorCommon.ICommonCodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@IMarkerService private markerService: IMarkerService
) {
super();
this._register(this.configurationService.onDidUpdateConfiguration(() => this.render()));
}
public render(): void {
this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, []));
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
const folderKeys = this.configurationService.keys({ resource: this.workspaceSettingsEditorModel.uri }).folder;
const workbenchKeys = folderKeys.filter(key => configurationRegistry[key] && configurationRegistry[key].scope === ConfigurationScope.WORKBENCH);
if (workbenchKeys.length) {
const ranges: IRange[] = [];
for (const unsupportedKey of workbenchKeys) {
const setting = this.workspaceSettingsEditorModel.getPreference(unsupportedKey);
if (setting) {
ranges.push({
startLineNumber: setting.keyRange.startLineNumber,
startColumn: setting.keyRange.startColumn - 1,
endLineNumber: setting.valueRange.endLineNumber,
endColumn: setting.valueRange.endColumn
});
}
}
this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, ranges.map(range => this.createDecoration(range, this.editor.getModel()))));
}
}
private static _INVALID_SETTING_ = ModelDecorationOptions.register({
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
inlineClassName: 'invalidSetting',
hoverMessage: nls.localize('unsupportedWorkbenchSetting', "This setting is a workbench setting and cannot be applied for resources under folder")
});
private createDecoration(range: IRange, model: editorCommon.IModel): editorCommon.IModelDeltaDecoration {
return {
range,
options: UnsupportedWorkbenchSettingsRenderer._INVALID_SETTING_
};
}
public dispose(): void {
if (this.decorationIds) {
this.decorationIds = this.editor.changeDecorations(changeAccessor => {
return changeAccessor.deltaDecorations(this.decorationIds, []);
});
}
super.dispose();
}
}
\ No newline at end of file
......@@ -146,29 +146,29 @@ export class PreferencesService extends Disposable implements IPreferencesServic
}
if (this.workspaceConfigSettingsResource.fsPath === uri.fsPath) {
promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE);
promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri);
this.defaultPreferencesEditorModels.set(uri, promise);
return promise;
}
if (this.getEditableSettingsURI(ConfigurationTarget.USER).fsPath === uri.fsPath) {
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER);
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri);
}
const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) {
return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE);
return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri);
}
return TPromise.wrap<IPreferencesEditorModel<any>>(null);
}
if (this.contextService.hasMultiFolderWorkspace()) {
return this.createEditableSettingsEditorModel(ConfigurationTarget.FOLDER, uri);
}
openSettings(target: ConfigurationTarget | URI): TPromise<IEditor> {
return this.doOpenSettings(target);
return TPromise.wrap<IPreferencesEditorModel<any>>(null);
}
openGlobalSettings(): TPromise<IEditor> {
return this.doOpenSettings(ConfigurationTarget.USER);
return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource);
}
openWorkspaceSettings(): TPromise<IEditor> {
......@@ -176,16 +176,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic
this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
return TPromise.as(null);
}
return this.doOpenSettings(ConfigurationTarget.WORKSPACE);
return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource);
}
switchSettings(target: URI | ConfigurationTarget): TPromise<void> {
openFolderSettings(folder: URI): TPromise<IEditor> {
return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder));
}
switchSettings(target: ConfigurationTarget, resource: URI): TPromise<void> {
const activeEditor = this.editorService.getActiveEditor();
const activeEditorInput = activeEditor.input;
if (activeEditorInput instanceof PreferencesEditorInput) {
return this.getOrCreateEditableSettingsEditorInput(target)
return this.getOrCreateEditableSettingsEditorInput(target, this.getEditableSettingsURI(target, resource))
.then(toInput => {
const replaceWith = new PreferencesEditorInput(this.getPreferencesEditorInputName(target), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource), toInput);
const replaceWith = new PreferencesEditorInput(this.getPreferencesEditorInputName(target, resource), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource), toInput);
return this.editorService.replaceEditors([{
toReplace: this.lastOpenedSettingsInput,
replaceWith
......@@ -194,7 +198,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
});
});
} else {
this.openSettings(target);
this.doOpenSettings(target, resource);
return undefined;
}
}
......@@ -231,13 +235,13 @@ export class PreferencesService extends Disposable implements IPreferencesServic
});
}
private doOpenSettings(configurationTarget: ConfigurationTarget | URI): TPromise<IEditor> {
private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI): TPromise<IEditor> {
const openDefaultSettings = !!this.configurationService.getConfiguration<IWorkbenchSettingsConfiguration>().workbench.settings.openDefaultSettings;
return this.getOrCreateEditableSettingsEditorInput(configurationTarget)
return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource)
.then(editableSettingsEditorInput => {
if (openDefaultSettings) {
const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource);
const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, <EditorInput>editableSettingsEditorInput);
const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, <EditorInput>editableSettingsEditorInput);
this.lastOpenedSettingsInput = preferencesEditorInput;
return this.editorService.openEditor(preferencesEditorInput, { pinned: true });
}
......@@ -245,22 +249,18 @@ export class PreferencesService extends Disposable implements IPreferencesServic
});
}
private getPreferencesEditorInputName(target: ConfigurationTarget | URI): string {
const name = getSettingsTargetName(target, this.contextService);
return target instanceof URI ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name;
private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string {
const name = getSettingsTargetName(target, resource, this.contextService);
return target === ConfigurationTarget.FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name;
}
private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget | URI): TPromise<EditorInput> {
const resource = this.getEditableSettingsURI(target);
if (resource) {
return this.createSettingsIfNotExists(target)
.then(() => <EditorInput>this.editorService.createInput({ resource }));
}
return TPromise.wrapError<EditorInput>(new Error('Unknown target ' + (target instanceof URI ? target.toString(false) : target.toString())));
private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget, resource: URI): TPromise<EditorInput> {
return this.createSettingsIfNotExists(target, resource)
.then(() => <EditorInput>this.editorService.createInput({ resource }));
}
private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget): TPromise<SettingsEditorModel> {
const settingsUri = this.getEditableSettingsURI(configurationTarget);
private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): TPromise<SettingsEditorModel> {
const settingsUri = this.getEditableSettingsURI(configurationTarget, resource);
if (settingsUri) {
if (settingsUri.fsPath === this.workspaceConfigSettingsResource.fsPath) {
return TPromise.join([this.textModelResolverService.createModelReference(settingsUri), this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration)])
......@@ -285,7 +285,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
return TPromise.as(null);
}
private getEmptyEditableSettingsContent(target: ConfigurationTarget | URI): string {
private getEmptyEditableSettingsContent(target: ConfigurationTarget): string {
if (target === ConfigurationTarget.USER) {
const emptySettingsHeader = nls.localize('emptySettingsHeader', "Place your settings in this file to overwrite the default settings");
return '// ' + emptySettingsHeader + '\n{\n}';
......@@ -297,11 +297,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
].join('\n');
}
private getEditableSettingsURI(configurationTarget: ConfigurationTarget | URI): URI {
if (configurationTarget instanceof URI) {
const root = this.contextService.getRoot(configurationTarget);
return root ? this.toResource(paths.join('.vscode', 'settings.json'), root) : null;
}
private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI {
switch (configurationTarget) {
case ConfigurationTarget.USER:
return URI.file(this.environmentService.appSettingsPath);
......@@ -314,6 +310,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic
return this.workspaceConfigSettingsResource;
}
return null;
case ConfigurationTarget.FOLDER:
const root = this.contextService.getRoot(resource);
return root ? this.toResource(paths.join('.vscode', 'settings.json'), root) : null;
}
return null;
}
......@@ -322,8 +321,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
return URI.file(paths.join(root.fsPath, relativePath));
}
private createSettingsIfNotExists(target: ConfigurationTarget | URI): TPromise<void> {
const resource = this.getEditableSettingsURI(target);
private createSettingsIfNotExists(target: ConfigurationTarget, resource: URI): TPromise<void> {
if (this.contextService.hasMultiFolderWorkspace() && target === ConfigurationTarget.WORKSPACE) {
return TPromise.as(null);
}
......
......@@ -257,12 +257,12 @@ export class SettingsTargetsWidget extends Widget {
private targetLabel: HTMLSelectElement;
private targetDetails: HTMLSelectElement;
private _onDidTargetChange: Emitter<ConfigurationTarget | URI> = new Emitter<ConfigurationTarget | URI>();
public readonly onDidTargetChange: Event<ConfigurationTarget | URI> = this._onDidTargetChange.event;
private _onDidTargetChange: Emitter<URI> = new Emitter<URI>();
public readonly onDidTargetChange: Event<URI> = this._onDidTargetChange.event;
private borderColor: Color;
constructor(parent: HTMLElement, private target: ConfigurationTarget | URI,
constructor(parent: HTMLElement, private uri: URI, private target: ConfigurationTarget,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IPreferencesService private preferencesService: IPreferencesService,
@IContextMenuService private contextMenuService: IContextMenuService,
......@@ -276,7 +276,8 @@ export class SettingsTargetsWidget extends Widget {
}));
}
public setTarget(target: ConfigurationTarget | URI): void {
public setTarget(uri: URI, target: ConfigurationTarget): void {
this.uri = uri;
this.target = target;
this.updateLabel();
}
......@@ -290,7 +291,7 @@ export class SettingsTargetsWidget extends Widget {
this.targetDetails = DOM.append(targetElement, DOM.$('.settings-target-details'));
this.updateLabel();
this.onclick(this.settingsTargetsContainer, e => this.showContextMennu(e));
this.onclick(this.settingsTargetsContainer, e => this.showContextMenu(e));
DOM.append(this.settingsTargetsContainer, DOM.$('.settings-target-dropdown-icon.octicon.octicon-triangle-down'));
......@@ -298,13 +299,13 @@ export class SettingsTargetsWidget extends Widget {
}
private updateLabel(): void {
this.targetLabel.textContent = getSettingsTargetName(this.target, this.workspaceContextService);
const details = this.target instanceof URI ? localize('folderSettingsDetails', "Folder Settings") : '';
this.targetLabel.textContent = getSettingsTargetName(this.target, this.uri, this.workspaceContextService);
const details = ConfigurationTarget.FOLDER === this.target ? localize('folderSettingsDetails', "Folder Settings") : '';
this.targetDetails.textContent = details;
DOM.toggleClass(this.targetDetails, 'empty', !details);
}
private showContextMennu(event: IMouseEvent): void {
private showContextMenu(event: IMouseEvent): void {
const actions = this.getSettingsTargetsActions();
this.contextMenuService.showContextMenu({
getAnchor: () => this.settingsTargetsContainer,
......@@ -316,21 +317,23 @@ export class SettingsTargetsWidget extends Widget {
private getSettingsTargetsActions(): IAction[] {
const actions: IAction[] = [];
const userSettingsResource = this.preferencesService.userSettingsResource;
actions.push(<IAction>{
id: 'userSettingsTarget',
label: getSettingsTargetName(ConfigurationTarget.USER, this.workspaceContextService),
checked: this.target === ConfigurationTarget.USER,
label: getSettingsTargetName(ConfigurationTarget.USER, userSettingsResource, this.workspaceContextService),
checked: this.uri.fsPath === userSettingsResource.fsPath,
enabled: true,
run: () => this.onTargetClicked(ConfigurationTarget.USER)
run: () => this.onTargetClicked(userSettingsResource)
});
if (this.workspaceContextService.hasWorkspace()) {
const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource;
actions.push(<IAction>{
id: 'workspaceSettingsTarget',
label: getSettingsTargetName(ConfigurationTarget.WORKSPACE, this.workspaceContextService),
checked: this.target === ConfigurationTarget.WORKSPACE,
label: getSettingsTargetName(ConfigurationTarget.WORKSPACE, workspaceSettingsResource, this.workspaceContextService),
checked: this.uri.fsPath === workspaceSettingsResource.fsPath,
enabled: true,
run: () => this.onTargetClicked(ConfigurationTarget.WORKSPACE)
run: () => this.onTargetClicked(workspaceSettingsResource)
});
}
......@@ -339,8 +342,8 @@ export class SettingsTargetsWidget extends Widget {
actions.push(...this.workspaceContextService.getWorkspace().roots.map((root, index) => {
return <IAction>{
id: 'folderSettingsTarget' + index,
label: getSettingsTargetName(root, this.workspaceContextService),
checked: this.target instanceof URI && this.target.fsPath === root.fsPath,
label: getSettingsTargetName(ConfigurationTarget.FOLDER, root, this.workspaceContextService),
checked: this.uri instanceof URI && this.uri.fsPath === root.fsPath,
enabled: true,
run: () => this.onTargetClicked(root)
};
......@@ -350,11 +353,8 @@ export class SettingsTargetsWidget extends Widget {
return actions;
}
private onTargetClicked(target: ConfigurationTarget | URI): void {
if (this.target instanceof URI && target instanceof URI && this.target.fsPath === target.fsPath) {
return;
}
if (this.target === target) {
private onTargetClicked(target: URI): void {
if (this.uri.fsPath === target.fsPath) {
return;
}
this._onDidTargetChange.fire(target);
......
......@@ -76,10 +76,10 @@ export interface IPreferencesService {
resolveContent(uri: URI): TPromise<string>;
createPreferencesEditorModel<T>(uri: URI): TPromise<IPreferencesEditorModel<T>>;
openSettings(target: ConfigurationTarget | URI): TPromise<IEditor>;
switchSettings(target: URI | ConfigurationTarget): TPromise<void>;
openGlobalSettings(): TPromise<IEditor>;
openWorkspaceSettings(): TPromise<IEditor>;
openFolderSettings(folder: URI): TPromise<IEditor>;
switchSettings(target: ConfigurationTarget, resource: URI): TPromise<void>;
openGlobalKeybindingSettings(textual: boolean): TPromise<void>;
configureSettingsForLanguage(language: string): void;
......@@ -99,16 +99,15 @@ export interface IKeybindingsEditor extends IEditor {
showConflicts(keybindingEntry: IKeybindingItemEntry): TPromise<any>;
}
export function getSettingsTargetName(target: ConfigurationTarget | URI, workspaceContextService: IWorkspaceContextService): string {
if (target instanceof URI) {
const root = workspaceContextService.getRoot(target);
return root ? paths.basename(root.fsPath) : '';
}
export function getSettingsTargetName(target: ConfigurationTarget, resource: URI, workspaceContextService: IWorkspaceContextService): string {
switch (target) {
case ConfigurationTarget.USER:
return localize('userSettingsTarget', "User Settings");
case ConfigurationTarget.WORKSPACE:
return localize('workspaceSettingsTarget', "Workspace Settings");
case ConfigurationTarget.FOLDER:
const root = workspaceContextService.getRoot(resource);
return root ? paths.basename(root.fsPath) : '';
}
}
......
......@@ -17,6 +17,11 @@ export enum ConfigurationEditingErrorCode {
*/
ERROR_UNKNOWN_KEY,
/**
* Error when trying to write a configuration key that is not supported for provided target.
*/
ERROR_INVALID_KEY,
/**
* Error when trying to write to user target but not supported for provided key.
*/
......@@ -54,7 +59,12 @@ export enum ConfigurationTarget {
/**
* Targets the workspace configuration file for writing. This only works if a workspace is opened.
*/
WORKSPACE
WORKSPACE,
/**
* Targets the folder configuration file for writing. This only works if a workspace is opened.
*/
FOLDER
}
export interface IConfigurationValue {
......
......@@ -18,6 +18,7 @@ import { Edit } from 'vs/base/common/jsonFormatter';
import { IReference } from 'vs/base/common/lifecycle';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Registry } from 'vs/platform/registry/common/platform';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
......@@ -29,7 +30,7 @@ import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS } fr
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationEditingService, ConfigurationEditingErrorCode, ConfigurationEditingError, ConfigurationTarget, IConfigurationValue, IConfigurationEditingOptions } from 'vs/workbench/services/configuration/common/configurationEditing';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message';
import { ICommandService } from 'vs/platform/commands/common/commands';
......@@ -84,7 +85,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService
const checkDirtyConfiguration = !(options.force || options.donotSave);
const saveConfiguration = options.force || !options.donotSave;
return this.resolveAndValidate(target, operation, checkDirtyConfiguration)
return this.resolveAndValidate(target, operation, checkDirtyConfiguration, options.scopes || {})
.then(reference => this.writeToBuffer(reference.object.textEditorModel, operation, saveConfiguration));
}
......@@ -163,10 +164,11 @@ export class ConfigurationEditingService implements IConfigurationEditingService
// API constraints
case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return nls.localize('errorUnknownKey', "Unable to write to the configuration file (Unknown Key)");
case ConfigurationEditingErrorCode.ERROR_INVALID_KEY: return nls.localize('errorInvalidKey', "Unable to write to the configuration file (Invalid Key)");
case ConfigurationEditingErrorCode.ERROR_INVALID_TARGET: return nls.localize('errorInvalidTarget', "Unable to write to the configuration file (Invalid Target)");
// User issues
case ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED: return nls.localize('errorNoWorkspaceOpened', "Unable to write into settings because no folder is opened. Please open a folder first and try again.");
case ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED: return nls.localize('errorNoWorkspaceOpened', "Unable to write into settings because no workspace is opened. Please open a workspace first and try again.");
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: {
if (target === ConfigurationTarget.USER) {
return nls.localize('errorInvalidConfiguration', "Unable to write into settings. Please open **User Settings** to correct errors/warnings in the file and try again.");
......@@ -221,7 +223,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService
return parseErrors.length > 0;
}
private resolveAndValidate(target: ConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean): TPromise<IReference<ITextEditorModel>> {
private resolveAndValidate(target: ConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): TPromise<IReference<ITextEditorModel>> {
// Any key must be a known setting from the registry (unless this is a standalone config)
if (!operation.isWorkspaceStandalone) {
......@@ -236,11 +238,22 @@ export class ConfigurationEditingService implements IConfigurationEditingService
return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_TARGET, target);
}
// Target cannot be workspace if no workspace opened
if (target === ConfigurationTarget.WORKSPACE && !this.contextService.hasWorkspace()) {
// Target cannot be workspace or folder if no workspace opened
if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.FOLDER) && !this.contextService.hasWorkspace()) {
return this.wrapError(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target);
}
if (target === ConfigurationTarget.FOLDER) {
if (!operation.resource) {
return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_TARGET, target);
}
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) {
return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_KEY, target);
}
}
return this.resolveModelReference(operation.resource)
.then(reference => {
const model = reference.object.textEditorModel;
......@@ -266,7 +279,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService
const standaloneConfigurationKeys = Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS);
for (let i = 0; i < standaloneConfigurationKeys.length; i++) {
const key = standaloneConfigurationKeys[i];
const resource = this.getConfigurationFileResource(WORKSPACE_STANDALONE_CONFIGURATIONS[key], overrides.resource);
const resource = this.getConfigurationFileResource(target, WORKSPACE_STANDALONE_CONFIGURATIONS[key], overrides.resource);
// Check for prefix
if (config.key === key) {
......@@ -289,23 +302,34 @@ export class ConfigurationEditingService implements IConfigurationEditingService
return { key, jsonPath, value: config.value, resource: URI.file(this.environmentService.appSettingsPath) };
}
const resource = this.getConfigurationFileResource(WORKSPACE_CONFIG_DEFAULT_PATH, overrides.resource);
const resource = this.getConfigurationFileResource(target, WORKSPACE_CONFIG_DEFAULT_PATH, overrides.resource);
if (workspace && workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath) {
jsonPath = ['settings', ...jsonPath];
}
return { key, jsonPath, value: config.value, resource };
}
private getConfigurationFileResource(relativePath: string, resource: URI): URI {
private getConfigurationFileResource(target: ConfigurationTarget, relativePath: string, resource: URI): URI {
if (target === ConfigurationTarget.USER) {
return URI.file(this.environmentService.appSettingsPath);
}
const workspace = this.contextService.getWorkspace();
if (workspace) {
if (resource) {
const root = this.contextService.getRoot(resource);
if (root) {
return this.toResource(relativePath, root);
if (target === ConfigurationTarget.WORKSPACE) {
return this.contextService.hasMultiFolderWorkspace() ? workspace.configuration : this.toResource(relativePath, workspace.roots[0]);
}
if (target === ConfigurationTarget.FOLDER) {
if (resource) {
const root = this.contextService.getRoot(resource);
if (root) {
return this.toResource(relativePath, root);
}
}
}
return workspace.configuration || this.toResource(relativePath, workspace.roots[0]);
}
return null;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册