edytor 4.0.0 → 6.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.
Files changed (193) hide show
  1. package/README.md +2 -2
  2. package/dist/block/block.svelte.js +6 -21
  3. package/dist/block/inlineBlock.svelte.js +4 -6
  4. package/dist/clipboard/moveText.js +6 -8
  5. package/dist/cloudflare/DocumentRoom.d.ts +10 -3
  6. package/dist/cloudflare/index.d.ts +1 -1
  7. package/dist/cloudflare/room/access.d.ts +8 -3
  8. package/dist/cloudflare/room/access.js +44 -20
  9. package/dist/cloudflare/room/admission.js +28 -5
  10. package/dist/cloudflare/room/comments.js +28 -1
  11. package/dist/cloudflare/room/context.d.ts +106 -109
  12. package/dist/cloudflare/room/context.js +10 -3
  13. package/dist/cloudflare/room/forged.d.ts +14 -0
  14. package/dist/cloudflare/room/forged.js +30 -2
  15. package/dist/cloudflare/room/frames.d.ts +4 -0
  16. package/dist/cloudflare/room/frames.js +5 -1
  17. package/dist/cloudflare/room/purge.js +2 -1
  18. package/dist/cloudflare/room/replicas.d.ts +4 -2
  19. package/dist/cloudflare/room/replicas.js +8 -3
  20. package/dist/cloudflare/room/suggest.d.ts +7 -0
  21. package/dist/cloudflare/room/suggest.js +143 -0
  22. package/dist/cloudflare/routeDocumentSocket.d.ts +10 -1
  23. package/dist/cloudflare/routeDocumentSocket.js +5 -3
  24. package/dist/components/Content.svelte +9 -1
  25. package/dist/crdt/anchors.js +3 -2
  26. package/dist/crdt/attribution/attribution.d.ts +3 -0
  27. package/dist/crdt/attribution/attribution.js +3 -3
  28. package/dist/crdt/doc/funnel.d.ts +1 -1
  29. package/dist/crdt/doc/funnel.js +5 -2
  30. package/dist/crdt/doc/gate.d.ts +1 -1
  31. package/dist/crdt/doc/history.d.ts +6 -0
  32. package/dist/crdt/doc/history.js +79 -59
  33. package/dist/crdt/doc/ops.d.ts +81 -0
  34. package/dist/crdt/doc/ops.js +1898 -0
  35. package/dist/crdt/doc/reads.d.ts +2 -2
  36. package/dist/crdt/doc/reads.js +18 -28
  37. package/dist/crdt/doc/suggest.d.ts +167 -0
  38. package/dist/crdt/doc/suggest.js +579 -0
  39. package/dist/crdt/document.d.ts +10 -1
  40. package/dist/crdt/document.js +19 -11
  41. package/dist/crdt/edytor-doc.d.ts +294 -272
  42. package/dist/crdt/edytor-doc.js +123 -108
  43. package/dist/crdt/engine-api.d.ts +8 -2
  44. package/dist/crdt/engine.d.ts +2 -1
  45. package/dist/crdt/engine.js +3 -1
  46. package/dist/crdt/flow.d.ts +5 -47
  47. package/dist/crdt/flow.js +3 -269
  48. package/dist/crdt/index.d.ts +102 -108
  49. package/dist/crdt/index.js +3 -0
  50. package/dist/crdt/operations.d.ts +13 -4
  51. package/dist/crdt/parts.d.ts +43 -0
  52. package/dist/crdt/parts.js +44 -0
  53. package/dist/crdt/placement/display.d.ts +1 -1
  54. package/dist/crdt/placement/display.js +3 -3
  55. package/dist/crdt/placement/keys.d.ts +5 -0
  56. package/dist/crdt/placement/keys.js +5 -0
  57. package/dist/crdt/placement/resolve.d.ts +1 -1
  58. package/dist/crdt/placement/resolve.js +2 -1
  59. package/dist/crdt/protocol.d.ts +1 -1
  60. package/dist/crdt/protocol.js +1 -1
  61. package/dist/crdt/protocols/auth.d.ts +11 -1
  62. package/dist/crdt/protocols/auth.js +17 -1
  63. package/dist/crdt/protocols/awareness.js +46 -81
  64. package/dist/crdt/protocols/comments.d.ts +16 -1
  65. package/dist/crdt/protocols/comments.js +9 -1
  66. package/dist/crdt/providers/index.d.ts +12 -22
  67. package/dist/crdt/providers/index.js +3 -1
  68. package/dist/crdt/providers/indexeddb.d.ts +6 -10
  69. package/dist/crdt/providers/indexeddb.js +10 -16
  70. package/dist/crdt/providers/room.d.ts +11 -0
  71. package/dist/crdt/providers/room.js +26 -12
  72. package/dist/crdt/providers/websocket.d.ts +8 -12
  73. package/dist/crdt/providers/websocket.js +17 -19
  74. package/dist/crdt/purge.d.ts +7 -1
  75. package/dist/crdt/purge.js +32 -2
  76. package/dist/crdt/rangeDelete.d.ts +2 -47
  77. package/dist/crdt/rangeDelete.js +1 -169
  78. package/dist/crdt/restore.d.ts +2 -1
  79. package/dist/crdt/restore.js +9 -0
  80. package/dist/crdt/schema.d.ts +9 -1
  81. package/dist/crdt/schema.js +13 -3
  82. package/dist/crdt/structs.d.ts +2 -0
  83. package/dist/crdt/structs.js +2 -0
  84. package/dist/crdt/text/index/build.d.ts +125 -0
  85. package/dist/crdt/text/index/build.js +2895 -0
  86. package/dist/crdt/text/index/shared.d.ts +2 -6
  87. package/dist/crdt/text/index/shared.js +19 -19
  88. package/dist/crdt/text/model.d.ts +10 -0
  89. package/dist/crdt/text/model.js +10 -4
  90. package/dist/crdt/text/runs.d.ts +43 -42
  91. package/dist/crdt/text/runs.js +2 -165
  92. package/dist/crdt/vendor/yjs/UPSTREAM.md +83 -0
  93. package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
  94. package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +6 -3
  95. package/dist/crdt/vendor/yjs/dts/ynode.d.ts +13 -2
  96. package/dist/crdt/vendor/yjs/src/index.js +1 -1
  97. package/dist/crdt/vendor/yjs/src/structs/Item.js +44 -5
  98. package/dist/crdt/vendor/yjs/src/ynode.js +29 -7
  99. package/dist/edytor.svelte.d.ts +1 -1
  100. package/dist/edytor.svelte.js +100 -75
  101. package/dist/events/beforeInputCommands.d.ts +2 -2
  102. package/dist/events/domTextOffset.d.ts +2 -0
  103. package/dist/events/domTextOffset.js +8 -0
  104. package/dist/events/nativeInteractiveControl.d.ts +11 -1
  105. package/dist/events/nativeInteractiveControl.js +41 -1
  106. package/dist/events/onBeforeInput.js +3 -3
  107. package/dist/events/onFocus.js +9 -11
  108. package/dist/export/forms.d.ts +75 -75
  109. package/dist/index.d.ts +4 -2
  110. package/dist/index.js +1 -1
  111. package/dist/labels.d.ts +8 -0
  112. package/dist/labels.js +6 -1
  113. package/dist/plugins/comments/CommentsController.svelte.d.ts +5 -1
  114. package/dist/plugins/comments/CommentsController.svelte.js +14 -4
  115. package/dist/plugins/find/search.js +2 -2
  116. package/dist/plugins/index.d.ts +1 -0
  117. package/dist/plugins/index.js +1 -0
  118. package/dist/plugins/richtext/RichTextPlugin.svelte +63 -61
  119. package/dist/plugins/richtext/richTextOperations.js +26 -32
  120. package/dist/plugins/suggestions/SuggestionBars.svelte +40 -23
  121. package/dist/plugins/suggestions/SuggestionBars.svelte.d.ts +3 -1
  122. package/dist/plugins/suggestions/SuggestionRuns.svelte +77 -0
  123. package/dist/plugins/suggestions/SuggestionRuns.svelte.d.ts +9 -0
  124. package/dist/plugins/suggestions/shared.svelte.d.ts +58 -0
  125. package/dist/plugins/suggestions/shared.svelte.js +421 -0
  126. package/dist/plugins/suggestions/suggestionsPlugin.d.ts +15 -4
  127. package/dist/selection/domSelection.d.ts +2 -0
  128. package/dist/selection/domSelection.js +6 -2
  129. package/dist/selection/pointer.svelte.js +75 -48
  130. package/dist/selection/replaceSelection.js +2 -6
  131. package/dist/selection/selection.svelte.d.ts +3 -3
  132. package/dist/selection/selection.svelte.js +39 -32
  133. package/dist/selection/selection.utils.d.ts +14 -0
  134. package/dist/selection/selection.utils.js +33 -11
  135. package/dist/session/commands.js +21 -11
  136. package/dist/session/composition.svelte.d.ts +5 -3
  137. package/dist/session/composition.svelte.js +21 -17
  138. package/dist/session/handles.d.ts +4 -17
  139. package/dist/session/handles.js +14 -44
  140. package/dist/session/navigation.js +6 -9
  141. package/dist/session/selection.d.ts +11 -5
  142. package/dist/session/selection.js +14 -48
  143. package/dist/session/suggestions.svelte.d.ts +38 -9
  144. package/dist/session/suggestions.svelte.js +37 -18
  145. package/dist/session/virtual.d.ts +1 -1
  146. package/dist/surface/attributes.d.ts +5 -0
  147. package/dist/surface/attributes.js +2 -2
  148. package/dist/surface/cells.d.ts +2 -26
  149. package/dist/surface/cells.js +2 -33
  150. package/dist/surface/observer.svelte.d.ts +6 -1
  151. package/dist/surface/observer.svelte.js +143 -111
  152. package/dist/surface/pin.svelte.d.ts +9 -9
  153. package/dist/surface/pin.svelte.js +15 -22
  154. package/dist/surface/projector.svelte.js +10 -16
  155. package/dist/text/text.svelte.js +14 -19
  156. package/dist/themes/notion.css +29 -0
  157. package/dist/utils.d.ts +5 -0
  158. package/dist/utils.js +7 -0
  159. package/package.json +3 -1
  160. package/dist/crdt/doc/capability.d.ts +0 -56
  161. package/dist/crdt/doc/capability.js +0 -211
  162. package/dist/crdt/doc/content.d.ts +0 -16
  163. package/dist/crdt/doc/content.js +0 -77
  164. package/dist/crdt/doc/delete.d.ts +0 -15
  165. package/dist/crdt/doc/delete.js +0 -84
  166. package/dist/crdt/doc/layout.d.ts +0 -9
  167. package/dist/crdt/doc/layout.js +0 -178
  168. package/dist/crdt/doc/meta.d.ts +0 -19
  169. package/dist/crdt/doc/meta.js +0 -199
  170. package/dist/crdt/doc/moves.d.ts +0 -21
  171. package/dist/crdt/doc/moves.js +0 -274
  172. package/dist/crdt/doc/split-merge.d.ts +0 -10
  173. package/dist/crdt/doc/split-merge.js +0 -179
  174. package/dist/crdt/doc/steps.d.ts +0 -65
  175. package/dist/crdt/doc/steps.js +0 -311
  176. package/dist/crdt/text/index/cache.d.ts +0 -16
  177. package/dist/crdt/text/index/cache.js +0 -175
  178. package/dist/crdt/text/index/claims.d.ts +0 -18
  179. package/dist/crdt/text/index/claims.js +0 -225
  180. package/dist/crdt/text/index/fold.d.ts +0 -21
  181. package/dist/crdt/text/index/fold.js +0 -656
  182. package/dist/crdt/text/index/layout.d.ts +0 -24
  183. package/dist/crdt/text/index/layout.js +0 -271
  184. package/dist/crdt/text/index/placement.d.ts +0 -47
  185. package/dist/crdt/text/index/placement.js +0 -741
  186. package/dist/crdt/text/index/records.d.ts +0 -13
  187. package/dist/crdt/text/index/records.js +0 -139
  188. package/dist/crdt/text/index/report.d.ts +0 -18
  189. package/dist/crdt/text/index/report.js +0 -337
  190. package/dist/crdt/text/index/state.d.ts +0 -197
  191. package/dist/crdt/text/index/state.js +0 -116
  192. package/dist/crdt/text/index/streams.d.ts +0 -25
  193. package/dist/crdt/text/index/streams.js +0 -248
@@ -1,311 +0,0 @@
1
- /**
2
- * The step writers every prepared op composes: the plan itself, moves (a
3
- * move's place and side), type steps and the kind a block shows where it
4
- * lands (`settle`), the containers and layouts a write leaves empty
5
- * (`emptying`, `dissolving`), delete and merge steps, and display spans of a
6
- * block's content.
7
- */
8
- import { TYPE } from '../schema.js';
9
- import { blockNodeOf } from '../placement/model.js';
10
- import { REFUSED, effectOf } from './plan.js';
11
- /** What the step writers read: the reads and the structural capability. */
12
- /**
13
- * A record's order among the records standing at one block, for the
14
- * engine's sort of two records at one origin (fork patch YP22): what a split
15
- * of a list around a block writes there — a new head list holding the items
16
- * before it (`head`), new blocks placed after the items before it, which
17
- * stay (`kept`), a head holding those items and the block (`with`), the
18
- * block itself leaving (`self`), new blocks after it (`after`) — in the
19
- * order every serial run of the gestures gives (`del.merge.container`).
20
- */
21
- export const PART = { head: 0, kept: 1, with: 2, self: 3, after: 4 };
22
- /** The step writers of one facade. */
23
- export const planSteps = (c) => {
24
- const { doc, runsView, roles, rendersContentOf, view, blockTypeOf, childrenIds, positionOf, ancestorsOf, is, isIsland, itemKindOf, isLayout, displayLength, contentItems, live, isContainer, fitted, emptiable, defaultChild } = c;
25
- // ── prepared ops ─────────────────────────────────────────────
26
- // Every op is `prepare` (pure: `refused`, or a plan of named steps plus
27
- // its effect summary, against the current version) then `apply(plan)`;
28
- // composites compose their steps into one plan, so a hook sees the
29
- // whole command before any write and a refusal refuses before one.
30
- // Each prepare normalizes its inputs once, here at ingress: ids
31
- // and strings as the wire would deliver them, payloads cloned.
32
- const plan = (ids, writes) => ({
33
- ids,
34
- writes,
35
- effect: effectOf(writes),
36
- version: runsView.version()
37
- });
38
- /**
39
- * Move `ids` to display index `index` among `parent`'s children (the
40
- * slot hooks see). `side`: the move record's class among the items of
41
- * its origin (`placement/slots.ts`) — `0`, the blocks stand after what
42
- * precedes them (a move; blocks leaving a block for the gap after it:
43
- * its children, a list's last items); `1`, before what follows them
44
- * (blocks leaving a block for the gap before it: a list's first item
45
- * lifted out). In one gap every serial order of the gestures puts a
46
- * split's pieces first, then the after-records, then the before-records
47
- * (`del.merge.container`), which the engine's sort gives whatever the
48
- * client ids.
49
- * Every planned move carries the type steps that keep what the moved
50
- * blocks show: one displayed out of an island as another kind than its
51
- * stored one (`displayType`) gets that kind written, so leaving the
52
- * island's slot never brings the island's child kind back.
53
- * `at`, `part`: the block the record stands at and its order among the
54
- * records standing there, for the engine's sort of two records at one
55
- * origin (`PART`; by default the first moved block, as itself).
56
- */
57
- const moveTo = (ids, parent, index, side = 0, at, part) => ids.length === 0
58
- ? []
59
- : [
60
- {
61
- op: 'moveBlocks',
62
- ids,
63
- parent,
64
- index,
65
- ...(side === 1 && { side }),
66
- ...(at !== undefined && { at }),
67
- ...(part !== undefined && { part })
68
- },
69
- ...ids.flatMap((id) => {
70
- const shown = runsView.displayType(id);
71
- return shown === undefined ? [] : attr(id, TYPE, shown);
72
- })
73
- ];
74
- /** Move `ids` to `index` among `parent`'s children. */
75
- const move = (ids, parent, index) => moveTo(ids, parent, index);
76
- /** The side of blocks leaving a block for the gap right after it (`after`) or right before it. */
77
- const leaving = (after) => (after ? 0 : 1);
78
- /**
79
- * A type step, planned only when the kind differs (the one same-value
80
- * guard). A kind counts as the same only when the block is stored and
81
- * shown as it: a move in the same plan pins the kind a block shows
82
- * (`moveTo`), so a paragraph shown as its list's item (`itemOf`) that
83
- * an outdent settles back to a paragraph is written back.
84
- */
85
- const attr = (id, key, value) => {
86
- const same = blockNodeOf(doc, id).getAttr(key) === value;
87
- if (same && (runsView.displayType(id) ?? value) === value)
88
- return [];
89
- return [{ op: 'setBlockType', id, type: value }];
90
- };
91
- /**
92
- * The kind `kid` shows once it leaves `from` for a slot under `parent`
93
- * — the island and container rules, one answer:
94
- * - an island's child takes `parent`'s default child (it leaves the
95
- * island's kinds) — unless that renders no content while the child
96
- * does: a line then takes the document's default kind (a code line
97
- * shed into a columns layout is a paragraph), any other child
98
- * keeps its kind, as `typeOf` shows one a peer adds meanwhile;
99
- * - a container's item (its default child) takes `parent`'s default
100
- * child — an item never shows outside its list — unless it
101
- * stays inside an outer container of that kind (a nested list),
102
- * or that kind renders no content (a column in a
103
- * columns layout: its text would vanish);
104
- * - then a plain block that does not fit `parent` (`fits`: a paragraph
105
- * shed into a list) becomes its item, when that item renders content
106
- * (`fitted`). A block that cannot (a paragraph in a columns
107
- * layout) keeps its kind: its text never vanishes; any other kind (an
108
- * image, a code block, a heading) keeps its kind.
109
- */
110
- /**
111
- * The kind a child of `island` (now `kind`) takes where the default
112
- * child is `to`: `to` — unless `to` renders no content while the child
113
- * does (its text would vanish): a line then takes the document's
114
- * default kind, any other child keeps its kind (as `typeOf`).
115
- */
116
- const leavingIsland = (island, kind, to) => {
117
- if (rendersContentOf(to) || (kind !== undefined && !rendersContentOf(kind)))
118
- return to;
119
- return is(island, (type) => roles.line(type) !== undefined) ? defaultChild(null) : kind;
120
- };
121
- const settledKind = (from, kid, parent) => {
122
- let kind = blockTypeOf(kid);
123
- if (from !== null && isIsland(from))
124
- kind = leavingIsland(from, kind, defaultChild(parent));
125
- else if (from !== null && isContainer(from) && kind === defaultChild(from)) {
126
- const within = parent === null ? [] : [parent, ...ancestorsOf(parent)];
127
- const to = defaultChild(parent);
128
- // An outer container of its kind keeps it an item (a nested list); a
129
- // column's default child is the document's: it holds no items of its own.
130
- const outer = kind !== defaultChild(null) &&
131
- within.some((a) => isContainer(a) && defaultChild(a) === kind);
132
- if (!outer && rendersContentOf(to))
133
- kind = to;
134
- }
135
- return fitted(parent, kind);
136
- };
137
- /** The kind steps for the `kids` of `from` (`null`: the root) landing under `parent` (`settledKind`). */
138
- const settle = (from, kids, parent) => kids.flatMap((kid) => {
139
- const kind = settledKind(from, kid, parent);
140
- return kind === undefined || kind === blockTypeOf(kid) ? [] : attr(kid, TYPE, kind);
141
- });
142
- /** `parent` and its display ancestors: where blocks landing under `parent` keep alive. */
143
- const landing = (parent) => new Set(parent === null ? [] : [parent, ...ancestorsOf(parent)]);
144
- /**
145
- * `writes`, then every container one of `from` (the blocks' former
146
- * parents) is left with no child but `leaving` removed
147
- * (`del.range.empty-container`), and so on upward — never one of
148
- * `kept`, and only an `emptiable` one (a container holding text of its
149
- * own stays). The containers are found together, deepest first: a
150
- * list that loses its last item along with a list nested in it goes
151
- * too. Then every layout the plan leaves with one
152
- * item or none dissolves (`dissolving`); `removed`: blocks the plan
153
- * deletes besides (a block delete's members), which only that counts.
154
- */
155
- const emptyingAll = (from, leaving, writes, kept = new Set(), removed = []) => {
156
- const gone = new Set(leaving);
157
- const tops = [];
158
- const deepest = [...new Set(from)]
159
- .filter((c) => c !== null)
160
- .sort((a, b) => ancestorsOf(b).length - ancestorsOf(a).length);
161
- for (const start of deepest) {
162
- let top = null;
163
- for (let c = start; c !== null && !gone.has(c) && !kept.has(c) && emptiable(c); c = positionOf(c).parent) {
164
- if (!childrenIds(c).every((kid) => gone.has(kid)))
165
- break;
166
- gone.add((top = c));
167
- }
168
- if (top !== null)
169
- tops.push(top);
170
- }
171
- const roots = tops.filter((t) => !ancestorsOf(t).some((a) => tops.includes(a)));
172
- const steps = [...writes, ...roots.map((t) => remove(t, leaving))];
173
- for (const id of removed)
174
- gone.add(id);
175
- return [...steps, ...dissolving(gone, leaving, steps)];
176
- };
177
- /**
178
- * `layout.dissolving`: the steps that delete each layout a plan leaves
179
- * with one item or none — `gone` (blocks the plan removes) and
180
- * `leaving` (blocks it moves) no longer count, an item `writes` move or
181
- * insert into it does. With one left, the layout and that item are
182
- * deleted and the item's children moved right after the layout, where
183
- * `layout.single` shows them, as the kind they show there (`settle`);
184
- * with none, the layout is deleted. One plan with the write that caused
185
- * it.
186
- */
187
- const dissolving = (gone, leaving, writes) => {
188
- const away = new Set([...gone, ...leaving]);
189
- const layouts = new Set();
190
- for (const id of away) {
191
- const parent = positionOf(id)?.parent;
192
- if (parent != null && isLayout(parent))
193
- layouts.add(parent);
194
- }
195
- const { kids } = view();
196
- const out = [];
197
- for (const layout of layouts) {
198
- if ([layout, ...ancestorsOf(layout)].some((a) => gone.has(a)))
199
- continue;
200
- const item = itemKindOf(layout);
201
- const arriving = writes.reduce((n, w) => w.op === 'moveBlocks' && w.parent === layout
202
- ? n + w.ids.filter((id) => blockTypeOf(id) === item).length
203
- : w.op === 'insertBlocks' && w.parent === layout
204
- ? n + w.specs.filter((spec) => spec.type === item).length
205
- : n, 0);
206
- const slots = kids.get(layout) ?? [];
207
- const items = slots.filter((k) => !away.has(k.id) && blockTypeOf(k.id) === item);
208
- if (items.length + arriving > 1)
209
- continue;
210
- const { parent } = positionOf(layout);
211
- const last = items[0];
212
- if (last === undefined) {
213
- out.push(deleting(layout, [layout]));
214
- continue;
215
- }
216
- // Its blocks keep their home slots: the read shows them in the layout's
217
- // slot (`layout.single`), settled for its parent.
218
- const moved = (kids.get(last.id) ?? []).filter((k) => !away.has(k.id));
219
- const ids = moved.map((k) => k.id);
220
- out.push(...settle(last.id, ids, parent), deleting(layout, [layout, last.id]));
221
- }
222
- return out;
223
- };
224
- /** `writes`, then `container` removed when they leave it no child but `leaving` (`emptyingAll`). */
225
- const emptying = (container, leaving, writes, kept) => emptyingAll([container], leaving, writes, kept);
226
- /**
227
- * Delete: `removes` leave. Every one is marked with what it
228
- * displays — an unmarked one would be promoted into the deleted slot
229
- * (`displaySlotOf`).
230
- */
231
- const deleting = (id, removes) => {
232
- const marks = [...new Set(removes.flatMap((b) => view().displays(b)))];
233
- return { op: 'deleteBlock', id, marks, removes };
234
- };
235
- /** Delete `id` and its subtree, `kept` children aside. */
236
- const remove = (id, kept = []) => {
237
- const removes = [];
238
- const skip = new Set(kept);
239
- const walk = (b) => {
240
- removes.push(b);
241
- for (const kid of childrenIds(b))
242
- if (!skip.has(kid))
243
- walk(kid);
244
- };
245
- walk(id);
246
- return deleting(id, removes);
247
- };
248
- const merge = (from, into) => ({
249
- op: 'mergeBlocks',
250
- from,
251
- into,
252
- at: displayLength(into),
253
- length: displayLength(from)
254
- });
255
- /** `[at, end)` — `[offset, offset + length)` clamped to `id`'s display. */
256
- const clamp = (id, offset, length) => {
257
- const total = displayLength(id);
258
- const at = Math.max(0, Math.min(offset, total));
259
- return [at, Math.min(total, at + Math.max(0, length))];
260
- };
261
- /** `id`'s display items, each with its `[at, end)` display offsets. */
262
- const spans = (id) => {
263
- let end = 0;
264
- return contentItems(id).map((item) => {
265
- const at = end;
266
- end += item.kind === 'text' ? item.text.length : 1;
267
- return { item, at, end };
268
- });
269
- };
270
- /** The live inline atom `atom` in `id`'s display, or undefined. */
271
- const atomOf = (id, atom) => live(id) ? spans(id).find(({ item }) => item.kind === 'inline' && item.id === atom) : undefined;
272
- /** Text items overlapping `[at, end)` of `id` (inline atoms carry no marks). */
273
- const textIn = (id, at, end) => spans(id).flatMap((s) => (s.item.kind === 'text' && s.at < end && s.end > at ? [s.item] : []));
274
- /** Push the steps writing `items` into `id` from `at` (text runs and atoms in order); the end offset. */
275
- const writeContent = (writes, id, at, items = []) => {
276
- for (const item of items) {
277
- if (item.kind === 'inline')
278
- writes.push({ op: 'insertInline', id, offset: at++, atom: item });
279
- else if (item.text !== '') {
280
- writes.push({ op: 'insertText', id, offset: at, text: item.text, marks: item.marks });
281
- at += item.text.length;
282
- }
283
- }
284
- return at;
285
- };
286
- /** `writes`, then every container the `leaving` blocks leave with no child removed. */
287
- const emptied = (leaving, writes, kept) => emptyingAll(leaving.map((id) => positionOf(id).parent), leaving, writes, kept);
288
- return {
289
- REFUSED,
290
- plan,
291
- moveTo,
292
- move,
293
- leaving,
294
- attr,
295
- leavingIsland,
296
- settledKind,
297
- settle,
298
- landing,
299
- emptyingAll,
300
- dissolving,
301
- emptying,
302
- emptied,
303
- deleting,
304
- remove,
305
- merge,
306
- clamp,
307
- atomOf,
308
- textIn,
309
- writeContent
310
- };
311
- };
@@ -1,16 +0,0 @@
1
- import type { BlockId } from '../../placement/model.js';
2
- import type { ContentRun, RunViewDebug } from '../runs.js';
3
- import type { IndexPlacement } from './placement.js';
4
- import { type Deps } from './shared.js';
5
- import type { IndexState } from './state.js';
6
- /** The run cache of one doc's index. */
7
- export declare const indexCache: (ix: IndexState & IndexPlacement) => {
8
- intern: <T>(v: T) => T;
9
- computeFresh: (b: BlockId) => {
10
- fresh: ContentRun[];
11
- deps: Deps;
12
- };
13
- computeRuns: (b: BlockId) => void;
14
- debug: RunViewDebug;
15
- };
16
- export type IndexCache = ReturnType<typeof indexCache>;
@@ -1,175 +0,0 @@
1
- /**
2
- * The run cache: each block's visible runs as a frozen snapshot, recomputed
3
- * when a fold invalidates it, sharing unchanged runs and interned payloads.
4
- */
5
- import { cloneJsonSafe } from '../../../utils/json.js';
6
- import { canonKey, deepFreeze, displayOf, readSegs } from '../model.js';
7
- import { runEquals } from './shared.js';
8
- /** The run cache of one doc's index. */
9
- export const indexCache = (ix) => {
10
- const { blocks, textConsumers, listConsumers, cache, dirty, foldStats, frames, ownShim } = ix;
11
- const rangeStats = { items: 0, markers: 0 };
12
- // ── run cache ────────────────────────────────────────────────────
13
- const internMap = new Map();
14
- const debug = {
15
- recomputes: 0,
16
- recomputed: new Set(),
17
- get itemsWalked() {
18
- return rangeStats.items;
19
- },
20
- get markersWalked() {
21
- return rangeStats.markers;
22
- },
23
- get frames() {
24
- return frames.size;
25
- },
26
- get folds() {
27
- return foldStats.folds;
28
- },
29
- get foldedPairs() {
30
- return foldStats.pairs;
31
- },
32
- get foldedStructs() {
33
- return foldStats.structs;
34
- },
35
- get placements() {
36
- return foldStats.placed;
37
- },
38
- reset() {
39
- debug.recomputes = 0;
40
- debug.recomputed.clear();
41
- foldStats.folds = 0;
42
- foldStats.pairs = 0;
43
- foldStats.structs = 0;
44
- foldStats.placed = 0;
45
- rangeStats.items = 0;
46
- rangeStats.markers = 0;
47
- }
48
- };
49
- // ── interning / freezing ─────────────────────────────────────────
50
- // `cloneJsonSafe` is total even against hostile replicated payloads,
51
- // and interning the normalized form keys it by its own canonical shape.
52
- // The shared instance is built FROM that key (sorted keys): it must not
53
- // remember the key order its first reader happened to fold, or
54
- // `toJSON` would depend on when the view was read.
55
- const intern = (v) => {
56
- const key = canonKey(cloneJsonSafe(v));
57
- let f = internMap.get(key);
58
- if (f === undefined)
59
- internMap.set(key, (f = deepFreeze(JSON.parse(key))));
60
- return f;
61
- };
62
- // ── dep bookkeeping ──────────────────────────────────────────────
63
- const drop = (index, keys, b) => {
64
- for (const k of keys) {
65
- const set = index.get(k);
66
- set?.delete(b);
67
- if (set?.size === 0)
68
- index.delete(k);
69
- }
70
- };
71
- const add = (index, keys, b) => {
72
- for (const k of keys) {
73
- let set = index.get(k);
74
- if (set === undefined)
75
- index.set(k, (set = new Set()));
76
- set.add(b);
77
- }
78
- };
79
- const applyDeps = (b, deps) => {
80
- const old = cache.get(b)?.deps;
81
- if (old) {
82
- drop(textConsumers, old.texts, b);
83
- drop(listConsumers, old.lists, b);
84
- }
85
- add(textConsumers, deps.texts, b);
86
- add(listConsumers, deps.lists, b);
87
- };
88
- // ── snapshot construction ────────────────────────────────────────
89
- const freezeFresh = (r) => Object.freeze(r);
90
- /** The normalized fresh runs of `b` (interned payloads, equal marks merged) and their deps. */
91
- const computeFresh = (b) => {
92
- const deps = { texts: new Set(), lists: new Set([b]) };
93
- const segs = displayOf(b, blocks, ownShim, (x, home) => {
94
- deps.lists.add(x);
95
- if (home !== undefined)
96
- deps.texts.add(home);
97
- // Every claim on a walked list is read, followed or not: a claim
98
- // skipped for a dead target or a higher claimer becomes effective
99
- // when that target revives or its winning claim goes away.
100
- for (const c of blocks.get(x)?.claims ?? [])
101
- deps.lists.add(c.m);
102
- }) ?? [];
103
- const fresh = [];
104
- for (const item of readSegs(segs, rangeStats)) {
105
- if (item.kind === 'text') {
106
- const last = fresh[fresh.length - 1];
107
- const marks = item.marks === undefined ? undefined : intern(item.marks);
108
- if (last && last.kind === 'text' && last.marks === marks) {
109
- last.text += item.text;
110
- }
111
- else {
112
- fresh.push({
113
- kind: 'text',
114
- text: item.text,
115
- ...(marks === undefined ? {} : { marks })
116
- });
117
- }
118
- }
119
- else {
120
- fresh.push({
121
- kind: 'inline',
122
- id: item.id,
123
- type: item.type,
124
- ...(item.data === undefined ? {} : { data: intern(item.data) })
125
- });
126
- }
127
- }
128
- return { fresh, deps };
129
- };
130
- /**
131
- * Structural sharing: reuse unchanged run objects from `old` — maximal
132
- * equal prefix + equal suffix; `old` itself when every run is identical.
133
- */
134
- const reconcile = (old, fresh) => {
135
- if (!old)
136
- return Object.freeze(fresh.map(freezeFresh));
137
- let s = 0;
138
- const n = Math.min(old.length, fresh.length);
139
- while (s < n && runEquals(old[s], fresh[s]))
140
- s++;
141
- if (s === old.length && s === fresh.length)
142
- return old;
143
- let eo = old.length - 1;
144
- let ef = fresh.length - 1;
145
- while (eo >= s && ef >= s && runEquals(old[eo], fresh[ef])) {
146
- eo--;
147
- ef--;
148
- }
149
- const out = new Array(fresh.length);
150
- for (let i = 0; i < s; i++)
151
- out[i] = old[i];
152
- for (let i = s; i <= ef; i++)
153
- out[i] = freezeFresh(fresh[i]);
154
- for (let i = eo + 1; i < old.length; i++)
155
- out[fresh.length - (old.length - i)] = old[i];
156
- return Object.freeze(out);
157
- };
158
- // ── recompute ────────────────────────────────────────────────────
159
- const computeRuns = (b) => {
160
- const old = cache.get(b);
161
- const { fresh, deps } = computeFresh(b);
162
- const runs = reconcile(old?.runs, fresh);
163
- applyDeps(b, deps);
164
- cache.set(b, { runs, deps });
165
- dirty.delete(b);
166
- debug.recomputes++;
167
- debug.recomputed.add(b);
168
- };
169
- return {
170
- intern,
171
- computeFresh,
172
- computeRuns,
173
- debug
174
- };
175
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * The claim graph (maintained): each block's owner along the max-stamp
3
- * claims (`top`), the blocks each owner displays, and what a structural
4
- * change of a block invalidates.
5
- */
6
- import type { BlockId } from '../../placement/model.js';
7
- import { type Claim, type Owner } from '../model.js';
8
- import type { FoldCtx, IndexState } from './state.js';
9
- /** The claim graph of one doc's index, over its state. */
10
- export declare const indexClaims: (ix: IndexState) => {
11
- ensureOwners: () => void;
12
- ownerOf: (b: BlockId) => Owner;
13
- top: (m: BlockId) => BlockId | undefined;
14
- displays: (owner: BlockId) => readonly BlockId[];
15
- noteClaims: (id: BlockId, before: readonly Claim[], after: readonly Claim[]) => void;
16
- invalidateBlock: (id: BlockId, ctx: FoldCtx, claimsBefore?: Claim[]) => void;
17
- };
18
- export type IndexClaims = ReturnType<typeof indexClaims>;