Merge from vscode 5b9869eb02fa4c96205a74d05cad9164dfd06d60 (#5607)

This commit is contained in:
Anthony Dresser
2019-05-24 12:20:30 -07:00
committed by GitHub
parent 361ada4963
commit bcc449b524
126 changed files with 3096 additions and 2255 deletions

View File

@@ -12,7 +12,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, IConfigurationFileService, MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, IConfigurationFileService, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
@@ -45,7 +45,7 @@ export class RemoteUserConfiguration extends Disposable {
this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, configurationCache);
remoteAgentService.getEnvironment().then(async environment => {
if (environment) {
const userConfiguration = this._register(new UserConfiguration(environment.settingsPath, MACHINE_SCOPES, this._configurationFileService));
const userConfiguration = this._register(new UserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._configurationFileService));
this._register(userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
this._userConfigurationInitializationPromise = userConfiguration.initialize();
const configurationModel = await this._userConfigurationInitializationPromise;

View File

@@ -15,7 +15,7 @@ import { isLinux } from 'vs/base/common/platform';
import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, IConfigurationFileService, machineSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, IConfigurationFileService, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
@@ -74,7 +74,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
this.defaultConfiguration = new DefaultConfigurationModel();
this.configurationCache = configurationCache;
if (userSettingsResource) {
this.localUserConfiguration = this._register(new UserConfiguration(userSettingsResource, undefined, configurationFileService));
this.localUserConfiguration = this._register(new UserConfiguration(userSettingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, configurationFileService));
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
}
if (remoteAuthority) {
@@ -515,14 +515,16 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
}, {});
};
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings"));
const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user settings"));
const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings"));
const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user Settings"));
const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user Settings"));
const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' } : allSettingsSchema;
const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema);
jsonRegistry.registerSchema(userSettingsSchemaId, allSettingsSchema);
jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema);
jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema);
if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) {

View File

@@ -20,7 +20,8 @@ export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace';
export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
export const launchSchemaId = 'vscode://schemas/launch';
export const MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE];

View File

@@ -268,6 +268,14 @@ suite('WorkspaceConfigurationService - Remote Folder', () => {
// return promise;
// });
test('machine settings in local user settings does not override defaults', async () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.machineSetting": "globalValue" }');
registerRemoteFileSystemProvider();
resolveRemoteEnvironment();
await initialize();
assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet');
});
});
function getWorkspaceId(configPath: URI): string {

View File

@@ -172,7 +172,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService
}
}
private runAction(actionRunner: IActionRunner, actionToRun: IAction, delegate: IContextMenuDelegate, event: IContextMenuEvent): void {
private async runAction(actionRunner: IActionRunner, actionToRun: IAction, delegate: IContextMenuDelegate, event: IContextMenuEvent): Promise<void> {
/* __GDPR__
"workbenchActionExecuted" : {
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
@@ -182,9 +182,15 @@ class NativeContextMenuService extends Disposable implements IContextMenuService
this.telemetryService.publicLog('workbenchActionExecuted', { id: actionToRun.id, from: 'contextMenu' });
const context = delegate.getActionsContext ? delegate.getActionsContext(event) : event;
const res = actionRunner.run(actionToRun, context) || Promise.resolve(null);
res.then(undefined, e => this.notificationService.error(e));
const runnable = actionRunner.run(actionToRun, context);
if (runnable) {
try {
await runnable;
} catch (error) {
this.notificationService.error(error);
}
}
}
}

View File

@@ -78,17 +78,16 @@ class NativeDialogService implements IDialogService {
sharedProcessService.registerChannel('dialog', new DialogChannel(this));
}
confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
this.logService.trace('DialogService#confirm', confirmation.message);
const { options, buttonIndexMap } = this.massageMessageBoxOptions(this.getConfirmOptions(confirmation));
return this.windowService.showMessageBox(options).then(result => {
return {
confirmed: buttonIndexMap[result.button] === 0 ? true : false,
checkboxChecked: result.checkboxChecked
};
});
const result = await this.windowService.showMessageBox(options);
return {
confirmed: buttonIndexMap[result.button] === 0 ? true : false,
checkboxChecked: result.checkboxChecked
};
}
private getConfirmOptions(confirmation: IConfirmation): Electron.MessageBoxOptions {
@@ -128,7 +127,7 @@ class NativeDialogService implements IDialogService {
return opts;
}
show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise<number> {
async show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise<number> {
this.logService.trace('DialogService#show', message);
const { options, buttonIndexMap } = this.massageMessageBoxOptions({
@@ -139,7 +138,8 @@ class NativeDialogService implements IDialogService {
detail: dialogOptions ? dialogOptions.detail : undefined
});
return this.windowService.showMessageBox(options).then(result => buttonIndexMap[result.button]);
const result = await this.windowService.showMessageBox(options);
return buttonIndexMap[result.button];
}
private massageMessageBoxOptions(options: Electron.MessageBoxOptions): IMassagedMessageBoxOptions {

View File

@@ -62,17 +62,16 @@ export class CodeEditorService extends CodeEditorServiceImpl {
return this.doOpenCodeEditor(input, source, sideBySide);
}
private doOpenCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> {
return this.editorService.openEditor(input, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(control => {
if (control) {
const widget = control.getControl();
if (isCodeEditor(widget)) {
return widget;
}
private async doOpenCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> {
const control = await this.editorService.openEditor(input, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
if (control) {
const widget = control.getControl();
if (isCodeEditor(widget)) {
return widget;
}
}
return null;
});
return null;
}
}

View File

@@ -331,7 +331,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
openEditors(editors: IEditorInputWithOptions[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise<IEditor[]>;
openEditors(editors: IResourceEditor[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise<IEditor[]>;
openEditors(editors: Array<IEditorInputWithOptions | IResourceEditor>, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise<IEditor[]> {
async openEditors(editors: Array<IEditorInputWithOptions | IResourceEditor>, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise<IEditor[]> {
// Convert to typed editors and options
const typedEditors: IEditorInputWithOptions[] = [];
@@ -367,7 +367,9 @@ export class EditorService extends Disposable implements EditorServiceImpl {
result.push(group.openEditors(editorsWithOptions));
});
return Promise.all(result).then(editors => coalesce(editors));
const openedEditors = await Promise.all(result);
return coalesce(openedEditors);
}
//#endregion

View File

@@ -6,9 +6,48 @@
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { isUIExtension as _isUIExtension } from 'vs/platform/extensions/node/extensionsUtil';
import { getGalleryExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import product from 'vs/platform/product/node/product';
export function isUIExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean {
const uiExtensionPoints = ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').map(e => e.name);
return _isUIExtension(manifest, uiExtensionPoints, configurationService);
const uiContributions = ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').map(e => e.name);
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
const extensionKind = getExtensionKind(manifest, configurationService);
switch (extensionKind) {
case 'ui': return true;
case 'workspace': return false;
default: {
// Tagged as UI extension in product
if (isNonEmptyArray(product.uiExtensions) && product.uiExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) {
return true;
}
// Not an UI extension if it has main
if (manifest.main) {
return false;
}
// Not an UI extension if it has dependencies or an extension pack
if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) {
return false;
}
if (manifest.contributes) {
// Not an UI extension if it has no ui contributions
if (!uiContributions.length || Object.keys(manifest.contributes).some(contribution => uiContributions.indexOf(contribution) === -1)) {
return false;
}
}
return true;
}
}
}
function getExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): string | undefined {
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
const configuredExtensionKinds = configurationService.getValue<{ [key: string]: string }>('remote.extensionKind') || {};
for (const id of Object.keys(configuredExtensionKinds)) {
if (areSameExtensions({ id: extensionId }, { id })) {
return configuredExtensionKinds[id];
}
}
return manifest.extensionKind;
}

View File

@@ -5,7 +5,8 @@
import { IDiskFileChange, normalizeFileChanges } from 'vs/workbench/services/files/node/watcher/watcher';
import { Disposable } from 'vs/base/common/lifecycle';
import { statLink, readlink } from 'vs/base/node/pfs';
import { statLink } from 'vs/base/node/pfs';
import { realpath } from 'vs/base/node/extpath';
import { watchFolder, watchFile, CHANGE_BUFFER_DELAY } from 'vs/base/node/watcher';
import { FileChangeType } from 'vs/platform/files/common/files';
import { ThrottledDelayer } from 'vs/base/common/async';
@@ -40,7 +41,7 @@ export class FileWatcher extends Disposable {
let pathToWatch = this.path;
if (isSymbolicLink) {
try {
pathToWatch = await readlink(pathToWatch);
pathToWatch = await realpath(pathToWatch);
} catch (error) {
this.onError(error);
}

View File

@@ -71,9 +71,9 @@ export class IntegrityServiceImpl implements IIntegrityService {
this.isPure().then(r => {
if (r.isPure) {
// all is good
return;
return; // all is good
}
this._prompt();
});
}
@@ -106,29 +106,25 @@ export class IntegrityServiceImpl implements IIntegrityService {
return this._isPurePromise;
}
private _isPure(): Promise<IntegrityTestResult> {
private async _isPure(): Promise<IntegrityTestResult> {
const expectedChecksums = product.checksums || {};
return this.lifecycleService.when(LifecyclePhase.Eventually).then(() => {
let asyncResults: Promise<ChecksumPair>[] = Object.keys(expectedChecksums).map((filename) => {
return this._resolve(filename, expectedChecksums[filename]);
});
await this.lifecycleService.when(LifecyclePhase.Eventually);
return Promise.all(asyncResults).then<IntegrityTestResult>((allResults) => {
let isPure = true;
for (let i = 0, len = allResults.length; i < len; i++) {
if (!allResults[i].isPure) {
isPure = false;
break;
}
}
const allResults = await Promise.all(Object.keys(expectedChecksums).map(filename => this._resolve(filename, expectedChecksums[filename])));
return {
isPure: isPure,
proof: allResults
};
});
});
let isPure = true;
for (let i = 0, len = allResults.length; i < len; i++) {
if (!allResults[i].isPure) {
isPure = false;
break;
}
}
return {
isPure: isPure,
proof: allResults
};
}
private _resolve(filename: string, expected: string): Promise<ChecksumPair> {

View File

@@ -208,7 +208,8 @@ export class ScopedProgressService extends ScopedService implements IProgressSer
};
}
showWhile(promise: Promise<any>, delay?: number): Promise<void> {
async showWhile(promise: Promise<any>, delay?: number): Promise<void> {
// Join with existing running promise to ensure progress is accurate
if (this.progressState.type === ProgressState.Type.While) {
promise = Promise.all([promise, this.progressState.whilePromise]);
@@ -217,24 +218,25 @@ export class ScopedProgressService extends ScopedService implements IProgressSer
// Keep Promise in State
this.progressState = new ProgressState.While(promise, delay || 0, Date.now());
let stop = () => {
try {
this.doShowWhile(delay);
// If this is not the last promise in the list of joined promises, return early
if (this.progressState.type === ProgressState.Type.While && this.progressState.whilePromise !== promise) {
return;
await promise;
} catch (error) {
// ignore
} finally {
// If this is not the last promise in the list of joined promises, skip this
if (this.progressState.type !== ProgressState.Type.While || this.progressState.whilePromise === promise) {
// The while promise is either null or equal the promise we last hooked on
this.progressState = ProgressState.None;
if (this.isActive) {
this.progressbar.stop().hide();
}
}
// The while promise is either null or equal the promise we last hooked on
this.progressState = ProgressState.None;
if (this.isActive) {
this.progressbar.stop().hide();
}
};
this.doShowWhile(delay);
return promise.then(stop, stop);
}
}
private doShowWhile(delay?: number): void {
@@ -280,13 +282,15 @@ export class ProgressService implements IProgressService {
};
}
showWhile(promise: Promise<any>, delay?: number): Promise<void> {
const stop = () => {
async showWhile(promise: Promise<any>, delay?: number): Promise<void> {
try {
this.progressbar.infinite().show(delay);
await promise;
} catch (error) {
// ignore
} finally {
this.progressbar.stop().hide();
};
this.progressbar.infinite().show(delay);
return promise.then(stop, stop);
}
}
}

View File

@@ -34,28 +34,28 @@ export class RemoteExtensionEnvironmentChannelClient {
constructor(private channel: IChannel) { }
getEnvironmentData(remoteAuthority: string, extensionDevelopmentPath?: URI[]): Promise<IRemoteAgentEnvironment> {
async getEnvironmentData(remoteAuthority: string, extensionDevelopmentPath?: URI[]): Promise<IRemoteAgentEnvironment> {
const args: IGetEnvironmentDataArguments = {
language: platform.language,
remoteAuthority,
extensionDevelopmentPath
};
return this.channel.call<IRemoteAgentEnvironmentDTO>('getEnvironmentData', args)
.then((data: IRemoteAgentEnvironmentDTO): IRemoteAgentEnvironment => {
return {
pid: data.pid,
appRoot: URI.revive(data.appRoot),
appSettingsHome: URI.revive(data.appSettingsHome),
settingsPath: URI.revive(data.settingsPath),
logsPath: URI.revive(data.logsPath),
extensionsPath: URI.revive(data.extensionsPath),
extensionHostLogsPath: URI.revive(data.extensionHostLogsPath),
globalStorageHome: URI.revive(data.globalStorageHome),
userHome: URI.revive(data.userHome),
extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }),
os: data.os
};
});
const data = await this.channel.call<IRemoteAgentEnvironmentDTO>('getEnvironmentData', args);
return {
pid: data.pid,
appRoot: URI.revive(data.appRoot),
appSettingsHome: URI.revive(data.appSettingsHome),
settingsPath: URI.revive(data.settingsPath),
logsPath: URI.revive(data.logsPath),
extensionsPath: URI.revive(data.extensionsPath),
extensionHostLogsPath: URI.revive(data.extensionHostLogsPath),
globalStorageHome: URI.revive(data.globalStorageHome),
userHome: URI.revive(data.userHome),
extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }),
os: data.os
};
}
getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise<IDiagnosticInfo> {

View File

@@ -31,7 +31,7 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod
super();
}
createReferencedObject(key: string, skipActivateProvider?: boolean): Promise<ITextEditorModel> {
async createReferencedObject(key: string, skipActivateProvider?: boolean): Promise<ITextEditorModel> {
this.modelsToDispose.delete(key);
const resource = URI.parse(key);
@@ -43,15 +43,19 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod
// Virtual documents
if (this.providers[resource.scheme]) {
return this.resolveTextModelContent(key).then(() => this.instantiationService.createInstance(ResourceEditorModel, resource));
await this.resolveTextModelContent(key);
return this.instantiationService.createInstance(ResourceEditorModel, resource);
}
// Either unknown schema, or not yet registered, try to activate
if (!skipActivateProvider) {
return this.fileService.activateProvider(resource.scheme).then(() => this.createReferencedObject(key, true));
await this.fileService.activateProvider(resource.scheme);
return this.createReferencedObject(key, true);
}
return Promise.reject(new Error('resource is not available'));
throw new Error('resource is not available');
}
destroyReferencedObject(key: string, modelPromise: Promise<ITextEditorModel>): void {
@@ -101,18 +105,17 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod
return this.providers[scheme] !== undefined;
}
private resolveTextModelContent(key: string): Promise<ITextModel> {
private async resolveTextModelContent(key: string): Promise<ITextModel> {
const resource = URI.parse(key);
const providers = this.providers[resource.scheme] || [];
const factories = providers.map(p => () => Promise.resolve(p.provideTextContent(resource)));
return first(factories).then(model => {
if (!model) {
return Promise.reject(new Error('resource is not available'));
}
const model = await first(factories);
if (!model) {
throw new Error('resource is not available');
}
return model;
});
return model;
}
}
@@ -131,14 +134,16 @@ export class TextModelResolverService implements ITextModelService {
}
createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
return this._createModelReference(resource);
return this.doCreateModelReference(resource);
}
private _createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
private async doCreateModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
// Untitled Schema: go through cached input
if (resource.scheme === network.Schemas.untitled) {
return this.untitledEditorService.loadOrCreate({ resource }).then(model => new ImmortalReference(model as IResolvedTextEditorModel));
const model = await this.untitledEditorService.loadOrCreate({ resource });
return new ImmortalReference(model as IResolvedTextEditorModel);
}
// InMemory Schema: go through model service cache
@@ -154,14 +159,15 @@ export class TextModelResolverService implements ITextModelService {
const ref = this.resourceModelCollection.acquire(resource.toString());
return ref.object.then(
model => ({ object: model, dispose: () => ref.dispose() }),
err => {
ref.dispose();
try {
const model = await ref.object;
return Promise.reject(err);
}
);
return { object: model as IResolvedTextEditorModel, dispose: () => ref.dispose() };
} catch (error) {
ref.dispose();
throw error;
}
}
registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable {

View File

@@ -71,6 +71,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
if (reason !== ShutdownReason.LOAD && reason !== ShutdownReason.CLOSE) {
return undefined; // only interested when window is closing or loading
}
const workspaceIdentifier = this.getCurrentWorkspaceIdentifier();
if (!workspaceIdentifier || !isEqualOrParent(workspaceIdentifier.configPath, this.environmentService.untitledWorkspacesHome)) {
return undefined; // only care about untitled workspaces to ask for saving
@@ -190,16 +191,23 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
}
private doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): Promise<void> {
return this.contextService.updateFolders(foldersToAdd, foldersToDelete, index)
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
private async doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): Promise<void> {
try {
await this.contextService.updateFolders(foldersToAdd, foldersToDelete, index);
} catch (error) {
if (donotNotifyError) {
throw error;
}
this.handleWorkspaceConfigurationEditingError(error);
}
}
addFolders(foldersToAdd: IWorkspaceFolderCreationData[], donotNotifyError: boolean = false): Promise<void> {
return this.doAddFolders(foldersToAdd, undefined, donotNotifyError);
}
private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> {
private async doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> {
const state = this.contextService.getWorkbenchState();
// If we are in no-workspace or single-folder workspace, adding folders has to
@@ -217,11 +225,18 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
// Delegate addition of folders to workspace service otherwise
return this.contextService.addFolders(foldersToAdd, index)
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
try {
await this.contextService.addFolders(foldersToAdd, index);
} catch (error) {
if (donotNotifyError) {
throw error;
}
this.handleWorkspaceConfigurationEditingError(error);
}
}
removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): Promise<void> {
async removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): Promise<void> {
// If we are in single-folder state and the opened folder is to be removed,
// we create an empty workspace and enter it.
@@ -230,8 +245,15 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
// Delegate removal of folders to workspace service otherwise
return this.contextService.removeFolders(foldersToRemove)
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
try {
await this.contextService.removeFolders(foldersToRemove);
} catch (error) {
if (donotNotifyError) {
throw error;
}
this.handleWorkspaceConfigurationEditingError(error);
}
}
private includesSingleFolderWorkspace(folders: URI[]): boolean {
@@ -283,10 +305,12 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
detail: nls.localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
noLink: true
};
return this.windowService.showMessageBox(options).then(() => false);
await this.windowService.showMessageBox(options);
return false;
}
return Promise.resolve(true); // OK
return true; // OK
}
private async saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPathURI: URI): Promise<any> {