sussudio
Version:
An unofficial VS Code Internal API
143 lines (142 loc) • 5.39 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { ThrottledDelayer } from "../../../base/common/async.mjs";
import { VSBuffer } from "../../../base/common/buffer.mjs";
import { isUndefined, isUndefinedOrNull } from "../../../base/common/types.mjs";
import { IEnvironmentService } from "../../environment/common/environment.mjs";
import { IFileService } from "../../files/common/files.mjs";
import { ILogService } from "../../log/common/log.mjs";
export class FileStorage {
storagePath;
logService;
fileService;
storage = Object.create(null);
lastSavedStorageContents = '';
flushDelayer = new ThrottledDelayer(100 /* buffer saves over a short time */);
initializing = undefined;
closing = undefined;
constructor(storagePath, logService, fileService) {
this.storagePath = storagePath;
this.logService = logService;
this.fileService = fileService;
}
init() {
if (!this.initializing) {
this.initializing = this.doInit();
}
return this.initializing;
}
async doInit() {
try {
this.lastSavedStorageContents = (await this.fileService.readFile(this.storagePath)).value.toString();
this.storage = JSON.parse(this.lastSavedStorageContents);
}
catch (error) {
if (error.fileOperationResult !== 1 /* FileOperationResult.FILE_NOT_FOUND */) {
this.logService.error(error);
}
}
}
getItem(key, defaultValue) {
const res = this.storage[key];
if (isUndefinedOrNull(res)) {
return defaultValue;
}
return res;
}
setItem(key, data) {
this.setItems([{ key, data }]);
}
setItems(items) {
let save = false;
for (const { key, data } of items) {
// Shortcut for data that did not change
if (this.storage[key] === data) {
continue;
}
// Remove items when they are undefined or null
if (isUndefinedOrNull(data)) {
if (!isUndefined(this.storage[key])) {
this.storage[key] = undefined;
save = true;
}
}
// Otherwise add an item
else {
this.storage[key] = data;
save = true;
}
}
if (save) {
this.save();
}
}
removeItem(key) {
// Only update if the key is actually present (not undefined)
if (!isUndefined(this.storage[key])) {
this.storage[key] = undefined;
this.save();
}
}
async save() {
if (this.closing) {
return; // already about to close
}
return this.flushDelayer.trigger(() => this.doSave());
}
async doSave() {
if (!this.initializing) {
return; // if we never initialized, we should not save our state
}
// Make sure to wait for init to finish first
await this.initializing;
// Return early if the database has not changed
const serializedDatabase = JSON.stringify(this.storage, null, 4);
if (serializedDatabase === this.lastSavedStorageContents) {
return;
}
// Write to disk
try {
await this.fileService.writeFile(this.storagePath, VSBuffer.fromString(serializedDatabase));
this.lastSavedStorageContents = serializedDatabase;
}
catch (error) {
this.logService.error(error);
}
}
async close() {
if (!this.closing) {
this.closing = this.flushDelayer.trigger(() => this.doSave(), 0 /* as soon as possible */);
}
return this.closing;
}
}
let StateService = class StateService {
fileStorage;
constructor(environmentService, logService, fileService) {
this.fileStorage = new FileStorage(environmentService.stateResource, logService, fileService);
}
async init() {
await this.fileStorage.init();
}
getItem(key, defaultValue) {
return this.fileStorage.getItem(key, defaultValue);
}
};
StateService = __decorate([
__param(0, IEnvironmentService),
__param(1, ILogService),
__param(2, IFileService)
], StateService);
export { StateService };