@fluidframework/matrix 2.0.0-internal.4.3.0 → 2.0.0-internal.5.0.0
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/CHANGELOG.md +8 -0
- package/dist/matrix.d.ts +3 -3
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +4 -26
- package/dist/matrix.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/permutationvector.d.ts +5 -12
- package/dist/permutationvector.d.ts.map +1 -1
- package/dist/permutationvector.js +24 -40
- package/dist/permutationvector.js.map +1 -1
- package/dist/serialization.d.ts +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +2 -2
- package/dist/serialization.js.map +1 -1
- package/dist/undoprovider.d.ts +6 -8
- package/dist/undoprovider.d.ts.map +1 -1
- package/dist/undoprovider.js +74 -62
- package/dist/undoprovider.js.map +1 -1
- package/lib/matrix.d.ts +3 -3
- package/lib/matrix.d.ts.map +1 -1
- package/lib/matrix.js +5 -27
- package/lib/matrix.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/permutationvector.d.ts +5 -12
- package/lib/permutationvector.d.ts.map +1 -1
- package/lib/permutationvector.js +23 -40
- package/lib/permutationvector.js.map +1 -1
- package/lib/serialization.d.ts +1 -1
- package/lib/serialization.d.ts.map +1 -1
- package/lib/serialization.js +1 -1
- package/lib/serialization.js.map +1 -1
- package/lib/undoprovider.d.ts +6 -8
- package/lib/undoprovider.d.ts.map +1 -1
- package/lib/undoprovider.js +75 -63
- package/lib/undoprovider.js.map +1 -1
- package/package.json +12 -12
- package/src/matrix.ts +6 -38
- package/src/packageVersion.ts +1 -1
- package/src/permutationvector.ts +33 -46
- package/src/serialization.ts +1 -1
- package/src/undoprovider.ts +83 -74
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"undoprovider.d.ts","sourceRoot":"","sources":["../src/undoprovider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"undoprovider.d.ts","sourceRoot":"","sources":["../src/undoprovider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGN,2BAA2B,EAG3B,yBAAyB,EAIzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAsB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,qBAAa,kBAAkB;IAS7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANxB,OAAO,CAAC,YAAY,CAAC,CAA6B;IAClD,OAAO,CAAC,SAAS,CAAC,CAAqB;IACvC,OAAO,CAAC,0BAA0B,CAAC,CAAgB;gBAGjC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,yBAAyB;IAG5C,MAAM,CAAC,SAAS,EAAE,2BAA2B;IAuDpD,OAAO,CAAC,cAAc;CAgDtB;AAED,qBAAa,kBAAkB,CAAC,CAAC;IAE/B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAHJ,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,iBAAiB;IA0BzC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;CAoBrE"}
|
package/lib/undoprovider.js
CHANGED
|
@@ -3,48 +3,47 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { assert } from "@fluidframework/common-utils";
|
|
6
|
-
import {
|
|
6
|
+
import { MergeTreeDeltaType, appendToMergeTreeDeltaRevertibles, revertMergeTreeDeltaRevertibles, discardMergeTreeDeltaRevertible, TrackingGroup, } from "@fluidframework/merge-tree";
|
|
7
7
|
import { isHandleValid } from "./handletable";
|
|
8
8
|
export class VectorUndoProvider {
|
|
9
|
-
constructor(manager,
|
|
9
|
+
constructor(manager, driver) {
|
|
10
10
|
this.manager = manager;
|
|
11
|
-
this.
|
|
12
|
-
this.undoRemove = undoRemove;
|
|
11
|
+
this.driver = driver;
|
|
13
12
|
}
|
|
14
|
-
record(
|
|
15
|
-
var _a;
|
|
16
|
-
if (
|
|
17
|
-
// Link each segment to a new TrackingGroup. A TrackingGroup keeps track of the original
|
|
18
|
-
// set of linked segments, including any fragmentatiton that occurs due to future splitting.
|
|
19
|
-
//
|
|
20
|
-
// A TrackingGroup also prevents removed segments from being unlinked from the tree during
|
|
21
|
-
// Zamboni and guarantees segments will not be merged/coalesced with segments outside of the
|
|
22
|
-
// current tracking group.
|
|
23
|
-
//
|
|
24
|
-
// These properties allow us to rely on MergeTree.getPosition() to find the locations/lengths
|
|
25
|
-
// of all content contained within the tracking group in the future.
|
|
13
|
+
record(deltaArgs) {
|
|
14
|
+
var _a, _b, _c, _d;
|
|
15
|
+
if (deltaArgs.deltaSegments.length > 0) {
|
|
26
16
|
// If we are in the process of reverting, the `IRevertible.revert()` will provide the tracking
|
|
27
17
|
// group so that we can preserve the original segment ranges as a single op/group as we move
|
|
28
18
|
// ops between the undo <-> redo stacks.
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
trackingGroup.link(range.segment);
|
|
32
|
-
}
|
|
19
|
+
const revertibles = (_a = this.currentGroup) !== null && _a !== void 0 ? _a : [];
|
|
20
|
+
appendToMergeTreeDeltaRevertibles(deltaArgs, revertibles);
|
|
33
21
|
// For SharedMatrix, each IRevertibles always holds a single row/col operation.
|
|
34
22
|
// Therefore, 'currentOp' must either be undefined or equal to the current op.
|
|
35
|
-
assert(this.currentOp === undefined || this.currentOp === operation, 0x02a /* "On vector undo, unexpected 'currentOp' type/state!" */);
|
|
36
|
-
|
|
23
|
+
assert(this.currentOp === undefined || this.currentOp === deltaArgs.operation, 0x02a /* "On vector undo, unexpected 'currentOp' type/state!" */);
|
|
24
|
+
let removeTrackingGroup;
|
|
25
|
+
if (deltaArgs.operation === MergeTreeDeltaType.REMOVE) {
|
|
26
|
+
// for removed segment we need a tracking group.
|
|
27
|
+
// this is for a few reason:
|
|
28
|
+
// 1. the handle for the row/column on the removed segment is still allocated,
|
|
29
|
+
// and needs to be in order to process unacked ops sent before the remove.
|
|
30
|
+
// 2. handles are freed on unlink(zamboni), but that also clears the row/column data.
|
|
31
|
+
// which we don't want to happen, so we can re-insert the cells when the row/col comes back.
|
|
32
|
+
// the tracking group prevents unlink.
|
|
33
|
+
// 3. when we re-insert we need to find the old segment and clear their handles
|
|
34
|
+
// so the new segment takes them over. there is no efficient look-up for this.
|
|
35
|
+
// the tracking group provides one.
|
|
36
|
+
const trackingGroup = (removeTrackingGroup =
|
|
37
|
+
(_b = this.currentRemoveTrackingGroup) !== null && _b !== void 0 ? _b : new TrackingGroup());
|
|
38
|
+
deltaArgs.deltaSegments.forEach((d) => d.segment.trackingCollection.link(trackingGroup));
|
|
39
|
+
}
|
|
40
|
+
switch (deltaArgs.operation) {
|
|
41
|
+
case MergeTreeDeltaType.REMOVE:
|
|
37
42
|
case MergeTreeDeltaType.INSERT:
|
|
38
|
-
if (this.currentOp !==
|
|
39
|
-
this.pushRevertible(
|
|
40
|
-
}
|
|
41
|
-
break;
|
|
42
|
-
case MergeTreeDeltaType.REMOVE: {
|
|
43
|
-
if (this.currentOp !== MergeTreeDeltaType.REMOVE) {
|
|
44
|
-
this.pushRevertible(trackingGroup, this.undoRemove);
|
|
43
|
+
if (this.currentOp !== deltaArgs.operation) {
|
|
44
|
+
this.pushRevertible(revertibles, removeTrackingGroup);
|
|
45
45
|
}
|
|
46
46
|
break;
|
|
47
|
-
}
|
|
48
47
|
default:
|
|
49
48
|
throw new Error("operation type not revertible");
|
|
50
49
|
}
|
|
@@ -52,38 +51,49 @@ export class VectorUndoProvider {
|
|
|
52
51
|
// another revertible until `IRevertable.revert()` finishes the current op and clears this
|
|
53
52
|
// field.
|
|
54
53
|
if (this.currentGroup !== undefined) {
|
|
55
|
-
this.currentOp = operation;
|
|
54
|
+
(_c = this.currentOp) !== null && _c !== void 0 ? _c : (this.currentOp = deltaArgs.operation);
|
|
55
|
+
(_d = this.currentRemoveTrackingGroup) !== null && _d !== void 0 ? _d : (this.currentRemoveTrackingGroup = removeTrackingGroup);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
pushRevertible(
|
|
60
|
-
const
|
|
59
|
+
pushRevertible(revertibles, removedTrackingGroup) {
|
|
60
|
+
const reverter = {
|
|
61
61
|
revert: () => {
|
|
62
62
|
assert(this.currentGroup === undefined && this.currentOp === undefined, 0x02b /* "Must not nest calls to IRevertible.revert()" */);
|
|
63
|
-
this.currentGroup =
|
|
63
|
+
this.currentGroup = [];
|
|
64
64
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
if (removedTrackingGroup !== undefined) {
|
|
66
|
+
while (removedTrackingGroup.size > 0) {
|
|
67
|
+
const tracked = removedTrackingGroup.tracked[0];
|
|
68
|
+
removedTrackingGroup.unlink(tracked);
|
|
69
|
+
// if there are groups tracked, this in a revert of a remove.
|
|
70
|
+
// this means we are about to re-insert the row/column
|
|
71
|
+
// with the same handle. We reuse the handle so the row/columns cells
|
|
72
|
+
// get re-inserted too.
|
|
73
|
+
// since a new segment will have the handle, we need to
|
|
74
|
+
// remove it from the removed segment which was tracked
|
|
75
|
+
tracked.reset();
|
|
76
|
+
}
|
|
72
77
|
}
|
|
78
|
+
revertMergeTreeDeltaRevertibles(this.driver, revertibles);
|
|
73
79
|
}
|
|
74
80
|
finally {
|
|
75
81
|
this.currentOp = undefined;
|
|
76
82
|
this.currentGroup = undefined;
|
|
83
|
+
this.currentRemoveTrackingGroup = undefined;
|
|
77
84
|
}
|
|
78
85
|
},
|
|
79
86
|
discard: () => {
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
if (removedTrackingGroup !== undefined) {
|
|
88
|
+
while (removedTrackingGroup.size > 0) {
|
|
89
|
+
removedTrackingGroup.unlink(removedTrackingGroup.tracked[0]);
|
|
90
|
+
}
|
|
82
91
|
}
|
|
92
|
+
discardMergeTreeDeltaRevertible(revertibles);
|
|
83
93
|
},
|
|
84
94
|
};
|
|
85
|
-
this.manager.pushToCurrentOperation(
|
|
86
|
-
return
|
|
95
|
+
this.manager.pushToCurrentOperation(reverter);
|
|
96
|
+
return reverter;
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
99
|
export class MatrixUndoProvider {
|
|
@@ -92,25 +102,27 @@ export class MatrixUndoProvider {
|
|
|
92
102
|
this.matrix = matrix;
|
|
93
103
|
this.rows = rows;
|
|
94
104
|
this.cols = cols;
|
|
95
|
-
rows.undo = new VectorUndoProvider(consumer,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
rows.undo = new VectorUndoProvider(consumer, {
|
|
106
|
+
annotateRange() {
|
|
107
|
+
throw new Error("not implemented");
|
|
108
|
+
},
|
|
109
|
+
insertFromSpec(pos, spec) {
|
|
110
|
+
matrix._undoRemoveRows(pos, spec);
|
|
111
|
+
},
|
|
112
|
+
removeRange(start, end) {
|
|
113
|
+
matrix.removeRows(start, end - start);
|
|
114
|
+
},
|
|
104
115
|
});
|
|
105
|
-
cols.undo = new VectorUndoProvider(consumer,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
cols.undo = new VectorUndoProvider(consumer, {
|
|
117
|
+
annotateRange() {
|
|
118
|
+
throw new Error("not implemented");
|
|
119
|
+
},
|
|
120
|
+
insertFromSpec(pos, spec) {
|
|
121
|
+
matrix._undoRemoveCols(pos, spec);
|
|
122
|
+
},
|
|
123
|
+
removeRange(start, end) {
|
|
124
|
+
matrix.removeCols(start, end - start);
|
|
125
|
+
},
|
|
114
126
|
});
|
|
115
127
|
}
|
|
116
128
|
cellSet(rowHandle, colHandle, oldValue) {
|
package/lib/undoprovider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"undoprovider.js","sourceRoot":"","sources":["../src/undoprovider.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/common-utils\";\nimport {\n\tTrackingGroup,\n\tMergeTreeDeltaOperationType,\n\tMergeTreeDeltaType,\n\ttoRemovalInfo,\n} from \"@fluidframework/merge-tree\";\nimport { MatrixItem, SharedMatrix } from \"./matrix\";\nimport { Handle, isHandleValid } from \"./handletable\";\nimport { PermutationSegment, PermutationVector } from \"./permutationvector\";\nimport { IUndoConsumer } from \"./types\";\n\nexport class VectorUndoProvider {\n\t// 'currentGroup' and 'currentOp' are used while applying an IRevertable.revert() to coalesce\n\t// the recorded into a single IRevertable / tracking group as they move between the undo <->\n\t// redo stacks.\n\tprivate currentGroup?: TrackingGroup;\n\tprivate currentOp?: MergeTreeDeltaType;\n\n\tconstructor(\n\t\tprivate readonly manager: IUndoConsumer,\n\t\tprivate readonly undoInsert: (segment: PermutationSegment) => void,\n\t\tprivate readonly undoRemove: (segment: PermutationSegment) => void,\n\t) {}\n\n\tpublic record(\n\t\toperation: MergeTreeDeltaOperationType,\n\t\tranges: { segment: PermutationSegment }[],\n\t) {\n\t\tif (ranges.length > 0) {\n\t\t\t// Link each segment to a new TrackingGroup. A TrackingGroup keeps track of the original\n\t\t\t// set of linked segments, including any fragmentatiton that occurs due to future splitting.\n\t\t\t//\n\t\t\t// A TrackingGroup also prevents removed segments from being unlinked from the tree during\n\t\t\t// Zamboni and guarantees segments will not be merged/coalesced with segments outside of the\n\t\t\t// current tracking group.\n\t\t\t//\n\t\t\t// These properties allow us to rely on MergeTree.getPosition() to find the locations/lengths\n\t\t\t// of all content contained within the tracking group in the future.\n\n\t\t\t// If we are in the process of reverting, the `IRevertible.revert()` will provide the tracking\n\t\t\t// group so that we can preserve the original segment ranges as a single op/group as we move\n\t\t\t// ops between the undo <-> redo stacks.\n\t\t\tconst trackingGroup = this.currentGroup ?? new TrackingGroup();\n\t\t\tfor (const range of ranges) {\n\t\t\t\ttrackingGroup.link(range.segment);\n\t\t\t}\n\n\t\t\t// For SharedMatrix, each IRevertibles always holds a single row/col operation.\n\t\t\t// Therefore, 'currentOp' must either be undefined or equal to the current op.\n\t\t\tassert(\n\t\t\t\tthis.currentOp === undefined || this.currentOp === operation,\n\t\t\t\t0x02a /* \"On vector undo, unexpected 'currentOp' type/state!\" */,\n\t\t\t);\n\n\t\t\tswitch (operation) {\n\t\t\t\tcase MergeTreeDeltaType.INSERT:\n\t\t\t\t\tif (this.currentOp !== MergeTreeDeltaType.INSERT) {\n\t\t\t\t\t\tthis.pushRevertible(trackingGroup, this.undoInsert);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MergeTreeDeltaType.REMOVE: {\n\t\t\t\t\tif (this.currentOp !== MergeTreeDeltaType.REMOVE) {\n\t\t\t\t\t\tthis.pushRevertible(trackingGroup, this.undoRemove);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\"operation type not revertible\");\n\t\t\t}\n\n\t\t\t// If we are in the process of reverting, set 'currentOp' to remind ourselves not to push\n\t\t\t// another revertible until `IRevertable.revert()` finishes the current op and clears this\n\t\t\t// field.\n\t\t\tif (this.currentGroup !== undefined) {\n\t\t\t\tthis.currentOp = operation;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate pushRevertible(\n\t\ttrackingGroup: TrackingGroup,\n\t\tcallback: (segment: PermutationSegment) => void,\n\t) {\n\t\tconst revertible = {\n\t\t\trevert: () => {\n\t\t\t\tassert(\n\t\t\t\t\tthis.currentGroup === undefined && this.currentOp === undefined,\n\t\t\t\t\t0x02b /* \"Must not nest calls to IRevertible.revert()\" */,\n\t\t\t\t);\n\n\t\t\t\tthis.currentGroup = new TrackingGroup();\n\n\t\t\t\ttry {\n\t\t\t\t\twhile (trackingGroup.size > 0) {\n\t\t\t\t\t\tconst segment = trackingGroup.segments[0] as PermutationSegment;\n\n\t\t\t\t\t\t// Unlink 'segment' from the current tracking group before invoking the callback\n\t\t\t\t\t\t// to exclude the current undo/redo segment from those copied to the replacement\n\t\t\t\t\t\t// segment (if any). (See 'PermutationSegment.transferToReplacement()')\n\t\t\t\t\t\tsegment.trackingCollection.unlink(trackingGroup);\n\n\t\t\t\t\t\tcallback(segment);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tthis.currentOp = undefined;\n\t\t\t\t\tthis.currentGroup = undefined;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdiscard: () => {\n\t\t\t\twhile (trackingGroup.size > 0) {\n\t\t\t\t\ttrackingGroup.unlink(trackingGroup.segments[0]);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\tthis.manager.pushToCurrentOperation(revertible);\n\n\t\treturn revertible;\n\t}\n}\n\nexport class MatrixUndoProvider<T> {\n\tconstructor(\n\t\tprivate readonly consumer: IUndoConsumer,\n\t\tprivate readonly matrix: SharedMatrix<T>,\n\t\tprivate readonly rows: PermutationVector,\n\t\tprivate readonly cols: PermutationVector,\n\t) {\n\t\trows.undo = new VectorUndoProvider(\n\t\t\tconsumer,\n\t\t\t/* undoInsert: */ (segment: PermutationSegment) => {\n\t\t\t\tif (toRemovalInfo(segment) === undefined) {\n\t\t\t\t\tconst start = this.rows.getPosition(segment);\n\t\t\t\t\tthis.matrix.removeRows(start, segment.cachedLength);\n\t\t\t\t}\n\t\t\t},\n\t\t\t/* undoRemove: */ (segment: PermutationSegment) => {\n\t\t\t\tthis.matrix._undoRemoveRows(segment);\n\t\t\t},\n\t\t);\n\t\tcols.undo = new VectorUndoProvider(\n\t\t\tconsumer,\n\t\t\t/* undoInsert: */ (segment: PermutationSegment) => {\n\t\t\t\tif (toRemovalInfo(segment) === undefined) {\n\t\t\t\t\tconst start = this.cols.getPosition(segment);\n\t\t\t\t\tthis.matrix.removeCols(start, segment.cachedLength);\n\t\t\t\t}\n\t\t\t},\n\t\t\t/* undoRemove: */ (segment: PermutationSegment) => {\n\t\t\t\tthis.matrix._undoRemoveCols(segment);\n\t\t\t},\n\t\t);\n\t}\n\n\tcellSet(rowHandle: Handle, colHandle: Handle, oldValue: MatrixItem<T>) {\n\t\tassert(\n\t\t\tisHandleValid(rowHandle) && isHandleValid(colHandle),\n\t\t\t0x02c /* \"On cellSet(), invalid row and/or column handles!\" */,\n\t\t);\n\n\t\tif (this.consumer !== undefined) {\n\t\t\tthis.consumer.pushToCurrentOperation({\n\t\t\t\trevert: () => {\n\t\t\t\t\tconst row = this.rows.handleToPosition(rowHandle);\n\t\t\t\t\tconst col = this.cols.handleToPosition(colHandle);\n\t\t\t\t\t// if the row/column no longer exists, we cannot set the cell\n\t\t\t\t\tif (row < this.matrix.rowCount && col < this.matrix.colCount) {\n\t\t\t\t\t\tthis.matrix.setCell(row, col, oldValue);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tdiscard: () => {},\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"undoprovider.js","sourceRoot":"","sources":["../src/undoprovider.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/common-utils\";\nimport {\n\tMergeTreeDeltaType,\n\tMergeTreeDeltaRevertible,\n\tIMergeTreeDeltaCallbackArgs,\n\tappendToMergeTreeDeltaRevertibles,\n\trevertMergeTreeDeltaRevertibles,\n\tMergeTreeRevertibleDriver,\n\tdiscardMergeTreeDeltaRevertible,\n\tTrackingGroup,\n\tITrackingGroup,\n} from \"@fluidframework/merge-tree\";\nimport { MatrixItem, SharedMatrix } from \"./matrix\";\nimport { Handle, isHandleValid } from \"./handletable\";\nimport { PermutationSegment, PermutationVector } from \"./permutationvector\";\nimport { IUndoConsumer } from \"./types\";\n\nexport class VectorUndoProvider {\n\t// 'currentGroup' and 'currentOp' are used while applying an IRevertable.revert() to coalesce\n\t// the recorded into a single IRevertable / tracking group as they move between the undo <->\n\t// redo stacks.\n\tprivate currentGroup?: MergeTreeDeltaRevertible[];\n\tprivate currentOp?: MergeTreeDeltaType;\n\tprivate currentRemoveTrackingGroup?: TrackingGroup;\n\n\tconstructor(\n\t\tprivate readonly manager: IUndoConsumer,\n\t\tprivate readonly driver: MergeTreeRevertibleDriver,\n\t) {}\n\n\tpublic record(deltaArgs: IMergeTreeDeltaCallbackArgs) {\n\t\tif (deltaArgs.deltaSegments.length > 0) {\n\t\t\t// If we are in the process of reverting, the `IRevertible.revert()` will provide the tracking\n\t\t\t// group so that we can preserve the original segment ranges as a single op/group as we move\n\t\t\t// ops between the undo <-> redo stacks.\n\t\t\tconst revertibles: MergeTreeDeltaRevertible[] = this.currentGroup ?? [];\n\t\t\tappendToMergeTreeDeltaRevertibles(deltaArgs, revertibles);\n\n\t\t\t// For SharedMatrix, each IRevertibles always holds a single row/col operation.\n\t\t\t// Therefore, 'currentOp' must either be undefined or equal to the current op.\n\t\t\tassert(\n\t\t\t\tthis.currentOp === undefined || this.currentOp === deltaArgs.operation,\n\t\t\t\t0x02a /* \"On vector undo, unexpected 'currentOp' type/state!\" */,\n\t\t\t);\n\t\t\tlet removeTrackingGroup: TrackingGroup | undefined;\n\t\t\tif (deltaArgs.operation === MergeTreeDeltaType.REMOVE) {\n\t\t\t\t// for removed segment we need a tracking group.\n\t\t\t\t// this is for a few reason:\n\t\t\t\t// 1. the handle for the row/column on the removed segment is still allocated,\n\t\t\t\t//\t\tand needs to be in order to process unacked ops sent before the remove.\n\t\t\t\t// 2. handles are freed on unlink(zamboni), but that also clears the row/column data.\n\t\t\t\t//\t\twhich we don't want to happen, so we can re-insert the cells when the row/col comes back.\n\t\t\t\t//\t\tthe tracking group prevents unlink.\n\t\t\t\t// 3. when we re-insert we need to find the old segment and clear their handles\n\t\t\t\t//\t\tso the new segment takes them over. there is no efficient look-up for this.\n\t\t\t\t//\t\tthe tracking group provides one.\n\t\t\t\tconst trackingGroup = (removeTrackingGroup =\n\t\t\t\t\tthis.currentRemoveTrackingGroup ?? new TrackingGroup());\n\t\t\t\tdeltaArgs.deltaSegments.forEach((d) =>\n\t\t\t\t\td.segment.trackingCollection.link(trackingGroup),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tswitch (deltaArgs.operation) {\n\t\t\t\tcase MergeTreeDeltaType.REMOVE:\n\t\t\t\tcase MergeTreeDeltaType.INSERT:\n\t\t\t\t\tif (this.currentOp !== deltaArgs.operation) {\n\t\t\t\t\t\tthis.pushRevertible(revertibles, removeTrackingGroup);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\"operation type not revertible\");\n\t\t\t}\n\n\t\t\t// If we are in the process of reverting, set 'currentOp' to remind ourselves not to push\n\t\t\t// another revertible until `IRevertable.revert()` finishes the current op and clears this\n\t\t\t// field.\n\t\t\tif (this.currentGroup !== undefined) {\n\t\t\t\tthis.currentOp ??= deltaArgs.operation;\n\t\t\t\tthis.currentRemoveTrackingGroup ??= removeTrackingGroup;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate pushRevertible(\n\t\trevertibles: MergeTreeDeltaRevertible[],\n\t\tremovedTrackingGroup: ITrackingGroup | undefined,\n\t) {\n\t\tconst reverter = {\n\t\t\trevert: () => {\n\t\t\t\tassert(\n\t\t\t\t\tthis.currentGroup === undefined && this.currentOp === undefined,\n\t\t\t\t\t0x02b /* \"Must not nest calls to IRevertible.revert()\" */,\n\t\t\t\t);\n\n\t\t\t\tthis.currentGroup = [];\n\n\t\t\t\ttry {\n\t\t\t\t\tif (removedTrackingGroup !== undefined) {\n\t\t\t\t\t\twhile (removedTrackingGroup.size > 0) {\n\t\t\t\t\t\t\tconst tracked = removedTrackingGroup.tracked[0];\n\t\t\t\t\t\t\tremovedTrackingGroup.unlink(tracked);\n\t\t\t\t\t\t\t// if there are groups tracked, this in a revert of a remove.\n\t\t\t\t\t\t\t// this means we are about to re-insert the row/column\n\t\t\t\t\t\t\t// with the same handle. We reuse the handle so the row/columns cells\n\t\t\t\t\t\t\t// get re-inserted too.\n\t\t\t\t\t\t\t// since a new segment will have the handle, we need to\n\t\t\t\t\t\t\t// remove it from the removed segment which was tracked\n\t\t\t\t\t\t\t(tracked as PermutationSegment).reset();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\trevertMergeTreeDeltaRevertibles(this.driver, revertibles);\n\t\t\t\t} finally {\n\t\t\t\t\tthis.currentOp = undefined;\n\t\t\t\t\tthis.currentGroup = undefined;\n\t\t\t\t\tthis.currentRemoveTrackingGroup = undefined;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdiscard: () => {\n\t\t\t\tif (removedTrackingGroup !== undefined) {\n\t\t\t\t\twhile (removedTrackingGroup.size > 0) {\n\t\t\t\t\t\tremovedTrackingGroup.unlink(removedTrackingGroup.tracked[0]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdiscardMergeTreeDeltaRevertible(revertibles);\n\t\t\t},\n\t\t};\n\n\t\tthis.manager.pushToCurrentOperation(reverter);\n\n\t\treturn reverter;\n\t}\n}\n\nexport class MatrixUndoProvider<T> {\n\tconstructor(\n\t\tprivate readonly consumer: IUndoConsumer,\n\t\tprivate readonly matrix: SharedMatrix<T>,\n\t\tprivate readonly rows: PermutationVector,\n\t\tprivate readonly cols: PermutationVector,\n\t) {\n\t\trows.undo = new VectorUndoProvider(consumer, {\n\t\t\tannotateRange() {\n\t\t\t\tthrow new Error(\"not implemented\");\n\t\t\t},\n\t\t\tinsertFromSpec(pos, spec) {\n\t\t\t\tmatrix._undoRemoveRows(pos, spec);\n\t\t\t},\n\t\t\tremoveRange(start, end) {\n\t\t\t\tmatrix.removeRows(start, end - start);\n\t\t\t},\n\t\t});\n\t\tcols.undo = new VectorUndoProvider(consumer, {\n\t\t\tannotateRange() {\n\t\t\t\tthrow new Error(\"not implemented\");\n\t\t\t},\n\t\t\tinsertFromSpec(pos, spec) {\n\t\t\t\tmatrix._undoRemoveCols(pos, spec);\n\t\t\t},\n\t\t\tremoveRange(start, end) {\n\t\t\t\tmatrix.removeCols(start, end - start);\n\t\t\t},\n\t\t});\n\t}\n\n\tcellSet(rowHandle: Handle, colHandle: Handle, oldValue: MatrixItem<T>) {\n\t\tassert(\n\t\t\tisHandleValid(rowHandle) && isHandleValid(colHandle),\n\t\t\t0x02c /* \"On cellSet(), invalid row and/or column handles!\" */,\n\t\t);\n\n\t\tif (this.consumer !== undefined) {\n\t\t\tthis.consumer.pushToCurrentOperation({\n\t\t\t\trevert: () => {\n\t\t\t\t\tconst row = this.rows.handleToPosition(rowHandle);\n\t\t\t\t\tconst col = this.cols.handleToPosition(colHandle);\n\t\t\t\t\t// if the row/column no longer exists, we cannot set the cell\n\t\t\t\t\tif (row < this.matrix.rowCount && col < this.matrix.colCount) {\n\t\t\t\t\t\tthis.matrix.setCell(row, col, oldValue);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tdiscard: () => {},\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/matrix",
|
|
3
|
-
"version": "2.0.0-internal.
|
|
3
|
+
"version": "2.0.0-internal.5.0.0",
|
|
4
4
|
"description": "Distributed matrix",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -33,29 +33,29 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
35
35
|
"@fluidframework/common-utils": "^1.1.1",
|
|
36
|
-
"@fluidframework/core-interfaces": ">=2.0.0-internal.
|
|
37
|
-
"@fluidframework/datastore-definitions": ">=2.0.0-internal.
|
|
38
|
-
"@fluidframework/
|
|
39
|
-
"@fluidframework/
|
|
36
|
+
"@fluidframework/core-interfaces": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
37
|
+
"@fluidframework/datastore-definitions": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
38
|
+
"@fluidframework/driver-utils": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
39
|
+
"@fluidframework/merge-tree": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
40
40
|
"@fluidframework/protocol-definitions": "^1.1.0",
|
|
41
|
-
"@fluidframework/runtime-definitions": ">=2.0.0-internal.
|
|
42
|
-
"@fluidframework/runtime-utils": ">=2.0.0-internal.
|
|
43
|
-
"@fluidframework/shared-object-base": ">=2.0.0-internal.
|
|
44
|
-
"@fluidframework/telemetry-utils": ">=2.0.0-internal.
|
|
41
|
+
"@fluidframework/runtime-definitions": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
42
|
+
"@fluidframework/runtime-utils": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
43
|
+
"@fluidframework/shared-object-base": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
44
|
+
"@fluidframework/telemetry-utils": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
45
45
|
"@tiny-calc/nano": "0.0.0-alpha.5",
|
|
46
46
|
"events": "^3.1.0",
|
|
47
47
|
"tslib": "^1.10.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@fluid-internal/test-dds-utils": ">=2.0.0-internal.
|
|
50
|
+
"@fluid-internal/test-dds-utils": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
51
51
|
"@fluid-tools/benchmark": "^0.47.0",
|
|
52
52
|
"@fluid-tools/build-cli": "^0.17.0",
|
|
53
53
|
"@fluidframework/build-common": "^1.1.0",
|
|
54
54
|
"@fluidframework/build-tools": "^0.17.0",
|
|
55
55
|
"@fluidframework/eslint-config-fluid": "^2.0.0",
|
|
56
56
|
"@fluidframework/matrix-previous": "npm:@fluidframework/matrix@2.0.0-internal.4.1.0",
|
|
57
|
-
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.
|
|
58
|
-
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.
|
|
57
|
+
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
58
|
+
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.5.0.0 <2.0.0-internal.5.1.0",
|
|
59
59
|
"@microsoft/api-extractor": "^7.34.4",
|
|
60
60
|
"@tiny-calc/micro": "0.0.0-alpha.5",
|
|
61
61
|
"@types/mocha": "^9.1.1",
|
package/src/matrix.ts
CHANGED
|
@@ -25,11 +25,11 @@ import {
|
|
|
25
25
|
MergeTreeDeltaType,
|
|
26
26
|
IMergeTreeOp,
|
|
27
27
|
SegmentGroup,
|
|
28
|
-
ISegment,
|
|
29
28
|
Client,
|
|
29
|
+
IJSONSegment,
|
|
30
30
|
} from "@fluidframework/merge-tree";
|
|
31
31
|
import { MatrixOp } from "./ops";
|
|
32
|
-
import { PermutationVector,
|
|
32
|
+
import { PermutationVector, reinsertSegmentIntoVector } from "./permutationvector";
|
|
33
33
|
import { SparseArray2D } from "./sparsearray2d";
|
|
34
34
|
import { SharedMatrixFactory } from "./runtime";
|
|
35
35
|
import { Handle, isHandleValid } from "./handletable";
|
|
@@ -368,26 +368,10 @@ export class SharedMatrix<T = any>
|
|
|
368
368
|
this.submitRowMessage(this.rows.remove(rowStart, count));
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
-
/** @internal */ public _undoRemoveRows(
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
// (Re)insert the removed number of rows at the original position.
|
|
375
|
-
const { op, inserted } = this.rows.insertRelative(original, original.cachedLength);
|
|
371
|
+
/** @internal */ public _undoRemoveRows(rowStart: number, spec: IJSONSegment) {
|
|
372
|
+
const { op, inserted } = reinsertSegmentIntoVector(this.rows, rowStart, spec);
|
|
376
373
|
this.submitRowMessage(op);
|
|
377
374
|
|
|
378
|
-
// Transfer handles and undo/redo tracking groups from the original segment to the
|
|
379
|
-
// newly inserted segment.
|
|
380
|
-
original.transferToReplacement(inserted);
|
|
381
|
-
|
|
382
|
-
// Invalidate the handleCache in case it was populated during the 'rowsChanged'
|
|
383
|
-
// callback, which occurs before the handle span is populated.
|
|
384
|
-
const rowStart = this.rows.getPosition(inserted);
|
|
385
|
-
this.rows.handleCache.itemsChanged(
|
|
386
|
-
rowStart,
|
|
387
|
-
/* removedCount: */ 0,
|
|
388
|
-
/* insertedCount: */ inserted.cachedLength,
|
|
389
|
-
);
|
|
390
|
-
|
|
391
375
|
// Generate setCell ops for each populated cell in the reinserted rows.
|
|
392
376
|
let rowHandle = inserted.start;
|
|
393
377
|
const rowCount = inserted.cachedLength;
|
|
@@ -407,26 +391,10 @@ export class SharedMatrix<T = any>
|
|
|
407
391
|
}
|
|
408
392
|
}
|
|
409
393
|
|
|
410
|
-
/** @internal */ public _undoRemoveCols(
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
// (Re)insert the removed number of columns at the original position.
|
|
414
|
-
const { op, inserted } = this.cols.insertRelative(original, original.cachedLength);
|
|
394
|
+
/** @internal */ public _undoRemoveCols(colStart: number, spec: IJSONSegment) {
|
|
395
|
+
const { op, inserted } = reinsertSegmentIntoVector(this.cols, colStart, spec);
|
|
415
396
|
this.submitColMessage(op);
|
|
416
397
|
|
|
417
|
-
// Transfer handles and undo/redo tracking groups from the original segment to the
|
|
418
|
-
// newly inserted segment.
|
|
419
|
-
original.transferToReplacement(inserted);
|
|
420
|
-
|
|
421
|
-
// Invalidate the handleCache in case it was populated during the 'colsChanged'
|
|
422
|
-
// callback, which occurs before the handle span is populated.
|
|
423
|
-
const colStart = this.cols.getPosition(inserted);
|
|
424
|
-
this.cols.handleCache.itemsChanged(
|
|
425
|
-
colStart,
|
|
426
|
-
/* removedCount: */ 0,
|
|
427
|
-
/* insertedCount: */ inserted.cachedLength,
|
|
428
|
-
);
|
|
429
|
-
|
|
430
398
|
// Generate setCell ops for each populated cell in the reinserted cols.
|
|
431
399
|
let colHandle = inserted.start;
|
|
432
400
|
const colCount = inserted.cachedLength;
|
package/src/packageVersion.ts
CHANGED
package/src/permutationvector.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
MergeTreeDeltaType,
|
|
20
20
|
IMergeTreeMaintenanceCallbackArgs,
|
|
21
21
|
MergeTreeMaintenanceType,
|
|
22
|
-
|
|
22
|
+
IJSONSegment,
|
|
23
23
|
} from "@fluidframework/merge-tree";
|
|
24
24
|
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
25
25
|
import { IFluidSerializer } from "@fluidframework/shared-object-base";
|
|
@@ -71,35 +71,6 @@ export class PermutationSegment extends BaseSegment {
|
|
|
71
71
|
this._start = value;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/**
|
|
75
|
-
* Invoked by '_undoRow/ColRemove' to prepare the newly inserted destination
|
|
76
|
-
* segment to serve as the replacement for this removed segment. This moves handle
|
|
77
|
-
* allocations from this segment to the replacement as well as maintains tracking
|
|
78
|
-
* groups for the undo/redo stack.
|
|
79
|
-
*/
|
|
80
|
-
public transferToReplacement(destination: PermutationSegment) {
|
|
81
|
-
// When this segment was removed, it may have been split from a larger original
|
|
82
|
-
// segment. In this case, it will have been added to an undo/redo tracking group
|
|
83
|
-
// that associates all of the fragments from the original insertion.
|
|
84
|
-
//
|
|
85
|
-
// Move this association from the this removed segment to its replacement so that
|
|
86
|
-
// it is included if the undo stack continues to unwind to the original insertion.
|
|
87
|
-
//
|
|
88
|
-
// Out of paranoia we link and unlink in separate loops to avoid mutating the underlying
|
|
89
|
-
// set during enumeration. In practice, this is unlikely to matter since there should be
|
|
90
|
-
// exactly 0 or 1 items in the enumeration.
|
|
91
|
-
for (const group of this.trackingCollection.trackingGroups) {
|
|
92
|
-
group.link(destination);
|
|
93
|
-
}
|
|
94
|
-
for (const group of this.trackingCollection.trackingGroups) {
|
|
95
|
-
group.unlink(this);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Move handle allocations from this segment to its replacement.
|
|
99
|
-
destination._start = this._start;
|
|
100
|
-
this.reset();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
74
|
public reset() {
|
|
104
75
|
this._start = Handle.unallocated;
|
|
105
76
|
}
|
|
@@ -170,6 +141,7 @@ export class PermutationVector extends Client {
|
|
|
170
141
|
{
|
|
171
142
|
...runtime.options,
|
|
172
143
|
newMergeTreeSnapshotFormat: true, // Temporarily force new snapshot format until it is the default.
|
|
144
|
+
mergeTreeUseNewLengthCalculations: true,
|
|
173
145
|
},
|
|
174
146
|
); // (See https://github.com/microsoft/FluidFramework/issues/84)
|
|
175
147
|
|
|
@@ -181,18 +153,6 @@ export class PermutationVector extends Client {
|
|
|
181
153
|
return this.insertSegmentLocal(start, new PermutationSegment(length));
|
|
182
154
|
}
|
|
183
155
|
|
|
184
|
-
public insertRelative(segment: ISegment, length: number) {
|
|
185
|
-
const inserted = new PermutationSegment(length);
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
op: this.insertAtReferencePositionLocal(
|
|
189
|
-
this.createLocalReferencePosition(segment, 0, ReferenceType.Transient, undefined),
|
|
190
|
-
inserted,
|
|
191
|
-
),
|
|
192
|
-
inserted,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
156
|
public remove(start: number, length: number) {
|
|
197
157
|
return this.removeRangeLocal(start, start + length);
|
|
198
158
|
}
|
|
@@ -346,10 +306,10 @@ export class PermutationVector extends Client {
|
|
|
346
306
|
|
|
347
307
|
private readonly onDelta = (
|
|
348
308
|
opArgs: IMergeTreeDeltaOpArgs,
|
|
349
|
-
|
|
309
|
+
deltaArgs: IMergeTreeDeltaCallbackArgs,
|
|
350
310
|
) => {
|
|
351
311
|
// Apply deltas in descending order to prevent positions from shifting.
|
|
352
|
-
const ranges = deltaSegments
|
|
312
|
+
const ranges = deltaArgs.deltaSegments
|
|
353
313
|
.map(({ segment }) => ({
|
|
354
314
|
segment: segment as PermutationSegment,
|
|
355
315
|
position: this.getPosition(segment),
|
|
@@ -360,10 +320,10 @@ export class PermutationVector extends Client {
|
|
|
360
320
|
|
|
361
321
|
// Notify the undo provider, if any is attached.
|
|
362
322
|
if (this.undo !== undefined && isLocal) {
|
|
363
|
-
this.undo.record(
|
|
323
|
+
this.undo.record(deltaArgs);
|
|
364
324
|
}
|
|
365
325
|
|
|
366
|
-
switch (operation) {
|
|
326
|
+
switch (deltaArgs.operation) {
|
|
367
327
|
case MergeTreeDeltaType.INSERT:
|
|
368
328
|
// Pass 1: Perform any internal maintenance first to avoid reentrancy.
|
|
369
329
|
for (const { segment, position } of ranges) {
|
|
@@ -453,3 +413,30 @@ export class PermutationVector extends Client {
|
|
|
453
413
|
return s.join("");
|
|
454
414
|
}
|
|
455
415
|
}
|
|
416
|
+
|
|
417
|
+
export function reinsertSegmentIntoVector(
|
|
418
|
+
vector: PermutationVector,
|
|
419
|
+
pos: number,
|
|
420
|
+
spec: IJSONSegment,
|
|
421
|
+
) {
|
|
422
|
+
const original = PermutationSegment.fromJSONObject(spec);
|
|
423
|
+
|
|
424
|
+
// (Re)insert the removed number of rows at the original position.
|
|
425
|
+
const op = vector.insertSegmentLocal(pos, original);
|
|
426
|
+
const inserted = vector.getContainingSegment(pos).segment as PermutationSegment;
|
|
427
|
+
|
|
428
|
+
// we reuse the original handle here
|
|
429
|
+
// so if cells exist, they can be found, and re-inserted
|
|
430
|
+
if (isHandleValid(original.start)) {
|
|
431
|
+
inserted.start = original.start;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Invalidate the handleCache in case it was populated during the 'rowsChanged'
|
|
435
|
+
// callback, which occurs before the handle span is populated.
|
|
436
|
+
vector.handleCache.itemsChanged(
|
|
437
|
+
pos,
|
|
438
|
+
/* removedCount: */ 0,
|
|
439
|
+
/* insertedCount: */ inserted.cachedLength,
|
|
440
|
+
);
|
|
441
|
+
return { op, inserted };
|
|
442
|
+
}
|
package/src/serialization.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Serializable, IChannelStorageService } from "@fluidframework/datastore-definitions";
|
|
7
|
-
import { BlobTreeEntry } from "@fluidframework/protocol-base";
|
|
8
7
|
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
8
|
+
import { BlobTreeEntry } from "@fluidframework/driver-utils";
|
|
9
9
|
import { IFluidSerializer } from "@fluidframework/shared-object-base";
|
|
10
10
|
import { bufferToString } from "@fluidframework/common-utils";
|
|
11
11
|
|