Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc';
import { Event, Emitter, debounceEvent } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { StorageMainService, IStorageChangeEvent } from 'vs/platform/storage/node/storageMainService';
import { IUpdateRequest, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/node/storage';
import { mapToSerializable, serializableToMap, values } from 'vs/base/common/map';
@@ -40,7 +40,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
// Listen for changes in global storage to send to listeners
// that are listening. Use a debouncer to reduce IPC traffic.
this._register(debounceEvent(this.storageMainService.onDidChangeStorage, (prev: IStorageChangeEvent[], cur: IStorageChangeEvent) => {
this._register(Event.debounce(this.storageMainService.onDidChangeStorage, (prev: IStorageChangeEvent[], cur: IStorageChangeEvent) => {
if (!prev) {
prev = [cur];
} else {
@@ -57,7 +57,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
private serializeEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent {
const items = new Map<Key, Value>();
events.forEach(event => items.set(event.key, this.storageMainService.get(event.key, null)));
events.forEach(event => items.set(event.key, this.storageMainService.get(event.key)));
return { items: mapToSerializable(items) } as ISerializableItemsChangeEvent;
}
@@ -70,7 +70,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Thenable<any> {
call(_, command: string, arg?: any): Promise<any> {
switch (command) {
case 'getItems': {
return Promise.resolve(mapToSerializable(this.storageMainService.items));
@@ -125,11 +125,11 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
}
}
getItems(): Thenable<Map<string, string>> {
getItems(): Promise<Map<string, string>> {
return this.channel.call('getItems').then((data: Item[]) => serializableToMap(data));
}
updateItems(request: IUpdateRequest): Thenable<void> {
updateItems(request: IUpdateRequest): Promise<void> {
let updateCount = 0;
const serializableRequest: ISerializableUpdateRequest = Object.create(null);
@@ -150,11 +150,11 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
return this.channel.call('updateItems', serializableRequest);
}
checkIntegrity(full: boolean): Thenable<string> {
checkIntegrity(full: boolean): Promise<string> {
return this.channel.call('checkIntegrity', full);
}
close(): Thenable<void> {
close(): Promise<void> {
// when we are about to close, we start to ignore main-side changes since we close anyway
this.onDidChangeItemsOnMainListener = dispose(this.onDidChangeItemsOnMainListener);

View File

@@ -39,6 +39,7 @@ export interface IStorageMainService {
* the provided defaultValue if the element is null or undefined.
*/
get(key: string, fallbackValue: string): string;
get(key: string, fallbackValue?: string): string | undefined;
/**
* Retrieve an element stored with the given key from storage. Use
@@ -46,6 +47,7 @@ export interface IStorageMainService {
* will be converted to a boolean.
*/
getBoolean(key: string, fallbackValue: boolean): boolean;
getBoolean(key: string, fallbackValue?: boolean): boolean | undefined;
/**
* Retrieve an element stored with the given key from storage. Use
@@ -53,6 +55,7 @@ export interface IStorageMainService {
* will be converted to a number using parseInt with a base of 10.
*/
getInteger(key: string, fallbackValue: number): number;
getInteger(key: string, fallbackValue?: number): number | undefined;
/**
* Store a string value under the given key to storage. The value will
@@ -74,7 +77,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
_serviceBrand: any;
private static STORAGE_NAME = 'temp.vscdb';
private static STORAGE_NAME = 'state.vscdb';
private _onDidChangeStorage: Emitter<IStorageChangeEvent> = this._register(new Emitter<IStorageChangeEvent>());
get onDidChangeStorage(): Event<IStorageChangeEvent> { return this._onDidChangeStorage.event; }
@@ -87,9 +90,9 @@ export class StorageMainService extends Disposable implements IStorageMainServic
private storage: IStorage;
constructor(
@ILogService private logService: ILogService,
@IEnvironmentService private environmentService: IEnvironmentService,
@ITelemetryService private telemetryService: ITelemetryService
@ILogService private readonly logService: ILogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ITelemetryService private readonly telemetryService: ITelemetryService
) {
super();
@@ -98,7 +101,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
}
private get storagePath(): string {
if (!!this.environmentService.extensionTestsPath || !process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
if (!!this.environmentService.extensionTestsPath) {
return SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests!
}
@@ -109,7 +112,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
const loggedStorageErrors = new Set<string>();
return {
logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : void 0,
logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined,
logError: error => {
this.logService.error(error);
@@ -130,7 +133,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
} as ISQLiteStorageDatabaseLoggingOptions;
}
initialize(): Thenable<void> {
initialize(): Promise<void> {
const useInMemoryStorage = this.storagePath === SQLiteStorageDatabase.IN_MEMORY_PATH;
let globalStorageExists: Promise<boolean>;
@@ -158,7 +161,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
}).then(() => {
// Migrate storage if this is the first start and we are not using in-memory
let migrationPromise: Thenable<void>;
let migrationPromise: Promise<void>;
if (!useInMemoryStorage && !exists) {
// TODO@Ben remove global storage migration and move Storage creation back to ctor
migrationPromise = this.migrateGlobalStorage().then(() => this.logService.info('[storage] migrated global storage'), error => this.logService.error(`[storage] migration error ${error}`));
@@ -171,10 +174,10 @@ export class StorageMainService extends Disposable implements IStorageMainServic
});
}
private migrateGlobalStorage(): Thenable<void> {
private migrateGlobalStorage(): Promise<void> {
this.logService.info('[storage] migrating global storage from localStorage into SQLite');
const localStorageDBBackup = join(this.environmentService.userDataPath, 'Local Storage', 'file__0.localstorage.vscmig');
const localStorageDBBackup = join(this.environmentService.userDataPath, 'Local Storage', 'file__0.vscmig');
return exists(localStorageDBBackup).then(exists => {
if (!exists) {
@@ -345,32 +348,35 @@ export class StorageMainService extends Disposable implements IStorageMainServic
});
}
get(key: string, fallbackValue: string): string {
get(key: string, fallbackValue: string): string;
get(key: string, fallbackValue?: string): string | undefined;
get(key: string, fallbackValue?: string): string | undefined {
return this.storage.get(key, fallbackValue);
}
getBoolean(key: string, fallbackValue: boolean): boolean {
getBoolean(key: string, fallbackValue: boolean): boolean;
getBoolean(key: string, fallbackValue?: boolean): boolean | undefined;
getBoolean(key: string, fallbackValue?: boolean): boolean | undefined {
return this.storage.getBoolean(key, fallbackValue);
}
getInteger(key: string, fallbackValue: number): number {
getInteger(key: string, fallbackValue: number): number;
getInteger(key: string, fallbackValue?: number): number | undefined;
getInteger(key: string, fallbackValue?: number): number | undefined {
return this.storage.getInteger(key, fallbackValue);
}
store(key: string, value: any): Thenable<void> {
store(key: string, value: any): Promise<void> {
return this.storage.set(key, value);
}
remove(key: string): Thenable<void> {
remove(key: string): Promise<void> {
return this.storage.delete(key);
}
close(): Thenable<void> {
close(): Promise<void> {
this.logService.trace('StorageMainService#close() - begin');
// Signal to storage that we are about to close
this.storage.beforeClose();
// Signal as event so that clients can still store data
this._onWillSaveState.fire();
@@ -383,7 +389,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
});
}
checkIntegrity(full: boolean): Thenable<string> {
checkIntegrity(full: boolean): Promise<string> {
return this.storage.checkIntegrity(full);
}
}

View File

@@ -8,19 +8,15 @@ import { Event, Emitter } from 'vs/base/common/event';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { Storage, ISQLiteStorageDatabaseLoggingOptions, IStorage, StorageHint, IStorageDatabase, SQLiteStorageDatabase } from 'vs/base/node/storage';
import { IStorageLegacyService, StorageLegacyScope } from 'vs/platform/storage/common/storageLegacyService';
import { startsWith, endsWith } from 'vs/base/common/strings';
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { localize } from 'vs/nls';
import { mark, getDuration } from 'vs/base/common/performance';
import { join } from 'path';
import { copy, exists, mkdirp, readdir, writeFile } from 'vs/base/node/pfs';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { copy, exists, mkdirp, writeFile } from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { onUnexpectedError } from 'vs/base/common/errors';
import { StorageObject, parseMultiRootStorage, parseFolderStorage, parseNoWorkspaceStorage, parseEmptyStorage } from 'vs/platform/storage/common/storageLegacyMigration';
export class StorageService extends Disposable implements IStorageService {
_serviceBrand: any;
@@ -37,7 +33,7 @@ export class StorageService extends Disposable implements IStorageService {
private _hasErrors = false;
get hasErrors(): boolean { return this._hasErrors; }
private bufferedWorkspaceStorageErrors?: (string | Error)[] = [];
private bufferedWorkspaceStorageErrors?: Array<string | Error> = [];
private _onWorkspaceStorageError: Emitter<string | Error> = this._register(new Emitter<string | Error>());
get onWorkspaceStorageError(): Event<string | Error> {
if (Array.isArray(this.bufferedWorkspaceStorageErrors)) {
@@ -49,7 +45,7 @@ export class StorageService extends Disposable implements IStorageService {
}, 0);
}
this.bufferedWorkspaceStorageErrors = void 0;
this.bufferedWorkspaceStorageErrors = undefined;
}
return this._onWorkspaceStorageError.event;
@@ -63,30 +59,28 @@ export class StorageService extends Disposable implements IStorageService {
constructor(
globalStorageDatabase: IStorageDatabase,
@ILogService private logService: ILogService,
@IEnvironmentService private environmentService: IEnvironmentService
@ILogService private readonly logService: ILogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
) {
super();
// Global Storage
this.globalStorage = new Storage(globalStorageDatabase);
if (process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
this._register(this.globalStorage.onDidChangeStorage(key => this.handleDidChangeStorage(key, StorageScope.GLOBAL)));
}
this._register(this.globalStorage.onDidChangeStorage(key => this.handleDidChangeStorage(key, StorageScope.GLOBAL)));
}
private handleDidChangeStorage(key: string, scope: StorageScope): void {
this._onDidChangeStorage.fire({ key, scope });
}
initialize(payload: IWorkspaceInitializationPayload): Thenable<void> {
initialize(payload: IWorkspaceInitializationPayload): Promise<void> {
return Promise.all([
this.initializeGlobalStorage(),
this.initializeWorkspaceStorage(payload)
]).then(() => void 0);
]).then(() => undefined);
}
private initializeGlobalStorage(): Thenable<void> {
private initializeGlobalStorage(): Promise<void> {
mark('willInitGlobalStorage');
return this.globalStorage.init().then(() => {
@@ -98,173 +92,26 @@ export class StorageService extends Disposable implements IStorageService {
});
}
private initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Thenable<void> {
private initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise<void> {
// Prepare workspace storage folder for DB
return this.prepareWorkspaceStorageFolder(payload).then(result => {
const useInMemoryStorage = !!this.environmentService.extensionTestsPath; // no storage during extension tests!
let workspaceStoragePath: string;
let workspaceStorageExists: Thenable<boolean>;
if (useInMemoryStorage) {
workspaceStoragePath = SQLiteStorageDatabase.IN_MEMORY_PATH;
workspaceStorageExists = Promise.resolve(true);
} else {
workspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
// Create workspace storage and initalize
mark('willInitWorkspaceStorage');
return this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init().then(() => {
mark('didInitWorkspaceStorage');
}, error => {
mark('didInitWorkspaceStorage');
mark('willCheckWorkspaceStorageExists');
workspaceStorageExists = exists(workspaceStoragePath).then(exists => {
mark('didCheckWorkspaceStorageExists');
return exists;
});
}
return workspaceStorageExists.then(exists => {
// Create workspace storage and initalize
mark('willInitWorkspaceStorage');
return this.createWorkspaceStorage(workspaceStoragePath, result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : void 0).init().then(() => {
mark('didInitWorkspaceStorage');
}, error => {
mark('didInitWorkspaceStorage');
return Promise.reject(error);
}).then(() => {
// Migrate storage if this is the first start and we are not using in-memory
let migrationPromise: Thenable<void>;
if (!useInMemoryStorage && !exists) {
migrationPromise = this.migrateWorkspaceStorage(payload);
} else {
migrationPromise = Promise.resolve();
}
return migrationPromise;
});
return Promise.reject(error);
});
});
}
}).then(undefined, error => {
onUnexpectedError(error);
// TODO@Ben remove migration after a while
private migrateWorkspaceStorage(payload: IWorkspaceInitializationPayload): Thenable<void> {
mark('willMigrateWorkspaceStorageKeys');
return readdir(this.environmentService.extensionsPath).then(extensions => {
// Otherwise, we migrate data from window.localStorage over
try {
let workspaceItems: StorageObject;
if (isWorkspaceIdentifier(payload)) {
workspaceItems = parseMultiRootStorage(window.localStorage, `root:${payload.id}`);
} else if (isSingleFolderWorkspaceInitializationPayload(payload)) {
workspaceItems = parseFolderStorage(window.localStorage, payload.folder.toString());
} else {
if (payload.id === 'ext-dev') {
workspaceItems = parseNoWorkspaceStorage(window.localStorage);
} else {
workspaceItems = parseEmptyStorage(window.localStorage, `${payload.id}`);
}
}
const workspaceItemsKeys = workspaceItems ? Object.keys(workspaceItems) : [];
if (workspaceItemsKeys.length > 0) {
const supportedKeys = new Map<string, string>();
[
'workbench.search.history',
'history.entries',
'ignoreNetVersionError',
'ignoreEnospcError',
'extensionUrlHandler.urlToHandle',
'terminal.integrated.isWorkspaceShellAllowed',
'workbench.tasks.ignoreTask010Shown',
'workbench.tasks.recentlyUsedTasks',
'workspaces.dontPromptToOpen',
'output.activechannel',
'outline/state',
'extensionsAssistant/workspaceRecommendationsIgnore',
'extensionsAssistant/dynamicWorkspaceRecommendations',
'debug.repl.history',
'editor.matchCase',
'editor.wholeWord',
'editor.isRegex',
'lifecyle.lastShutdownReason',
'debug.selectedroot',
'debug.selectedconfigname',
'debug.breakpoint',
'debug.breakpointactivated',
'debug.functionbreakpoint',
'debug.exceptionbreakpoint',
'debug.watchexpressions',
'workbench.sidebar.activeviewletid',
'workbench.panelpart.activepanelid',
'workbench.zenmode.active',
'workbench.centerededitorlayout.active',
'workbench.sidebar.hidden',
'workbench.panel.hidden',
'workbench.panel.location',
'extensionsIdentifiers/disabled',
'extensionsIdentifiers/enabled',
'scm.views',
'suggest/memories/first',
'suggest/memories/recentlyUsed',
'suggest/memories/recentlyUsedByPrefix',
'workbench.view.explorer.numberOfVisibleViews',
'workbench.view.extensions.numberOfVisibleViews',
'workbench.view.debug.numberOfVisibleViews',
'workbench.explorer.views.state',
'workbench.view.extensions.state',
'workbench.view.debug.state',
'memento/workbench.editor.walkThroughPart',
'memento/workbench.editor.settings2',
'memento/workbench.editor.htmlPreviewPart',
'memento/workbench.editor.defaultPreferences',
'memento/workbench.editors.files.textFileEditor',
'memento/workbench.editors.logViewer',
'memento/workbench.editors.textResourceEditor',
'memento/workbench.panel.output'
].forEach(key => supportedKeys.set(key.toLowerCase(), key));
// Support extension storage as well (always the ID of the extension)
extensions.forEach(extension => {
let extensionId: string;
if (extension.indexOf('-') >= 0) {
extensionId = extension.substring(0, extension.lastIndexOf('-')); // convert "author.extension-0.2.5" => "author.extension"
} else {
extensionId = extension;
}
if (extensionId) {
supportedKeys.set(extensionId.toLowerCase(), extensionId);
}
});
workspaceItemsKeys.forEach(key => {
const value = workspaceItems[key];
// first check for a well known supported key and store with realcase value
const supportedKey = supportedKeys.get(key);
if (supportedKey) {
this.store(supportedKey, value, StorageScope.WORKSPACE);
}
// fix lowercased ".numberOfVisibleViews"
else if (endsWith(key, '.numberOfVisibleViews'.toLowerCase())) {
const normalizedKey = key.substring(0, key.length - '.numberOfVisibleViews'.length) + '.numberOfVisibleViews';
this.store(normalizedKey, value, StorageScope.WORKSPACE);
}
// support dynamic keys
else if (key.indexOf('memento/') === 0 || endsWith(key, '.state')) {
this.store(key, value, StorageScope.WORKSPACE);
}
});
}
} catch (error) {
onUnexpectedError(error);
this.logService.error(error);
}
mark('didMigrateWorkspaceStorageKeys');
// Upon error, fallback to in-memory storage
return this.createWorkspaceStorage(SQLiteStorageDatabase.IN_MEMORY_PATH).init();
});
}
@@ -272,7 +119,7 @@ export class StorageService extends Disposable implements IStorageService {
// Logger for workspace storage
const workspaceLoggingOptions: ISQLiteStorageDatabaseLoggingOptions = {
logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : void 0,
logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined,
logError: error => {
this.logService.error(error);
@@ -302,7 +149,7 @@ export class StorageService extends Disposable implements IStorageService {
return join(this.environmentService.workspaceStorageHome, payload.id); // workspace home + workspace id;
}
private prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Thenable<{ path: string, wasCreated: boolean }> {
private prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> {
const workspaceStorageFolderPath = this.getWorkspaceStorageFolderPath(payload);
return exists(workspaceStorageFolderPath).then(exists => {
@@ -321,7 +168,7 @@ export class StorageService extends Disposable implements IStorageService {
}
private ensureWorkspaceStorageFolderMeta(payload: IWorkspaceInitializationPayload): void {
let meta: object | undefined = void 0;
let meta: object | undefined = undefined;
if (isSingleFolderWorkspaceInitializationPayload(payload)) {
meta = { folder: payload.folder.toString() };
} else if (isWorkspaceIdentifier(payload)) {
@@ -332,11 +179,11 @@ export class StorageService extends Disposable implements IStorageService {
const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), StorageService.WORKSPACE_META_NAME);
exists(workspaceStorageMetaPath).then(exists => {
if (exists) {
return void 0; // already existing
return undefined; // already existing
}
return writeFile(workspaceStorageMetaPath, JSON.stringify(meta, void 0, 2));
}).then(null, error => onUnexpectedError(error));
return writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2));
}).then(undefined, error => onUnexpectedError(error));
}
}
@@ -358,7 +205,7 @@ export class StorageService extends Disposable implements IStorageService {
return this.getStorage(scope).getInteger(key, fallbackValue);
}
store(key: string, value: any, scope: StorageScope): void {
store(key: string, value: string | boolean | number, scope: StorageScope): void {
this.getStorage(scope).set(key, value);
}
@@ -368,10 +215,6 @@ export class StorageService extends Disposable implements IStorageService {
close(): Promise<void> {
// Signal to storage that we are about to close
this.globalStorage.beforeClose();
this.workspaceStorage.beforeClose();
// Signal as event so that clients can still store data
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
@@ -394,7 +237,7 @@ export class StorageService extends Disposable implements IStorageService {
return scope === StorageScope.GLOBAL ? this.globalStorage.size : this.workspaceStorage.size;
}
checkIntegrity(scope: StorageScope, full: boolean): Thenable<string> {
checkIntegrity(scope: StorageScope, full: boolean): Promise<string> {
return scope === StorageScope.GLOBAL ? this.globalStorage.checkIntegrity(full) : this.workspaceStorage.checkIntegrity(full);
}
@@ -449,7 +292,7 @@ export class StorageService extends Disposable implements IStorageService {
});
}
migrate(toWorkspace: IWorkspaceInitializationPayload): Thenable<void> {
migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {
if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) {
return Promise.resolve(); // no migration needed if running in memory
}
@@ -480,129 +323,15 @@ export class LogStorageAction extends Action {
constructor(
id: string,
label: string,
@IStorageService private storageService: DelegatingStorageService,
@IWindowService private windowService: IWindowService
@IStorageService private readonly storageService: StorageService,
@IWindowService private readonly windowService: IWindowService
) {
super(id, label);
}
run(): Thenable<void> {
this.storageService.storage.logStorage();
run(): Promise<void> {
this.storageService.logStorage();
return this.windowService.openDevTools();
}
}
export class DelegatingStorageService extends Disposable implements IStorageService {
_serviceBrand: any;
private _onDidChangeStorage: Emitter<IWorkspaceStorageChangeEvent> = this._register(new Emitter<IWorkspaceStorageChangeEvent>());
get onDidChangeStorage(): Event<IWorkspaceStorageChangeEvent> { return this._onDidChangeStorage.event; }
private _onWillSaveState: Emitter<IWillSaveStateEvent> = this._register(new Emitter<IWillSaveStateEvent>());
get onWillSaveState(): Event<IWillSaveStateEvent> { return this._onWillSaveState.event; }
private closed: boolean;
private useLegacyWorkspaceStorage: boolean;
constructor(
private storageService: IStorageService,
private storageLegacyService: IStorageLegacyService,
private logService: ILogService,
configurationService: IConfigurationService
) {
super();
this.useLegacyWorkspaceStorage = configurationService.inspect<boolean>('workbench.enableLegacyStorage').value === true;
this.registerListeners();
}
private registerListeners(): void {
this._register(this.storageService.onDidChangeStorage(e => this._onDidChangeStorage.fire(e)));
this._register(this.storageService.onWillSaveState(e => this._onWillSaveState.fire(e)));
const globalKeyMarker = 'storage://global/';
window.addEventListener('storage', e => {
if (e.key && startsWith(e.key, globalKeyMarker)) {
const key = e.key.substr(globalKeyMarker.length);
this._onDidChangeStorage.fire({ key, scope: StorageScope.GLOBAL });
}
});
}
get storage(): StorageService {
return this.storageService as StorageService;
}
get(key: string, scope: StorageScope, fallbackValue: string): string;
get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined {
if (!this.useLegacyWorkspaceStorage) {
if (scope === StorageScope.WORKSPACE || process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
return this.storageService.get(key, scope, fallbackValue);
}
}
return this.storageLegacyService.get(key, this.convertScope(scope), fallbackValue);
}
getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined {
if (!this.useLegacyWorkspaceStorage) {
if (scope === StorageScope.WORKSPACE || process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
return this.storageService.getBoolean(key, scope, fallbackValue);
}
}
return this.storageLegacyService.getBoolean(key, this.convertScope(scope), fallbackValue);
}
getInteger(key: string, scope: StorageScope, fallbackValue: number): number;
getInteger(key: string, scope: StorageScope, fallbackValue?: number): number | undefined {
if (!this.useLegacyWorkspaceStorage) {
if (scope === StorageScope.WORKSPACE || process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
return this.storageService.getInteger(key, scope, fallbackValue);
}
}
return this.storageLegacyService.getInteger(key, this.convertScope(scope), fallbackValue);
}
store(key: string, value: any, scope: StorageScope): void {
if (this.closed) {
this.logService.warn(`Unsupported write (store) access after close (key: ${key})`);
return; // prevent writing after close to detect late write access
}
this.storageLegacyService.store(key, value, this.convertScope(scope));
this.storageService.store(key, value, scope);
}
remove(key: string, scope: StorageScope): void {
if (this.closed) {
this.logService.warn(`Unsupported write (remove) access after close (key: ${key})`);
return; // prevent writing after close to detect late write access
}
this.storageLegacyService.remove(key, this.convertScope(scope));
this.storageService.remove(key, scope);
}
close(): Promise<void> {
const promise = this.storage.close();
this.closed = true;
return promise;
}
private convertScope(scope: StorageScope): StorageLegacyScope {
return scope === StorageScope.GLOBAL ? StorageLegacyScope.GLOBAL : StorageLegacyScope.WORKSPACE;
}
}