Skip to content

Commit ca037e6

Browse files
committed
feat(json-crdt-extensions): 🎸 add OverlayPoint implementation
1 parent 7c31a6f commit ca037e6

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import {Point} from '../rga/Point';
2+
import {compare} from '../../../json-crdt-patch/clock';
3+
import {OverlayRef, OverlayRefSliceEnd, OverlayRefSliceStart} from './refs';
4+
import {printTree} from 'sonic-forest/lib/print/printTree';
5+
import type {HeadlessNode} from 'sonic-forest/lib/types';
6+
import type {Printable} from '../../../util/print/types';
7+
import type {Slice} from '../slice/types';
8+
9+
export class OverlayPoint extends Point implements Printable, HeadlessNode {
10+
/**
11+
* Sorted list of references to rich-text constructs.
12+
*/
13+
public readonly refs: OverlayRef[] = [];
14+
15+
/**
16+
* Sorted list of layers, contain the interval from this point to the next one.
17+
*/
18+
public readonly layers: Slice[] = [];
19+
20+
/**
21+
* Collapsed slices.
22+
*
23+
* @todo Rename to `markers`?
24+
*/
25+
public readonly points: Slice[] = [];
26+
27+
/** Hash of text contents until the next {@link OverlayPoint}. */
28+
public hash: number = 0;
29+
30+
public removeSlice(slice: Slice): void {
31+
const refs = this.refs;
32+
const length = refs.length;
33+
for (let i = 0; i < length; i++) {
34+
const ref = refs[i];
35+
if (
36+
ref === slice ||
37+
(ref instanceof OverlayRefSliceStart && ref.slice === slice) ||
38+
(ref instanceof OverlayRefSliceEnd && ref.slice === slice)
39+
) {
40+
refs.splice(i, 1);
41+
break;
42+
}
43+
}
44+
this.removeLayer(slice);
45+
this.removePoint(slice);
46+
}
47+
48+
/**
49+
* Inserts a slice to the list of layers which contains the area from this
50+
* point to the next one.
51+
* @param slice Slice to add to the layer list.
52+
*/
53+
public addLayer(slice: Slice): void {
54+
const layers = this.layers;
55+
const length = layers.length;
56+
if (!length) {
57+
layers.push(slice);
58+
return;
59+
}
60+
// We attempt to insert from the end of the list, as it is the most likely.
61+
const lastSlice = layers[length - 1];
62+
const sliceId = slice.id;
63+
if (compare(lastSlice.id, sliceId) < 0) {
64+
layers.push(slice);
65+
return;
66+
}
67+
for (let i = length - 2; i >= 0; i--) {
68+
const currSlice = layers[i];
69+
if (compare(currSlice.id, sliceId) < 0) {
70+
layers.splice(i + 1, 0, slice);
71+
return;
72+
}
73+
}
74+
layers.unshift(slice);
75+
}
76+
77+
public removeLayer(slice: Slice): void {
78+
const layers = this.layers;
79+
const length = layers.length;
80+
for (let i = 0; i < length; i++) {
81+
if (layers[i] === slice) {
82+
layers.splice(i, 1);
83+
return;
84+
}
85+
}
86+
}
87+
88+
public addPoint(slice: Slice): void {
89+
const points = this.points;
90+
const length = points.length;
91+
if (!length) {
92+
points.push(slice);
93+
return;
94+
}
95+
// We attempt to insert from the end of the list, as it is the most likely.
96+
const lastSlice = points[length - 1];
97+
const sliceId = slice.id;
98+
if (compare(lastSlice.id, sliceId) < 0) {
99+
points.push(slice);
100+
return;
101+
}
102+
for (let i = length - 2; i >= 0; i--) {
103+
const currSlice = points[i];
104+
if (compare(currSlice.id, sliceId) < 0) {
105+
points.splice(i + 1, 0, slice);
106+
return;
107+
}
108+
}
109+
points.unshift(slice);
110+
}
111+
112+
public removePoint(slice: Slice): void {
113+
const points = this.points;
114+
const length = points.length;
115+
for (let i = 0; i < length; i++) {
116+
if (points[i] === slice) {
117+
points.splice(i, 1);
118+
return;
119+
}
120+
}
121+
}
122+
123+
// ---------------------------------------------------------------- Printable
124+
125+
public toStringName(tab: string, lite?: boolean): string {
126+
return super.toString(tab, lite);
127+
}
128+
129+
public toString(tab: string = '', lite?: boolean): string {
130+
const refs = lite ? '' : `, refs = ${this.refs.length}`;
131+
const header = this.toStringName(tab, lite) + refs;
132+
if (lite) return header;
133+
return (
134+
header +
135+
printTree(
136+
tab,
137+
this.layers.map((slice) => (tab) => slice.toString(tab)),
138+
)
139+
);
140+
}
141+
142+
// ------------------------------------------------------------- HeadlessNode
143+
144+
public p: OverlayPoint | undefined = undefined;
145+
public l: OverlayPoint | undefined = undefined;
146+
public r: OverlayPoint | undefined = undefined;
147+
}

0 commit comments

Comments
 (0)