@theia/test 1.45.1 → 1.46.0-next.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/constants.d.ts +45 -45
- package/lib/browser/constants.js +17 -17
- package/lib/browser/test-service.d.ts +154 -154
- package/lib/browser/test-service.js +247 -247
- package/lib/browser/view/test-context-key-service.d.ts +7 -7
- package/lib/browser/view/test-context-key-service.js +51 -51
- package/lib/browser/view/test-execution-state-manager.d.ts +13 -13
- package/lib/browser/view/test-execution-state-manager.js +173 -173
- package/lib/browser/view/test-output-ui-model.d.ts +47 -47
- package/lib/browser/view/test-output-ui-model.js +151 -151
- package/lib/browser/view/test-output-view-contribution.d.ts +5 -5
- package/lib/browser/view/test-output-view-contribution.js +47 -47
- package/lib/browser/view/test-output-widget.d.ts +24 -24
- package/lib/browser/view/test-output-widget.js +158 -158
- package/lib/browser/view/test-result-view-contribution.d.ts +5 -5
- package/lib/browser/view/test-result-view-contribution.js +47 -47
- package/lib/browser/view/test-result-widget.d.ts +20 -20
- package/lib/browser/view/test-result-widget.js +108 -108
- package/lib/browser/view/test-run-view-contribution.d.ts +17 -17
- package/lib/browser/view/test-run-view-contribution.js +100 -100
- package/lib/browser/view/test-run-widget.d.ts +58 -58
- package/lib/browser/view/test-run-widget.js +310 -310
- package/lib/browser/view/test-tree-widget.d.ts +67 -67
- package/lib/browser/view/test-tree-widget.js +386 -386
- package/lib/browser/view/test-view-contribution.d.ts +45 -45
- package/lib/browser/view/test-view-contribution.js +288 -288
- package/lib/browser/view/test-view-frontend-module.d.ts +6 -6
- package/lib/browser/view/test-view-frontend-module.js +121 -121
- package/lib/common/collections.d.ts +46 -46
- package/lib/common/collections.js +210 -210
- package/lib/common/tree-delta.d.ts +51 -51
- package/lib/common/tree-delta.js +240 -240
- package/lib/common/tree-delta.spec.d.ts +1 -1
- package/lib/common/tree-delta.spec.js +139 -139
- package/package.json +8 -8
- package/src/browser/constants.ts +71 -71
- package/src/browser/style/index.css +41 -41
- package/src/browser/test-service.ts +355 -355
- package/src/browser/view/test-context-key-service.ts +36 -36
- package/src/browser/view/test-execution-state-manager.ts +147 -147
- package/src/browser/view/test-output-ui-model.ts +156 -156
- package/src/browser/view/test-output-view-contribution.ts +34 -34
- package/src/browser/view/test-output-widget.ts +148 -148
- package/src/browser/view/test-result-view-contribution.ts +34 -34
- package/src/browser/view/test-result-widget.ts +92 -92
- package/src/browser/view/test-run-view-contribution.ts +89 -89
- package/src/browser/view/test-run-widget.tsx +271 -271
- package/src/browser/view/test-tree-widget.tsx +360 -360
- package/src/browser/view/test-view-contribution.ts +300 -300
- package/src/browser/view/test-view-frontend-module.ts +134 -134
- package/src/common/collections.ts +223 -223
- package/src/common/tree-delta.spec.ts +166 -166
- package/src/common/tree-delta.ts +259 -259
package/src/common/tree-delta.ts
CHANGED
|
@@ -1,259 +1,259 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2022 STMicroelectronics and others.
|
|
3
|
-
//
|
|
4
|
-
// This program and the accompanying materials are made available under the
|
|
5
|
-
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
-
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
-
//
|
|
8
|
-
// This Source Code may also be made available under the following Secondary
|
|
9
|
-
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
-
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
-
// with the GNU Classpath Exception which is available at
|
|
12
|
-
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
-
//
|
|
14
|
-
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
-
// *****************************************************************************
|
|
16
|
-
|
|
17
|
-
import { Emitter, Event } from '@theia/core';
|
|
18
|
-
import { ChangeBatcher } from './collections';
|
|
19
|
-
|
|
20
|
-
export interface CollectionDelta<K, T> {
|
|
21
|
-
added?: T[];
|
|
22
|
-
removed?: K[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export enum DeltaKind {
|
|
26
|
-
NONE, ADDED, REMOVED, CHANGED
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface TreeDelta<K, T> {
|
|
30
|
-
path: K[];
|
|
31
|
-
type: DeltaKind;
|
|
32
|
-
value?: Partial<T>;
|
|
33
|
-
childDeltas?: TreeDelta<K, T>[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface TreeDeltaBuilder<K, T> {
|
|
37
|
-
reportAdded(path: K[], added: T): void;
|
|
38
|
-
reportRemoved(path: K[]): void;
|
|
39
|
-
reportChanged(path: K[], change: Partial<T>): void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export class MappingTreeDeltaBuilder<K, T, V> implements TreeDeltaBuilder<K, V> {
|
|
43
|
-
constructor(private readonly wrapped: TreeDeltaBuilder<K, T>, private readonly map: (value: V) => T, private readonly mapPartial: (value: Partial<V>) => Partial<T>) { }
|
|
44
|
-
reportAdded(path: K[], added: V): void {
|
|
45
|
-
this.wrapped.reportAdded(path, this.map(added));
|
|
46
|
-
}
|
|
47
|
-
reportRemoved(path: K[]): void {
|
|
48
|
-
this.wrapped.reportRemoved(path);
|
|
49
|
-
}
|
|
50
|
-
reportChanged(path: K[], change: Partial<V>): void {
|
|
51
|
-
this.wrapped.reportChanged(path, this.mapPartial(change));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class TreeDeltaBuilderImpl<K, T> {
|
|
56
|
-
protected _currentDelta: TreeDelta<K, T>[] = [];
|
|
57
|
-
|
|
58
|
-
get currentDelta(): TreeDelta<K, T>[] {
|
|
59
|
-
return this._currentDelta;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
reportAdded(path: K[], added: T): void {
|
|
63
|
-
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
64
|
-
if (residual.length === 0) {
|
|
65
|
-
// we matched an exact node
|
|
66
|
-
const child = parentCollection[nodeIndex];
|
|
67
|
-
if (child.type === DeltaKind.REMOVED) {
|
|
68
|
-
child.type = DeltaKind.CHANGED;
|
|
69
|
-
} else if (child.type === DeltaKind.NONE) {
|
|
70
|
-
child.type = DeltaKind.ADDED;
|
|
71
|
-
}
|
|
72
|
-
child.value = added;
|
|
73
|
-
} else {
|
|
74
|
-
this.insert(parentCollection, nodeIndex, {
|
|
75
|
-
path: residual,
|
|
76
|
-
type: DeltaKind.ADDED,
|
|
77
|
-
value: added,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
reportRemoved(path: K[]): void {
|
|
84
|
-
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
85
|
-
if (residual.length === 0) {
|
|
86
|
-
// we matched an exact node
|
|
87
|
-
const child = parentCollection[nodeIndex];
|
|
88
|
-
if (child.type === DeltaKind.CHANGED) {
|
|
89
|
-
child.type = DeltaKind.REMOVED;
|
|
90
|
-
delete child.value;
|
|
91
|
-
} else if (child.type === DeltaKind.ADDED) {
|
|
92
|
-
parentCollection.splice(nodeIndex, 1);
|
|
93
|
-
} else if (child.type === DeltaKind.NONE) {
|
|
94
|
-
child.type = DeltaKind.REMOVED;
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
this.insert(parentCollection, nodeIndex, {
|
|
98
|
-
path: residual,
|
|
99
|
-
type: DeltaKind.REMOVED,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
reportChanged(path: K[], change: Partial<T>): void {
|
|
107
|
-
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
108
|
-
if (residual.length === 0) {
|
|
109
|
-
// we matched an exact node
|
|
110
|
-
const child = parentCollection[nodeIndex];
|
|
111
|
-
if (child.type === DeltaKind.NONE) {
|
|
112
|
-
child.type = DeltaKind.CHANGED;
|
|
113
|
-
child.value = change;
|
|
114
|
-
} else if (child.type === DeltaKind.CHANGED) {
|
|
115
|
-
Object.assign(child.value!, change);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
this.insert(parentCollection, nodeIndex, {
|
|
119
|
-
path: residual,
|
|
120
|
-
type: DeltaKind.CHANGED,
|
|
121
|
-
value: change,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private insert(parentCollection: TreeDelta<K, T>[], nodeIndex: number, delta: TreeDelta<K, T>): void {
|
|
129
|
-
if (nodeIndex < 0) {
|
|
130
|
-
parentCollection.push(delta);
|
|
131
|
-
} else {
|
|
132
|
-
const child = parentCollection[nodeIndex];
|
|
133
|
-
const prefixLength = computePrefixLength(delta.path, child.path);
|
|
134
|
-
|
|
135
|
-
if (prefixLength === delta.path.length) {
|
|
136
|
-
child.path = child.path.slice(prefixLength);
|
|
137
|
-
delta.childDeltas = [child];
|
|
138
|
-
parentCollection[nodeIndex] = delta;
|
|
139
|
-
} else {
|
|
140
|
-
const newNode: TreeDelta<K, T> = {
|
|
141
|
-
path: child.path.slice(0, prefixLength),
|
|
142
|
-
type: DeltaKind.NONE,
|
|
143
|
-
childDeltas: []
|
|
144
|
-
};
|
|
145
|
-
parentCollection[nodeIndex] = newNode;
|
|
146
|
-
delta.path = delta.path.slice(prefixLength);
|
|
147
|
-
newNode.childDeltas!.push(delta);
|
|
148
|
-
child.path = child.path.slice(prefixLength);
|
|
149
|
-
newNode.childDeltas!.push(child);
|
|
150
|
-
if (newNode.path.length === 0) {
|
|
151
|
-
console.log('newNode');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (delta.path.length === 0) {
|
|
155
|
-
console.log('delta');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (child.path.length === 0) {
|
|
159
|
-
console.log('child');
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private findNode(path: K[], handler: (parentCollection: TreeDelta<K, T>[], nodeIndex: number, residualPath: K[]) => void): void {
|
|
165
|
-
doFindNode(this._currentDelta, path, handler);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function doFindNode<K, T>(rootCollection: TreeDelta<K, T>[], path: K[],
|
|
170
|
-
handler: (parentCollection: TreeDelta<K, T>[], nodeIndex: number, residualPath: K[]) => void): void {
|
|
171
|
-
// handler parameters:
|
|
172
|
-
// parent collection: the collection the node index refers to, if valid
|
|
173
|
-
// nodeIndex: the index of the node that has a common path prefix with the path of the path we're searching
|
|
174
|
-
// residual path: the path that has not been consumed looking for the path: if empty, we found the exact node
|
|
175
|
-
|
|
176
|
-
let commonPrefixLength = 0;
|
|
177
|
-
const childIndex = rootCollection.findIndex(delta => {
|
|
178
|
-
commonPrefixLength = computePrefixLength(delta.path, path);
|
|
179
|
-
return commonPrefixLength > 0;
|
|
180
|
-
});
|
|
181
|
-
if (childIndex >= 0) {
|
|
182
|
-
// we know which child to insert into
|
|
183
|
-
const child = rootCollection[childIndex];
|
|
184
|
-
|
|
185
|
-
if (commonPrefixLength === child.path.length) {
|
|
186
|
-
// we matched a child
|
|
187
|
-
if (commonPrefixLength === path.length) {
|
|
188
|
-
// it's an exact match: we already have a node for the given path
|
|
189
|
-
handler(rootCollection, childIndex, []);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
// we know the node is below the child
|
|
193
|
-
if (child.type === DeltaKind.REMOVED || child.type === DeltaKind.ADDED) {
|
|
194
|
-
// there will be no children deltas beneath added/remove nodes
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (!child.childDeltas) {
|
|
198
|
-
child.childDeltas = [];
|
|
199
|
-
}
|
|
200
|
-
doFindNode(child.childDeltas, path.slice(child.path.length), handler);
|
|
201
|
-
} else {
|
|
202
|
-
handler(rootCollection, childIndex, path);
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
// we have no node to insert into
|
|
206
|
-
handler(rootCollection, -1, path);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function computePrefixLength<K>(left: K[], right: K[]): number {
|
|
211
|
-
let i = 0;
|
|
212
|
-
while (i < left.length && i < right.length && left[i] === right[i]) {
|
|
213
|
-
i++;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return i;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export class AccumulatingTreeDeltaEmitter<K, T> extends TreeDeltaBuilderImpl<K, T> {
|
|
220
|
-
private batcher: ChangeBatcher;
|
|
221
|
-
private onDidFlushEmitter: Emitter<TreeDelta<K, T>[]> = new Emitter();
|
|
222
|
-
onDidFlush: Event<TreeDelta<K, T>[]> = this.onDidFlushEmitter.event;
|
|
223
|
-
|
|
224
|
-
constructor(timeoutMillis: number) {
|
|
225
|
-
super();
|
|
226
|
-
this.batcher = new ChangeBatcher(() => this.doEmitDelta(), timeoutMillis);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
flush(): void {
|
|
230
|
-
this.batcher.flush();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
doEmitDelta(): void {
|
|
234
|
-
const batch = this._currentDelta;
|
|
235
|
-
this._currentDelta = [];
|
|
236
|
-
this.onDidFlushEmitter.fire(batch);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
override reportAdded(path: K[], added: T): void {
|
|
240
|
-
super.reportAdded(path, added);
|
|
241
|
-
// console.debug(`reported added, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
242
|
-
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
243
|
-
this.batcher.changeOccurred();
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
override reportChanged(path: K[], change: Partial<T>): void {
|
|
247
|
-
super.reportChanged(path, change);
|
|
248
|
-
// console.debug(`reported changed, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
249
|
-
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
250
|
-
this.batcher.changeOccurred();
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
override reportRemoved(path: K[]): void {
|
|
254
|
-
super.reportRemoved(path);
|
|
255
|
-
// console.debug(`reported removed, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
256
|
-
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
257
|
-
this.batcher.changeOccurred();
|
|
258
|
-
}
|
|
259
|
-
}
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 STMicroelectronics and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { Emitter, Event } from '@theia/core';
|
|
18
|
+
import { ChangeBatcher } from './collections';
|
|
19
|
+
|
|
20
|
+
export interface CollectionDelta<K, T> {
|
|
21
|
+
added?: T[];
|
|
22
|
+
removed?: K[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export enum DeltaKind {
|
|
26
|
+
NONE, ADDED, REMOVED, CHANGED
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TreeDelta<K, T> {
|
|
30
|
+
path: K[];
|
|
31
|
+
type: DeltaKind;
|
|
32
|
+
value?: Partial<T>;
|
|
33
|
+
childDeltas?: TreeDelta<K, T>[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TreeDeltaBuilder<K, T> {
|
|
37
|
+
reportAdded(path: K[], added: T): void;
|
|
38
|
+
reportRemoved(path: K[]): void;
|
|
39
|
+
reportChanged(path: K[], change: Partial<T>): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class MappingTreeDeltaBuilder<K, T, V> implements TreeDeltaBuilder<K, V> {
|
|
43
|
+
constructor(private readonly wrapped: TreeDeltaBuilder<K, T>, private readonly map: (value: V) => T, private readonly mapPartial: (value: Partial<V>) => Partial<T>) { }
|
|
44
|
+
reportAdded(path: K[], added: V): void {
|
|
45
|
+
this.wrapped.reportAdded(path, this.map(added));
|
|
46
|
+
}
|
|
47
|
+
reportRemoved(path: K[]): void {
|
|
48
|
+
this.wrapped.reportRemoved(path);
|
|
49
|
+
}
|
|
50
|
+
reportChanged(path: K[], change: Partial<V>): void {
|
|
51
|
+
this.wrapped.reportChanged(path, this.mapPartial(change));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class TreeDeltaBuilderImpl<K, T> {
|
|
56
|
+
protected _currentDelta: TreeDelta<K, T>[] = [];
|
|
57
|
+
|
|
58
|
+
get currentDelta(): TreeDelta<K, T>[] {
|
|
59
|
+
return this._currentDelta;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
reportAdded(path: K[], added: T): void {
|
|
63
|
+
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
64
|
+
if (residual.length === 0) {
|
|
65
|
+
// we matched an exact node
|
|
66
|
+
const child = parentCollection[nodeIndex];
|
|
67
|
+
if (child.type === DeltaKind.REMOVED) {
|
|
68
|
+
child.type = DeltaKind.CHANGED;
|
|
69
|
+
} else if (child.type === DeltaKind.NONE) {
|
|
70
|
+
child.type = DeltaKind.ADDED;
|
|
71
|
+
}
|
|
72
|
+
child.value = added;
|
|
73
|
+
} else {
|
|
74
|
+
this.insert(parentCollection, nodeIndex, {
|
|
75
|
+
path: residual,
|
|
76
|
+
type: DeltaKind.ADDED,
|
|
77
|
+
value: added,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
reportRemoved(path: K[]): void {
|
|
84
|
+
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
85
|
+
if (residual.length === 0) {
|
|
86
|
+
// we matched an exact node
|
|
87
|
+
const child = parentCollection[nodeIndex];
|
|
88
|
+
if (child.type === DeltaKind.CHANGED) {
|
|
89
|
+
child.type = DeltaKind.REMOVED;
|
|
90
|
+
delete child.value;
|
|
91
|
+
} else if (child.type === DeltaKind.ADDED) {
|
|
92
|
+
parentCollection.splice(nodeIndex, 1);
|
|
93
|
+
} else if (child.type === DeltaKind.NONE) {
|
|
94
|
+
child.type = DeltaKind.REMOVED;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
this.insert(parentCollection, nodeIndex, {
|
|
98
|
+
path: residual,
|
|
99
|
+
type: DeltaKind.REMOVED,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
reportChanged(path: K[], change: Partial<T>): void {
|
|
107
|
+
this.findNode(path, (parentCollection, nodeIndex, residual) => {
|
|
108
|
+
if (residual.length === 0) {
|
|
109
|
+
// we matched an exact node
|
|
110
|
+
const child = parentCollection[nodeIndex];
|
|
111
|
+
if (child.type === DeltaKind.NONE) {
|
|
112
|
+
child.type = DeltaKind.CHANGED;
|
|
113
|
+
child.value = change;
|
|
114
|
+
} else if (child.type === DeltaKind.CHANGED) {
|
|
115
|
+
Object.assign(child.value!, change);
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
this.insert(parentCollection, nodeIndex, {
|
|
119
|
+
path: residual,
|
|
120
|
+
type: DeltaKind.CHANGED,
|
|
121
|
+
value: change,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private insert(parentCollection: TreeDelta<K, T>[], nodeIndex: number, delta: TreeDelta<K, T>): void {
|
|
129
|
+
if (nodeIndex < 0) {
|
|
130
|
+
parentCollection.push(delta);
|
|
131
|
+
} else {
|
|
132
|
+
const child = parentCollection[nodeIndex];
|
|
133
|
+
const prefixLength = computePrefixLength(delta.path, child.path);
|
|
134
|
+
|
|
135
|
+
if (prefixLength === delta.path.length) {
|
|
136
|
+
child.path = child.path.slice(prefixLength);
|
|
137
|
+
delta.childDeltas = [child];
|
|
138
|
+
parentCollection[nodeIndex] = delta;
|
|
139
|
+
} else {
|
|
140
|
+
const newNode: TreeDelta<K, T> = {
|
|
141
|
+
path: child.path.slice(0, prefixLength),
|
|
142
|
+
type: DeltaKind.NONE,
|
|
143
|
+
childDeltas: []
|
|
144
|
+
};
|
|
145
|
+
parentCollection[nodeIndex] = newNode;
|
|
146
|
+
delta.path = delta.path.slice(prefixLength);
|
|
147
|
+
newNode.childDeltas!.push(delta);
|
|
148
|
+
child.path = child.path.slice(prefixLength);
|
|
149
|
+
newNode.childDeltas!.push(child);
|
|
150
|
+
if (newNode.path.length === 0) {
|
|
151
|
+
console.log('newNode');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (delta.path.length === 0) {
|
|
155
|
+
console.log('delta');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (child.path.length === 0) {
|
|
159
|
+
console.log('child');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private findNode(path: K[], handler: (parentCollection: TreeDelta<K, T>[], nodeIndex: number, residualPath: K[]) => void): void {
|
|
165
|
+
doFindNode(this._currentDelta, path, handler);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function doFindNode<K, T>(rootCollection: TreeDelta<K, T>[], path: K[],
|
|
170
|
+
handler: (parentCollection: TreeDelta<K, T>[], nodeIndex: number, residualPath: K[]) => void): void {
|
|
171
|
+
// handler parameters:
|
|
172
|
+
// parent collection: the collection the node index refers to, if valid
|
|
173
|
+
// nodeIndex: the index of the node that has a common path prefix with the path of the path we're searching
|
|
174
|
+
// residual path: the path that has not been consumed looking for the path: if empty, we found the exact node
|
|
175
|
+
|
|
176
|
+
let commonPrefixLength = 0;
|
|
177
|
+
const childIndex = rootCollection.findIndex(delta => {
|
|
178
|
+
commonPrefixLength = computePrefixLength(delta.path, path);
|
|
179
|
+
return commonPrefixLength > 0;
|
|
180
|
+
});
|
|
181
|
+
if (childIndex >= 0) {
|
|
182
|
+
// we know which child to insert into
|
|
183
|
+
const child = rootCollection[childIndex];
|
|
184
|
+
|
|
185
|
+
if (commonPrefixLength === child.path.length) {
|
|
186
|
+
// we matched a child
|
|
187
|
+
if (commonPrefixLength === path.length) {
|
|
188
|
+
// it's an exact match: we already have a node for the given path
|
|
189
|
+
handler(rootCollection, childIndex, []);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// we know the node is below the child
|
|
193
|
+
if (child.type === DeltaKind.REMOVED || child.type === DeltaKind.ADDED) {
|
|
194
|
+
// there will be no children deltas beneath added/remove nodes
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (!child.childDeltas) {
|
|
198
|
+
child.childDeltas = [];
|
|
199
|
+
}
|
|
200
|
+
doFindNode(child.childDeltas, path.slice(child.path.length), handler);
|
|
201
|
+
} else {
|
|
202
|
+
handler(rootCollection, childIndex, path);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
// we have no node to insert into
|
|
206
|
+
handler(rootCollection, -1, path);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function computePrefixLength<K>(left: K[], right: K[]): number {
|
|
211
|
+
let i = 0;
|
|
212
|
+
while (i < left.length && i < right.length && left[i] === right[i]) {
|
|
213
|
+
i++;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return i;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export class AccumulatingTreeDeltaEmitter<K, T> extends TreeDeltaBuilderImpl<K, T> {
|
|
220
|
+
private batcher: ChangeBatcher;
|
|
221
|
+
private onDidFlushEmitter: Emitter<TreeDelta<K, T>[]> = new Emitter();
|
|
222
|
+
onDidFlush: Event<TreeDelta<K, T>[]> = this.onDidFlushEmitter.event;
|
|
223
|
+
|
|
224
|
+
constructor(timeoutMillis: number) {
|
|
225
|
+
super();
|
|
226
|
+
this.batcher = new ChangeBatcher(() => this.doEmitDelta(), timeoutMillis);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
flush(): void {
|
|
230
|
+
this.batcher.flush();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
doEmitDelta(): void {
|
|
234
|
+
const batch = this._currentDelta;
|
|
235
|
+
this._currentDelta = [];
|
|
236
|
+
this.onDidFlushEmitter.fire(batch);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
override reportAdded(path: K[], added: T): void {
|
|
240
|
+
super.reportAdded(path, added);
|
|
241
|
+
// console.debug(`reported added, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
242
|
+
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
243
|
+
this.batcher.changeOccurred();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
override reportChanged(path: K[], change: Partial<T>): void {
|
|
247
|
+
super.reportChanged(path, change);
|
|
248
|
+
// console.debug(`reported changed, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
249
|
+
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
250
|
+
this.batcher.changeOccurred();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
override reportRemoved(path: K[]): void {
|
|
254
|
+
super.reportRemoved(path);
|
|
255
|
+
// console.debug(`reported removed, now: ${JSON.stringify(path, undefined, 3)}`);
|
|
256
|
+
// logging levels don't work in plugin host: https://github.com/eclipse-theia/theia/issues/12234
|
|
257
|
+
this.batcher.changeOccurred();
|
|
258
|
+
}
|
|
259
|
+
}
|