提交 bed2921b 编写于 作者: S Sandeep Somavarapu

Support remote user configuration

上级 75bf16eb
......@@ -29,6 +29,8 @@ export interface IConfigurationOverrides {
export const enum ConfigurationTarget {
USER = 1,
USER_LOCAL,
USER_REMOTE,
WORKSPACE,
WORKSPACE_FOLDER,
DEFAULT,
......@@ -37,6 +39,8 @@ export const enum ConfigurationTarget {
export function ConfigurationTargetToString(configurationTarget: ConfigurationTarget) {
switch (configurationTarget) {
case ConfigurationTarget.USER: return 'USER';
case ConfigurationTarget.USER_LOCAL: return 'USER_LOCAL';
case ConfigurationTarget.USER_REMOTE: return 'USER_REMOTE';
case ConfigurationTarget.WORKSPACE: return 'WORKSPACE';
case ConfigurationTarget.WORKSPACE_FOLDER: return 'WORKSPACE_FOLDER';
case ConfigurationTarget.DEFAULT: return 'DEFAULT';
......@@ -88,6 +92,8 @@ export interface IConfigurationService {
inspect<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
userLocal?: T,
userRemote?: T,
workspace?: T,
workspaceFolder?: T,
memory?: T,
......
......@@ -36,6 +36,10 @@ export class ConfigurationModel implements IConfigurationModel {
return this.checkAndFreeze(this._keys);
}
isEmpty(): boolean {
return this._keys.length === 0 || Object.keys(this._contents).length === 0 || this._overrides.length === 0;
}
getValue<V>(section: string | undefined): V {
return section ? getConfigurationValue<any>(this.contents, section) : this.contents;
}
......@@ -283,7 +287,8 @@ export class Configuration {
constructor(
private _defaultConfiguration: ConfigurationModel,
private _userConfiguration: ConfigurationModel,
private _localUserConfiguration: ConfigurationModel,
private _remoteUserConfiguration: ConfigurationModel = new ConfigurationModel(),
private _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),
private _folderConfigurations: ResourceMap<ConfigurationModel> = new ResourceMap<ConfigurationModel>(),
private _memoryConfiguration: ConfigurationModel = new ConfigurationModel(),
......@@ -322,6 +327,8 @@ export class Configuration {
inspect<C>(key: string, overrides: IConfigurationOverrides, workspace: Workspace | undefined): {
default: C,
user: C,
userLocal?: C,
userRemote?: C,
workspace?: C,
workspaceFolder?: C
memory?: C
......@@ -332,7 +339,9 @@ export class Configuration {
const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;
return {
default: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._defaultConfiguration.freeze().getValue(key),
user: overrides.overrideIdentifier ? this._userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._userConfiguration.freeze().getValue(key),
user: overrides.overrideIdentifier ? this.userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.userConfiguration.freeze().getValue(key),
userLocal: overrides.overrideIdentifier ? this.localUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.localUserConfiguration.freeze().getValue(key),
userRemote: overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.remoteUserConfiguration.freeze().getValue(key),
workspace: workspace ? overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._workspaceConfiguration.freeze().getValue(key) : undefined, //Check on workspace exists or not because _workspaceConfiguration is never null
workspaceFolder: folderConfigurationModel ? overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : folderConfigurationModel.freeze().getValue(key) : undefined,
memory: overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).getValue(key) : memoryConfigurationModel.getValue(key),
......@@ -349,7 +358,7 @@ export class Configuration {
const folderConfigurationModel = this.getFolderConfigurationModelForResource(undefined, workspace);
return {
default: this._defaultConfiguration.freeze().keys,
user: this._userConfiguration.freeze().keys,
user: this.userConfiguration.freeze().keys,
workspace: this._workspaceConfiguration.freeze().keys,
workspaceFolder: folderConfigurationModel ? folderConfigurationModel.freeze().keys : []
};
......@@ -361,8 +370,16 @@ export class Configuration {
this._foldersConsolidatedConfigurations.clear();
}
updateUserConfiguration(userConfiguration: ConfigurationModel): void {
this._userConfiguration = userConfiguration;
updateLocalUserConfiguration(localUserConfiguration: ConfigurationModel): void {
this._localUserConfiguration = localUserConfiguration;
this._userConfiguration = null;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
updateRemoteUserConfiguration(remoteUserConfiguration: ConfigurationModel): void {
this._remoteUserConfiguration = remoteUserConfiguration;
this._userConfiguration = null;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
......@@ -379,7 +396,7 @@ export class Configuration {
}
deleteFolderConfiguration(resource: URI): void {
this.folders.delete(resource);
this.folderConfigurations.delete(resource);
this._foldersConsolidatedConfigurations.delete(resource);
}
......@@ -387,15 +404,30 @@ export class Configuration {
return this._defaultConfiguration;
}
get user(): ConfigurationModel {
private _userConfiguration: ConfigurationModel | null;
get userConfiguration(): ConfigurationModel {
if (!this._userConfiguration) {
this._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration);
if (this._freeze) {
this._userConfiguration.freeze();
}
}
return this._userConfiguration;
}
get workspace(): ConfigurationModel {
get localUserConfiguration(): ConfigurationModel {
return this._localUserConfiguration;
}
get remoteUserConfiguration(): ConfigurationModel {
return this._remoteUserConfiguration;
}
get workspaceConfiguration(): ConfigurationModel {
return this._workspaceConfiguration;
}
protected get folders(): ResourceMap<ConfigurationModel> {
protected get folderConfigurations(): ResourceMap<ConfigurationModel> {
return this._folderConfigurations;
}
......@@ -423,7 +455,7 @@ export class Configuration {
private getWorkspaceConsolidatedConfiguration(): ConfigurationModel {
if (!this._workspaceConsolidatedConfiguration) {
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this._userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
if (this._freeze) {
this._workspaceConfiguration = this._workspaceConfiguration.freeze();
}
......@@ -467,9 +499,9 @@ export class Configuration {
keys: this._defaultConfiguration.keys
},
user: {
contents: this._userConfiguration.contents,
overrides: this._userConfiguration.overrides,
keys: this._userConfiguration.keys
contents: this.userConfiguration.contents,
overrides: this.userConfiguration.overrides,
keys: this.userConfiguration.keys
},
workspace: {
contents: this._workspaceConfiguration.contents,
......@@ -497,8 +529,8 @@ export class Configuration {
};
addKeys(keys.user);
addKeys(keys.workspace);
for (const resource of this.folders.keys()) {
addKeys(this.folders.get(resource)!.keys);
for (const resource of this.folderConfigurations.keys()) {
addKeys(this.folderConfigurations.get(resource)!.keys);
}
return all;
}
......
......@@ -91,10 +91,10 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
}
private onDidChangeUserConfiguration(userConfigurationModel: ConfigurationModel): void {
const { added, updated, removed } = compare(this._configuration.user, userConfigurationModel);
const { added, updated, removed } = compare(this._configuration.localUserConfiguration, userConfigurationModel);
const changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
this._configuration.updateUserConfiguration(userConfigurationModel);
this._configuration.updateLocalUserConfiguration(userConfigurationModel);
this.trigger(changedKeys, ConfigurationTarget.USER);
}
}
......@@ -113,7 +113,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
case ConfigurationTarget.DEFAULT:
return this._configuration.defaults.contents;
case ConfigurationTarget.USER:
return this._configuration.user.contents;
return this._configuration.localUserConfiguration.contents;
}
return {};
}
......
......@@ -56,6 +56,8 @@ export class TestConfigurationService implements IConfigurationService {
public inspect<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
userLocal?: T,
userRemote?: T,
workspace?: T,
workspaceFolder?: T
value: T,
......
......@@ -263,7 +263,7 @@ export class ExtHostConfigProvider {
result.set(URI.parse(key), ExtHostConfigProvider.parseConfigurationModel(data.folders[key]));
return result;
}, new ResourceMap<ConfigurationModel>());
return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), false);
return new Configuration(defaultConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), false);
}
private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel {
......
......@@ -9,7 +9,7 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
import { IWindowConfiguration, IWindowService } from 'vs/platform/windows/common/windows';
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext } from 'vs/workbench/common/editor';
import { IsMacContext, IsLinuxContext, IsWindowsContext, HasMacNativeTabsContext, IsDevelopmentContext, SupportsWorkspacesContext, SupportsOpenFileFolderContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys';
import { IsMacContext, IsLinuxContext, IsWindowsContext, HasMacNativeTabsContext, IsDevelopmentContext, SupportsWorkspacesContext, SupportsOpenFileFolderContext, WorkbenchStateContext, WorkspaceFolderCountContext, IsRemoteContext } from 'vs/workbench/common/contextkeys';
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -90,6 +90,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
IsLinuxContext.bindTo(this.contextKeyService);
IsWindowsContext.bindTo(this.contextKeyService);
IsRemoteContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority);
// macOS Native Tabs
const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig && windowConfig.window && windowConfig.window.nativeTabs);
......
......@@ -9,6 +9,7 @@ import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform';
export const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh);
export const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux);
export const IsWindowsContext = new RawContextKey<boolean>('isWindows', isWindows);
export const IsRemoteContext = new RawContextKey<boolean>('isRemote', false);
export const HasMacNativeTabsContext = new RawContextKey<boolean>('hasMacNativeTabs', false);
......
......@@ -88,6 +88,24 @@ export class OpenGlobalSettingsAction extends Action {
}
}
export class OpenRemoteSettingsAction extends Action {
static readonly ID = 'workbench.action.openRemoteSettings';
static readonly LABEL = nls.localize('openRemoteSettings', "Open User Settings (Remote)");
constructor(
id: string,
label: string,
@IPreferencesService private readonly preferencesService: IPreferencesService,
) {
super(id, label);
}
run(event?: any): Promise<any> {
return this.preferencesService.openRemoteSettings();
}
}
export class OpenGlobalKeybindingsAction extends Action {
static readonly ID = 'workbench.action.openGlobalKeybindings';
......
......@@ -13,7 +13,7 @@ import * as nls from 'vs/nls';
import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchStateContext } from 'vs/workbench/common/contextkeys';
import { WorkbenchStateContext, IsRemoteContext } from 'vs/workbench/common/contextkeys';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
......@@ -28,7 +28,7 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchCo
import { EditorInput, Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
import { ResourceContextKey } from 'vs/workbench/common/resources';
import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor';
import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL, OpenRemoteSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor';
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution';
......@@ -553,6 +553,18 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
group: '1_keyboard_preferences_actions'
});
CommandsRegistry.registerCommand(OpenRemoteSettingsAction.ID, serviceAccessor => {
serviceAccessor.get(IInstantiationService).createInstance(OpenRemoteSettingsAction, OpenRemoteSettingsAction.ID, OpenRemoteSettingsAction.LABEL).run();
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: OpenRemoteSettingsAction.ID,
title: { value: OpenRemoteSettingsAction.LABEL, original: 'Preferences: Open Remote Settings' },
category: nls.localize('preferencesCategory', "Preferences")
},
when: IsRemoteContext
});
abstract class SettingsCommand extends Command {
protected getPreferencesEditor(accessor: ServicesAccessor): PreferencesEditor | SettingsEditor2 | null {
......
......@@ -12,7 +12,7 @@ import { ElectronWindow } from 'vs/workbench/electron-browser/window';
import { setZoomLevel, setZoomFactor, setFullscreen } from 'vs/base/browser/browser';
import { domContentLoaded, addDisposableListener, EventType, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { onUnexpectedError } from 'vs/base/common/errors';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { isLinux, isMacintosh, isWindows, OperatingSystem } from 'vs/base/common/platform';
import { URI as uri } from 'vs/base/common/uri';
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
......@@ -46,6 +46,8 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
import { FileService2 } from 'vs/workbench/services/files2/common/fileService2';
import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/workbench/services/files2/node/diskFileSystemProvider';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/node/remoteAgentFileSystemChannel';
class CodeRendererMain extends Disposable {
......@@ -160,11 +162,6 @@ class CodeRendererMain extends Disposable {
private initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> {
const serviceCollection = new ServiceCollection();
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
// CONTRIBUTE IT VIA WORKBENCH.MAIN.TS AND registerSingleton().
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Main Process
const mainProcessService = this._register(new MainProcessService(this.configuration.windowId));
serviceCollection.set(IMainProcessService, mainProcessService);
......@@ -192,8 +189,19 @@ class CodeRendererMain extends Disposable {
const remoteAgentService = new RemoteAgentService(this.configuration, environmentService, remoteAuthorityResolverService);
serviceCollection.set(IRemoteAgentService, remoteAgentService);
const connection = remoteAgentService.getConnection();
if (connection) {
const channel = connection.getChannel<IChannel>(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
const fileSystemProvider = new RemoteExtensionsFileSystemProvider(channel);
fileService.registerProvider('vscode-remote', fileSystemProvider);
remoteAgentService.getEnvironment().then(remoteAgentEnvironment => {
const isCaseSensitive = !!(remoteAgentEnvironment && remoteAgentEnvironment.os === OperatingSystem.Linux);
fileSystemProvider.setCaseSensitive(isCaseSensitive);
});
}
return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([
this.createWorkspaceService(payload, environmentService, logService).then(service => {
this.createWorkspaceService(payload, environmentService, remoteAgentService, logService).then(service => {
// Workspace
serviceCollection.set(IWorkspaceContextService, service);
......@@ -284,8 +292,8 @@ class CodeRendererMain extends Disposable {
}, error => onUnexpectedError(error));
}
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, logService: ILogService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService(environmentService);
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService(this.configuration, environmentService, remoteAgentService);
return workspaceService.initialize(payload).then(() => workspaceService, error => {
onUnexpectedError(error);
......
......@@ -28,6 +28,7 @@ import { ITextModel } from 'vs/editor/common/model';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
export const enum ConfigurationEditingErrorCode {
......@@ -120,6 +121,7 @@ export class ConfigurationEditingService {
public _serviceBrand: any;
private queue: Queue<void>;
private remoteSettingsResource: URI | null;
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService,
......@@ -130,9 +132,15 @@ export class ConfigurationEditingService {
@ITextFileService private readonly textFileService: ITextFileService,
@INotificationService private readonly notificationService: INotificationService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IEditorService private readonly editorService: IEditorService
@IEditorService private readonly editorService: IEditorService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
this.queue = new Queue<void>();
remoteAgentService.getEnvironment().then(environment => {
if (environment) {
this.remoteSettingsResource = environment.appSettingsPath;
}
});
}
writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise<void> {
......@@ -458,7 +466,7 @@ export class ConfigurationEditingService {
if (config.key) {
const standaloneConfigurationKeys = Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS);
for (const key of standaloneConfigurationKeys) {
const resource = this.getConfigurationFileResource(target, WORKSPACE_STANDALONE_CONFIGURATIONS[key], overrides.resource);
const resource = this.getConfigurationFileResource(target, config, WORKSPACE_STANDALONE_CONFIGURATIONS[key], overrides.resource);
// Check for prefix
if (config.key === key) {
......@@ -478,10 +486,10 @@ export class ConfigurationEditingService {
let key = config.key;
let jsonPath = overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier), key] : [key];
if (target === ConfigurationTarget.USER) {
return { key, jsonPath, value: config.value, resource: URI.file(this.environmentService.appSettingsPath), target };
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, config, '', null)), target };
}
const resource = this.getConfigurationFileResource(target, FOLDER_SETTINGS_PATH, overrides.resource);
const resource = this.getConfigurationFileResource(target, config, FOLDER_SETTINGS_PATH, overrides.resource);
if (this.isWorkspaceConfigurationResource(resource)) {
jsonPath = ['settings', ...jsonPath];
}
......@@ -493,8 +501,17 @@ export class ConfigurationEditingService {
return !!(workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath);
}
private getConfigurationFileResource(target: ConfigurationTarget, relativePath: string, resource: URI | null | undefined): URI | null {
private getConfigurationFileResource(target: ConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null {
if (target === ConfigurationTarget.USER_LOCAL) {
return URI.file(this.environmentService.appSettingsPath);
}
if (target === ConfigurationTarget.USER_REMOTE) {
return this.remoteSettingsResource;
}
if (target === ConfigurationTarget.USER) {
if (this.configurationService.inspect(config.key).userRemote !== undefined) {
return this.remoteSettingsResource;
}
return URI.file(this.environmentService.appSettingsPath);
}
......
......@@ -131,13 +131,14 @@ export class Configuration extends BaseConfiguration {
constructor(
defaults: ConfigurationModel,
user: ConfigurationModel,
localUser: ConfigurationModel,
remoteUser: ConfigurationModel,
workspaceConfiguration: ConfigurationModel,
folders: ResourceMap<ConfigurationModel>,
memoryConfiguration: ConfigurationModel,
memoryConfigurationByResource: ResourceMap<ConfigurationModel>,
private readonly _workspace?: Workspace) {
super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource);
super(defaults, localUser, remoteUser, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource);
}
getValue(key: string | undefined, overrides: IConfigurationOverrides = {}): any {
......@@ -164,17 +165,26 @@ export class Configuration extends BaseConfiguration {
return super.keys(this._workspace);
}
compareAndUpdateUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.user, user);
compareAndUpdateLocalUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.localUserConfiguration, user);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
super.updateUserConfiguration(user);
super.updateLocalUserConfiguration(user);
}
return new ConfigurationChangeEvent().change(changedKeys);
}
compareAndUpdateRemoteUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.remoteUserConfiguration, user);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
super.updateRemoteUserConfiguration(user);
}
return new ConfigurationChangeEvent().change(changedKeys);
}
compareAndUpdateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.workspace, workspaceConfiguration);
const { added, updated, removed } = compare(this.workspaceConfiguration, workspaceConfiguration);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
super.updateWorkspaceConfiguration(workspaceConfiguration);
......@@ -183,7 +193,7 @@ export class Configuration extends BaseConfiguration {
}
compareAndUpdateFolderConfiguration(resource: URI, folderConfiguration: ConfigurationModel): ConfigurationChangeEvent {
const currentFolderConfiguration = this.folders.get(resource);
const currentFolderConfiguration = this.folderConfigurations.get(resource);
if (currentFolderConfiguration) {
const { added, updated, removed } = compare(currentFolderConfiguration, folderConfiguration);
let changedKeys = [...added, ...updated, ...removed];
......@@ -202,7 +212,7 @@ export class Configuration extends BaseConfiguration {
// Do not remove workspace configuration
return new ConfigurationChangeEvent();
}
const folderConfig = this.folders.get(folder);
const folderConfig = this.folderConfigurations.get(folder);
if (!folderConfig) {
throw new Error('Unknown folder');
}
......
......@@ -13,7 +13,7 @@ import * as collections from 'vs/base/common/collections';
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler, Delayer } from 'vs/base/common/async';
import { FileChangeType, FileChangesEvent, IContent, IFileService } from 'vs/platform/files/common/files';
import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
......@@ -25,7 +25,155 @@ import { extname, join } from 'vs/base/common/path';
import { equals } from 'vs/base/common/objects';
import { Schemas } from 'vs/base/common/network';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IConfigurationModel, compare } from 'vs/platform/configuration/common/configuration';
export class RemoteUserConfiguration extends Disposable {
private readonly _cachedConfiguration: CachedUserConfiguration;
private _userConfiguration: FileServiceBasedUserConfiguration | CachedUserConfiguration;
private readonly _onDidUpdateConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidUpdateConfiguration.event;
constructor(
remoteAuthority: string,
environmentService: IEnvironmentService
) {
super();
this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, environmentService);
}
load(): Promise<ConfigurationModel> {
return this._userConfiguration.loadConfiguration();
}
async adopt(configurationResource: URI | null, fileService: IFileService): Promise<ConfigurationModel | null> {
if (this._userConfiguration instanceof CachedUserConfiguration) {
const oldConfigurationModel = this._userConfiguration.getConfigurationModel();
let newConfigurationModel = new ConfigurationModel();
if (configurationResource) {
this._userConfiguration = new FileServiceBasedUserConfiguration(configurationResource, oldConfigurationModel, fileService);
this._register(this._userConfiguration.onDidChange(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
newConfigurationModel = await this._userConfiguration.loadConfiguration();
}
const { added, updated, removed } = compare(oldConfigurationModel, newConfigurationModel);
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
this.updateCache(newConfigurationModel);
return newConfigurationModel;
}
}
return null;
}
private onDidUserConfigurationChange(configurationModel: ConfigurationModel): void {
this.updateCache(configurationModel);
this._onDidUpdateConfiguration.fire(configurationModel);
}
private updateCache(configurationModel: ConfigurationModel): Promise<void> {
return this._cachedConfiguration.updateConfiguration(configurationModel);
}
}
class FileServiceBasedUserConfiguration extends Disposable {
private readonly reloadConfigurationScheduler: RunOnceScheduler;
protected readonly _onDidChange: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChange: Event<ConfigurationModel> = this._onDidChange.event;
constructor(
private readonly configurationResource: URI,
private configurationModel: ConfigurationModel,
private readonly fileService: IFileService
) {
super();
this._register(fileService.onFileChanges(e => this.handleFileEvents(e)));
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configurationModel => this._onDidChange.fire(configurationModel)), 50));
this.fileService.watchFileChanges(this.configurationResource);
this._register(toDisposable(() => this.fileService.unwatchFileChanges(this.configurationResource)));
}
loadConfiguration(): Promise<ConfigurationModel> {
return this.fileService.resolveContent(this.configurationResource)
.then(content => content.value, e => {
errors.onUnexpectedError(e);
return '';
}).then(content => {
const parser = new ConfigurationModelParser(this.configurationResource.toString());
parser.parse(content);
this.configurationModel = parser.configurationModel;
return this.configurationModel;
});
}
private handleFileEvents(event: FileChangesEvent): void {
const events = event.changes;
let affectedByChanges = false;
// Find changes that affect workspace file
for (let i = 0, len = events.length; i < len && !affectedByChanges; i++) {
affectedByChanges = resources.isEqual(this.configurationResource, events[i].resource);
}
if (affectedByChanges) {
this.reloadConfigurationScheduler.schedule();
}
}
}
class CachedUserConfiguration extends Disposable {
private readonly _onDidChange: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChange: Event<ConfigurationModel> = this._onDidChange.event;
private readonly cachedFolderPath: string;
private readonly cachedConfigurationPath: string;
private configurationModel: ConfigurationModel;
constructor(
remoteAuthority: string,
private environmentService: IEnvironmentService
) {
super();
this.cachedFolderPath = join(this.environmentService.userDataPath, 'CachedConfigurations', 'user', remoteAuthority);
this.cachedConfigurationPath = join(this.cachedFolderPath, 'configuration.json');
this.configurationModel = new ConfigurationModel();
}
getConfigurationModel(): ConfigurationModel {
return this.configurationModel;
}
loadConfiguration(): Promise<ConfigurationModel> {
return pfs.readFile(this.cachedConfigurationPath)
.then(content => content.toString(), () => '')
.then(content => {
try {
const parsed: IConfigurationModel = JSON.parse(content);
this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides);
} catch (e) {
}
return this.configurationModel;
});
}
updateConfiguration(configurationModel: ConfigurationModel): Promise<void> {
const raw = JSON.stringify(configurationModel.toJSON());
return this.createCachedFolder().then(created => {
if (created) {
return configurationModel.keys.length ? pfs.writeFile(this.cachedConfigurationPath, raw) : pfs.rimraf(this.cachedFolderPath);
}
return undefined;
});
}
private createCachedFolder(): Promise<boolean> {
return Promise.resolve(pfs.exists(this.cachedFolderPath))
.then(undefined, () => false)
.then(exists => exists ? exists : pfs.mkdirp(this.cachedFolderPath).then(() => true, () => false));
}
}
export interface IWorkspaceIdentifier {
id: string;
......
......@@ -28,7 +28,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import product from 'vs/platform/product/node/product';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { WorkspaceConfiguration, FolderConfiguration } from 'vs/workbench/services/configuration/node/configuration';
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration } from 'vs/workbench/services/configuration/node/configuration';
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
import { UserConfiguration } from 'vs/platform/configuration/node/configuration';
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
......@@ -36,6 +36,8 @@ import { localize } from 'vs/nls';
import { isEqual, dirname } from 'vs/base/common/resources';
import { mark } from 'vs/base/common/performance';
import { Schemas } from 'vs/base/common/network';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService {
......@@ -45,7 +47,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
private completeWorkspaceBarrier: Barrier;
private _configuration: Configuration;
private defaultConfiguration: DefaultConfigurationModel;
private userConfiguration: UserConfiguration;
private localUserConfiguration: UserConfiguration;
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
private workspaceConfiguration: WorkspaceConfiguration;
private cachedFolderConfigs: ResourceMap<FolderConfiguration>;
......@@ -67,14 +70,18 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
private configurationEditingService: ConfigurationEditingService;
private jsonEditingService: JSONEditingService;
constructor(private environmentService: IEnvironmentService, private workspaceSettingsRootFolder: string = FOLDER_CONFIG_FOLDER_NAME) {
constructor(configuration: IWindowConfiguration, private environmentService: IEnvironmentService, private remoteAgentService: IRemoteAgentService, private workspaceSettingsRootFolder: string = FOLDER_CONFIG_FOLDER_NAME) {
super();
this.completeWorkspaceBarrier = new Barrier();
this.defaultConfiguration = new DefaultConfigurationModel();
this.userConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
this.localUserConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
if (configuration.remoteAuthority) {
this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(configuration.remoteAuthority, environmentService));
this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration)));
}
this.workspaceConfiguration = this._register(new WorkspaceConfiguration(environmentService));
this._register(this.userConfiguration.onDidChangeConfiguration(userConfiguration => this.onUserConfigurationChanged(userConfiguration)));
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged()));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidSchemaChange(e => this.registerConfigurationSchemas()));
......@@ -254,8 +261,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
return this.reloadWorkspaceFolderConfiguration(folder, key);
}
return this.reloadUserConfiguration()
.then(userConfigurationModel => this.reloadWorkspaceConfiguration()
.then(() => this.loadConfiguration(userConfigurationModel)));
.then(({ local, remote }) => this.reloadWorkspaceConfiguration()
.then(() => this.loadConfiguration(local, remote)));
}
inspect<T>(key: string, overrides?: IConfigurationOverrides): {
......@@ -306,6 +313,15 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
}
this.releaseWorkspaceBarrier();
});
if (this.remoteUserConfiguration) {
this.remoteAgentService.getEnvironment()
.then(environment => this.remoteUserConfiguration!.adopt(environment ? environment.appSettingsPath : null, fileService)
.then(changedModel => {
if (changedModel) {
this.onRemoteUserConfigurationChanged(changedModel);
}
}));
}
}
acquireInstantiationService(instantiationService: IInstantiationService): void {
......@@ -425,12 +441,18 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
private initializeConfiguration(): Promise<void> {
this.registerConfigurationSchemas();
return this.userConfiguration.initialize()
.then(userConfigurationModel => this.loadConfiguration(userConfigurationModel));
return this.initializeUserConfiguration()
.then(({ local, remote }) => this.loadConfiguration(local, remote));
}
private initializeUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
return Promise.all([this.localUserConfiguration.initialize(), this.remoteUserConfiguration ? this.remoteUserConfiguration.load() : Promise.resolve(new ConfigurationModel())])
.then(([local, remote]) => ({ local, remote }));
}
private reloadUserConfiguration(key?: string): Promise<ConfigurationModel> {
return this.userConfiguration.reload();
private reloadUserConfiguration(key?: string): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
return Promise.all([this.localUserConfiguration.reload(), this.remoteUserConfiguration ? this.remoteUserConfiguration.load() : Promise.resolve(new ConfigurationModel())])
.then(([local, remote]) => ({ local, remote }));
}
private reloadWorkspaceConfiguration(key?: string): Promise<void> {
......@@ -448,7 +470,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
return this.onWorkspaceFolderConfigurationChanged(folder, key);
}
private loadConfiguration(userConfigurationModel: ConfigurationModel): Promise<void> {
private loadConfiguration(userConfigurationModel: ConfigurationModel, remoteUserConfigurationModel: ConfigurationModel): Promise<void> {
// reset caches
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
......@@ -461,7 +483,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
const currentConfiguration = this._configuration;
this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
if (currentConfiguration) {
const changedKeys = this._configuration.compare(currentConfiguration);
......@@ -528,8 +550,13 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
}
}
private onUserConfigurationChanged(userConfiguration: ConfigurationModel): void {
const keys = this._configuration.compareAndUpdateUserConfiguration(userConfiguration);
private onLocalUserConfigurationChanged(userConfiguration: ConfigurationModel): void {
const keys = this._configuration.compareAndUpdateLocalUserConfiguration(userConfiguration);
this.triggerConfigurationChange(keys, ConfigurationTarget.USER);
}
private onRemoteUserConfigurationChanged(userConfiguration: ConfigurationModel): void {
const keys = this._configuration.compareAndUpdateRemoteUserConfiguration(userConfiguration);
this.triggerConfigurationChange(keys, ConfigurationTarget.USER);
}
......@@ -670,9 +697,9 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
case ConfigurationTarget.DEFAULT:
return this._configuration.defaults.contents;
case ConfigurationTarget.USER:
return this._configuration.user.contents;
return this._configuration.userConfiguration.contents;
case ConfigurationTarget.WORKSPACE:
return this._configuration.workspace.contents;
return this._configuration.workspaceConfiguration.contents;
}
return {};
}
......
......@@ -201,7 +201,7 @@ suite('AllKeysConfigurationChangeEvent', () => {
test('changeEvent affects keys for any resource', () => {
const configuraiton = new Configuration(new ConfigurationModel({}, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']),
new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), null!);
new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), null!);
let testObject = new AllKeysConfigurationChangeEvent(configuraiton, ConfigurationTarget.USER, null);
assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']);
......
......@@ -36,6 +36,9 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/workbench/services/commands/common/commandService';
import { URI } from 'vs/base/common/uri';
import { createHash } from 'crypto';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
class SettingsTestEnvironmentService extends EnvironmentService {
......@@ -99,7 +102,9 @@ suite('ConfigurationEditingService', () => {
instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
instantiationService.stub(IEnvironmentService, environmentService);
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => {
instantiationService.stub(IConfigurationService, workspaceService);
......
......@@ -37,6 +37,10 @@ import { Schemas } from 'vs/base/common/network';
import { originalFSPath } from 'vs/base/common/resources';
import { isLinux } from 'vs/base/common/platform';
import { IWorkspaceIdentifier } from 'vs/workbench/services/configuration/node/configuration';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
class SettingsTestEnvironmentService extends EnvironmentService {
......@@ -95,7 +99,7 @@ suite('WorkspaceContextService - Folder', () => {
workspaceResource = folderDir;
const globalSettingsFile = path.join(parentDir, 'settings.json');
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
workspaceContextService = new WorkspaceService(environmentService);
workspaceContextService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, new RemoteAgentService(<IWindowConfiguration>{}, environmentService, new RemoteAuthorityResolverService()));
return (<WorkspaceService>workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir)));
});
});
......@@ -153,10 +157,12 @@ suite('WorkspaceContextService - Workspace', () => {
parentResource = parentDir;
instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json'));
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
instantiationService = <TestInstantiationService>workbenchInstantiationService();
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
......@@ -207,10 +213,12 @@ suite('WorkspaceContextService - Workspace Editing', () => {
parentResource = parentDir;
instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json'));
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
instantiationService = <TestInstantiationService>workbenchInstantiationService();
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
......@@ -473,7 +481,9 @@ suite('WorkspaceService - Initialization', () => {
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
......@@ -728,7 +738,9 @@ suite('WorkspaceConfigurationService - Folder', () => {
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
......@@ -1014,10 +1026,12 @@ suite('WorkspaceConfigurationService-Multiroot', () => {
parentResource = parentDir;
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json'));
const workspaceService = new WorkspaceService(environmentService);
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {});
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const workspaceService = new WorkspaceService(<IWindowConfiguration>{}, environmentService, remoteAgentService);
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
......
......@@ -36,6 +36,7 @@ import { DEFAULT_SETTINGS_EDITOR_SETTING, FOLDER_SETTINGS_PATH, getSettingsTarge
import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
import { defaultKeybindingsContents, DefaultKeybindingsEditorModel, DefaultSettings, DefaultSettingsEditorModel, Settings2EditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel, DefaultRawSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
const emptyEditableSettingsContent = '{\n}';
......@@ -69,7 +70,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic
@IModelService private readonly modelService: IModelService,
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
@IModeService private readonly modeService: IModeService,
@ILabelService private readonly labelService: ILabelService
@ILabelService private readonly labelService: ILabelService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
) {
super();
// The default keybindings.json updates based on keyboard layouts, so here we make sure
......@@ -210,6 +212,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic
this.openOrSwitchSettings2(ConfigurationTarget.USER, undefined, options, group);
}
async openRemoteSettings(): Promise<IEditor | null> {
const environemnt = await this.remoteAgentService.getEnvironment();
if (environemnt) {
await this.createIfNotExists(environemnt.appSettingsPath, emptyEditableSettingsContent);
return this.editorService.openEditor({ resource: environemnt.appSettingsPath, options: { pinned: true, revealIfOpened: true } });
}
return null;
}
openWorkspaceSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor | null> {
jsonEditor = typeof jsonEditor === 'undefined' ?
this.configurationService.getValue('workbench.settings.editor') === 'json' :
......
......@@ -201,6 +201,7 @@ export interface IPreferencesService {
openRawDefaultSettings(): Promise<IEditor | null>;
openSettings(jsonEditor?: boolean): Promise<IEditor | null>;
openGlobalSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor | null>;
openRemoteSettings(): Promise<IEditor | null>;
openWorkspaceSettings(jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor | null>;
openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise<IEditor | null>;
switchSettings(target: ConfigurationTarget, resource: URI, jsonEditor?: boolean): Promise<void>;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册