monaco-editor
Version:
A browser based code editor
193 lines (192 loc) • 8.07 kB
JavaScript
import { Emitter, Event, PauseableEmitter } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { isUndefinedOrNull } from '../../../base/common/types.js';
import { InMemoryStorageDatabase, Storage, StorageHint } from '../../../base/parts/storage/common/storage.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
export const TARGET_KEY = '__$__targetStorageMarker';
export const IStorageService = createDecorator('storageService');
export var WillSaveStateReason;
(function (WillSaveStateReason) {
/**
* No specific reason to save state.
*/
WillSaveStateReason[WillSaveStateReason["NONE"] = 0] = "NONE";
/**
* A hint that the workbench is about to shutdown.
*/
WillSaveStateReason[WillSaveStateReason["SHUTDOWN"] = 1] = "SHUTDOWN";
})(WillSaveStateReason || (WillSaveStateReason = {}));
export function loadKeyTargets(storage) {
const keysRaw = storage.get(TARGET_KEY);
if (keysRaw) {
try {
return JSON.parse(keysRaw);
}
catch (error) {
// Fail gracefully
}
}
return Object.create(null);
}
export class AbstractStorageService extends Disposable {
constructor(options = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) {
super();
this.options = options;
this._onDidChangeValue = this._register(new PauseableEmitter());
this._onDidChangeTarget = this._register(new PauseableEmitter());
this._onWillSaveState = this._register(new Emitter());
this.onWillSaveState = this._onWillSaveState.event;
this._workspaceKeyTargets = undefined;
this._profileKeyTargets = undefined;
this._applicationKeyTargets = undefined;
}
onDidChangeValue(scope, key, disposable) {
return Event.filter(this._onDidChangeValue.event, e => e.scope === scope && (key === undefined || e.key === key), disposable);
}
emitDidChangeValue(scope, event) {
const { key, external } = event;
// Specially handle `TARGET_KEY`
if (key === TARGET_KEY) {
// Clear our cached version which is now out of date
switch (scope) {
case -1 /* StorageScope.APPLICATION */:
this._applicationKeyTargets = undefined;
break;
case 0 /* StorageScope.PROFILE */:
this._profileKeyTargets = undefined;
break;
case 1 /* StorageScope.WORKSPACE */:
this._workspaceKeyTargets = undefined;
break;
}
// Emit as `didChangeTarget` event
this._onDidChangeTarget.fire({ scope });
}
// Emit any other key to outside
else {
this._onDidChangeValue.fire({ scope, key, target: this.getKeyTargets(scope)[key], external });
}
}
get(key, scope, fallbackValue) {
var _a;
return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.get(key, fallbackValue);
}
getBoolean(key, scope, fallbackValue) {
var _a;
return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.getBoolean(key, fallbackValue);
}
getNumber(key, scope, fallbackValue) {
var _a;
return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.getNumber(key, fallbackValue);
}
store(key, value, scope, target, external = false) {
// We remove the key for undefined/null values
if (isUndefinedOrNull(value)) {
this.remove(key, scope, external);
return;
}
// Update our datastructures but send events only after
this.withPausedEmitters(() => {
var _a;
// Update key-target map
this.updateKeyTarget(key, scope, target);
// Store actual value
(_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.set(key, value, external);
});
}
remove(key, scope, external = false) {
// Update our datastructures but send events only after
this.withPausedEmitters(() => {
var _a;
// Update key-target map
this.updateKeyTarget(key, scope, undefined);
// Remove actual key
(_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.delete(key, external);
});
}
withPausedEmitters(fn) {
// Pause emitters
this._onDidChangeValue.pause();
this._onDidChangeTarget.pause();
try {
fn();
}
finally {
// Resume emitters
this._onDidChangeValue.resume();
this._onDidChangeTarget.resume();
}
}
updateKeyTarget(key, scope, target, external = false) {
var _a, _b;
// Add
const keyTargets = this.getKeyTargets(scope);
if (typeof target === 'number') {
if (keyTargets[key] !== target) {
keyTargets[key] = target;
(_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.set(TARGET_KEY, JSON.stringify(keyTargets), external);
}
}
// Remove
else {
if (typeof keyTargets[key] === 'number') {
delete keyTargets[key];
(_b = this.getStorage(scope)) === null || _b === void 0 ? void 0 : _b.set(TARGET_KEY, JSON.stringify(keyTargets), external);
}
}
}
get workspaceKeyTargets() {
if (!this._workspaceKeyTargets) {
this._workspaceKeyTargets = this.loadKeyTargets(1 /* StorageScope.WORKSPACE */);
}
return this._workspaceKeyTargets;
}
get profileKeyTargets() {
if (!this._profileKeyTargets) {
this._profileKeyTargets = this.loadKeyTargets(0 /* StorageScope.PROFILE */);
}
return this._profileKeyTargets;
}
get applicationKeyTargets() {
if (!this._applicationKeyTargets) {
this._applicationKeyTargets = this.loadKeyTargets(-1 /* StorageScope.APPLICATION */);
}
return this._applicationKeyTargets;
}
getKeyTargets(scope) {
switch (scope) {
case -1 /* StorageScope.APPLICATION */:
return this.applicationKeyTargets;
case 0 /* StorageScope.PROFILE */:
return this.profileKeyTargets;
default:
return this.workspaceKeyTargets;
}
}
loadKeyTargets(scope) {
const storage = this.getStorage(scope);
return storage ? loadKeyTargets(storage) : Object.create(null);
}
}
AbstractStorageService.DEFAULT_FLUSH_INTERVAL = 60 * 1000; // every minute
export class InMemoryStorageService extends AbstractStorageService {
constructor() {
super();
this.applicationStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
this.profileStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
this.workspaceStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
this._register(this.workspaceStorage.onDidChangeStorage(e => this.emitDidChangeValue(1 /* StorageScope.WORKSPACE */, e)));
this._register(this.profileStorage.onDidChangeStorage(e => this.emitDidChangeValue(0 /* StorageScope.PROFILE */, e)));
this._register(this.applicationStorage.onDidChangeStorage(e => this.emitDidChangeValue(-1 /* StorageScope.APPLICATION */, e)));
}
getStorage(scope) {
switch (scope) {
case -1 /* StorageScope.APPLICATION */:
return this.applicationStorage;
case 0 /* StorageScope.PROFILE */:
return this.profileStorage;
default:
return this.workspaceStorage;
}
}
}