Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/common/memento.ts
5220 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from '../../platform/storage/common/storage.js';
7
import { isEmptyObject } from '../../base/common/types.js';
8
import { onUnexpectedError } from '../../base/common/errors.js';
9
import { DisposableStore } from '../../base/common/lifecycle.js';
10
import { Event } from '../../base/common/event.js';
11
12
export class Memento<T extends object> {
13
14
private static readonly applicationMementos = new Map<string, ScopedMemento<unknown>>();
15
private static readonly profileMementos = new Map<string, ScopedMemento<unknown>>();
16
private static readonly workspaceMementos = new Map<string, ScopedMemento<unknown>>();
17
18
private static readonly COMMON_PREFIX = 'memento/';
19
20
private readonly id: string;
21
22
constructor(id: string, private storageService: IStorageService) {
23
this.id = Memento.COMMON_PREFIX + id;
24
}
25
26
getMemento(scope: StorageScope, target: StorageTarget): Partial<T> {
27
switch (scope) {
28
case StorageScope.WORKSPACE: {
29
let workspaceMemento = Memento.workspaceMementos.get(this.id);
30
if (!workspaceMemento) {
31
workspaceMemento = new ScopedMemento(this.id, scope, target, this.storageService);
32
Memento.workspaceMementos.set(this.id, workspaceMemento);
33
}
34
35
return workspaceMemento.getMemento();
36
}
37
38
case StorageScope.PROFILE: {
39
let profileMemento = Memento.profileMementos.get(this.id);
40
if (!profileMemento) {
41
profileMemento = new ScopedMemento(this.id, scope, target, this.storageService);
42
Memento.profileMementos.set(this.id, profileMemento);
43
}
44
45
return profileMemento.getMemento();
46
}
47
48
case StorageScope.APPLICATION: {
49
let applicationMemento = Memento.applicationMementos.get(this.id);
50
if (!applicationMemento) {
51
applicationMemento = new ScopedMemento(this.id, scope, target, this.storageService);
52
Memento.applicationMementos.set(this.id, applicationMemento);
53
}
54
55
return applicationMemento.getMemento();
56
}
57
}
58
}
59
60
onDidChangeValue(scope: StorageScope, disposables: DisposableStore): Event<IStorageValueChangeEvent> {
61
return this.storageService.onDidChangeValue(scope, this.id, disposables);
62
}
63
64
saveMemento(): void {
65
Memento.workspaceMementos.get(this.id)?.save();
66
Memento.profileMementos.get(this.id)?.save();
67
Memento.applicationMementos.get(this.id)?.save();
68
}
69
70
reloadMemento(scope: StorageScope): void {
71
let memento: ScopedMemento<unknown> | undefined;
72
switch (scope) {
73
case StorageScope.APPLICATION:
74
memento = Memento.applicationMementos.get(this.id);
75
break;
76
case StorageScope.PROFILE:
77
memento = Memento.profileMementos.get(this.id);
78
break;
79
case StorageScope.WORKSPACE:
80
memento = Memento.workspaceMementos.get(this.id);
81
break;
82
}
83
84
memento?.reload();
85
}
86
87
static clear(scope: StorageScope): void {
88
switch (scope) {
89
case StorageScope.WORKSPACE:
90
Memento.workspaceMementos.clear();
91
break;
92
case StorageScope.PROFILE:
93
Memento.profileMementos.clear();
94
break;
95
case StorageScope.APPLICATION:
96
Memento.applicationMementos.clear();
97
break;
98
}
99
}
100
}
101
102
class ScopedMemento<T> {
103
104
private mementoObj: Partial<T>;
105
106
constructor(private id: string, private scope: StorageScope, private target: StorageTarget, private storageService: IStorageService) {
107
this.mementoObj = this.doLoad();
108
}
109
110
private doLoad(): Partial<T> {
111
try {
112
return this.storageService.getObject(this.id, this.scope, {});
113
} catch (error) {
114
// Seeing reports from users unable to open editors
115
// from memento parsing exceptions. Log the contents
116
// to diagnose further
117
// https://github.com/microsoft/vscode/issues/102251
118
onUnexpectedError(`[memento]: failed to parse contents: ${error} (id: ${this.id}, scope: ${this.scope}, contents: ${this.storageService.get(this.id, this.scope)})`);
119
}
120
121
return {};
122
}
123
124
getMemento(): Partial<T> {
125
return this.mementoObj;
126
}
127
128
reload(): void {
129
130
// Clear old
131
for (const name of Object.getOwnPropertyNames(this.mementoObj)) {
132
delete this.mementoObj[name as keyof Partial<T>];
133
}
134
135
// Assign new
136
Object.assign(this.mementoObj, this.doLoad());
137
}
138
139
save(): void {
140
if (!isEmptyObject(this.mementoObj)) {
141
this.storageService.store(this.id, this.mementoObj, this.scope, this.target);
142
} else {
143
this.storageService.remove(this.id, this.scope);
144
}
145
}
146
}
147
148