@agentshouse/mdruntime 0.1.0-cb95ca2c884cf → 0.1.0-cb9c79aee537a
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/AGENTS.md +275 -275
- package/README.md +8 -8
- package/dist/adapter.d.ts +51 -9
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attempt.d.ts.map +1 -1
- package/dist/attempt.js +14 -1
- package/dist/bootstrap.d.ts +3 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +33 -7
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +36 -10
- package/dist/chat/acts.d.ts +3 -4
- package/dist/chat/acts.d.ts.map +1 -1
- package/dist/chat/acts.js +10 -10
- package/dist/chat/earlier.d.ts +10 -0
- package/dist/chat/earlier.d.ts.map +1 -0
- package/dist/chat/earlier.js +54 -0
- package/dist/chat/kit.d.ts +2 -1
- package/dist/chat/kit.d.ts.map +1 -1
- package/dist/chat/kit.js +3 -3
- package/dist/chat/list.d.ts +8 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +48 -8
- package/dist/chat/markdown.d.ts +3 -1
- package/dist/chat/markdown.d.ts.map +1 -1
- package/dist/chat/markdown.js +85 -26
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chat/messages.d.ts +1 -0
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +4 -0
- package/dist/chat/pieces.d.ts +51 -0
- package/dist/chat/pieces.d.ts.map +1 -0
- package/dist/chat/pieces.js +797 -0
- package/dist/chat/provider.d.ts +1 -1
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +62 -79
- package/dist/chat/question.d.ts +1 -1
- package/dist/chat/question.d.ts.map +1 -1
- package/dist/chat/question.js +7 -18
- package/dist/chat/ready.d.ts +1 -0
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +4 -4
- package/dist/chat/style.js +4 -4
- package/dist/chat.d.ts +1 -1
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +1 -1
- package/dist/client.d.ts +17 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +19 -6
- package/dist/collection.d.ts +20 -5
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +309 -33
- package/dist/connection.d.ts +31 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1573 -372
- package/dist/conversation.d.ts +20 -7
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +474 -163
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +17 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +157 -0
- package/dist/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/host.d.ts +15 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +94 -12
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +6 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/memory.d.ts +8 -2
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +33 -6
- package/dist/model.d.ts +4 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -1
- package/dist/observation.d.ts +7 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +29 -12
- package/dist/outcome.d.ts +12 -2
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +4 -0
- package/dist/overlay.d.ts +3 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +62 -55
- package/dist/query.d.ts +56 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +36 -7
- package/dist/reach.d.ts +6 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +30 -5
- package/dist/react.d.ts +8 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- package/dist/read-side.d.ts +16 -7
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +484 -100
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +98 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +197 -0
- package/dist/refresh.d.ts +4 -4
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +18 -11
- package/dist/replica.d.ts +10 -5
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +95 -32
- package/dist/room-draft.d.ts +13 -1
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +2 -2
- package/dist/rows.d.ts +6 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +10 -13
- package/dist/save.d.ts +9 -3
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +68 -22
- package/dist/search.d.ts +49 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +192 -47
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +75 -0
- package/dist/shared.d.ts +14 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +394 -0
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +59 -12
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +350 -86
- package/dist/turn.d.ts +9 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +64 -0
- package/dist/windows.d.ts +26 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +93 -0
- package/dist/wire.d.ts +152 -32
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +52 -31
- package/package.json +6 -2
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
2
|
+
import { gfmFromMarkdown } from 'mdast-util-gfm';
|
|
3
|
+
import { gfm } from 'micromark-extension-gfm';
|
|
4
|
+
export function parseMarkdown(text) {
|
|
5
|
+
return fromMarkdown(text, { extensions: [gfm()], mdastExtensions: [gfmFromMarkdown()] });
|
|
6
|
+
}
|
|
7
|
+
const VIEW_CHARS = 16_384;
|
|
8
|
+
const WINDOW_CHARS = 2 * VIEW_CHARS;
|
|
9
|
+
const WINDOW_LINES = 2_048;
|
|
10
|
+
const SPAN_CHARS = WINDOW_CHARS;
|
|
11
|
+
const TRACKS = 32;
|
|
12
|
+
const FENCE = /^(`{3,}|~{3,})(.*)$/;
|
|
13
|
+
const CLOSING = /^(`{3,}|~{3,})[ \t]*$/;
|
|
14
|
+
const RAW = [
|
|
15
|
+
[/^<(?:script|pre|style|textarea)(?:[ \t>]|$)/i, /<\/(?:script|pre|style|textarea)>/i],
|
|
16
|
+
[/^<!--/, /-->/],
|
|
17
|
+
[/^<\?/, /\?>/],
|
|
18
|
+
[/^<![A-Za-z]/, />/],
|
|
19
|
+
[/^<!\[CDATA\[/, /\]\]>/],
|
|
20
|
+
];
|
|
21
|
+
const TAG = /^<[A-Za-z/]/;
|
|
22
|
+
const ATX = /^#{1,6}(?:[ \t]|$)/;
|
|
23
|
+
const THEMATIC = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/;
|
|
24
|
+
const UNDERLINE = /^(?:=+|-+)[ \t]*$/;
|
|
25
|
+
const ITEM = /^(?:[-+*]|(\d{1,9})[.)])(?=[ \t]|$)/;
|
|
26
|
+
const UNRESOLVED = /^\[(?:[^\\[\]]|\\.)+\]:[ \t]*$/;
|
|
27
|
+
const DELIMITER_ROW = /^\|?[ \t]*:?-+:?[ \t]*(?:\|[ \t]*:?-+:?[ \t]*)*\|?[ \t]*$/;
|
|
28
|
+
const CANDIDATE = /^[ \t>]*(?:(?:[-+*]|\d{1,9}[.)])[ \t]+[ \t>]*)*\[/;
|
|
29
|
+
const DEFINED = /\[((?:[^\\[\]]|\\[\s\S]){1,999})\]:/y;
|
|
30
|
+
const LABEL = /\[((?:[^\\[\]]|\\[\s\S]){1,999})\]/g;
|
|
31
|
+
const QUOTE_BREAK = /^[ \t>]*$/;
|
|
32
|
+
const BLOCK_START = /[\s#>+*=_`~<|-]/;
|
|
33
|
+
const ORDERED = /\d{1,9}[.)](?=[ \t\r\n]|$)/y;
|
|
34
|
+
const SPACE = /\s/u;
|
|
35
|
+
const PUNCTUATION = /[\p{P}\p{S}]/u;
|
|
36
|
+
const ESCAPABLE = /[!-/:-@[-`{-~]/;
|
|
37
|
+
const TAG_START = /[A-Za-z!?/]/;
|
|
38
|
+
const LINE_ENDING = /\r\n?|\n/g;
|
|
39
|
+
const START = {
|
|
40
|
+
fence: null,
|
|
41
|
+
list: null,
|
|
42
|
+
empty: false,
|
|
43
|
+
para: false,
|
|
44
|
+
table: false,
|
|
45
|
+
quote: false,
|
|
46
|
+
unresolved: false,
|
|
47
|
+
};
|
|
48
|
+
export function identifierOf(label) {
|
|
49
|
+
return label
|
|
50
|
+
.replace(/(?:\r\n?|\n)[ \t>]*/g, '\n')
|
|
51
|
+
.replace(/[\t\n\r ]+/g, ' ')
|
|
52
|
+
.replace(/^ | $/g, '')
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.toUpperCase()
|
|
55
|
+
.toLowerCase();
|
|
56
|
+
}
|
|
57
|
+
function lineOf(long, at) {
|
|
58
|
+
let low = 0;
|
|
59
|
+
let high = long.starts.length - 2;
|
|
60
|
+
while (low < high) {
|
|
61
|
+
const middle = (low + high + 1) >> 1;
|
|
62
|
+
if (long.starts[middle] <= at)
|
|
63
|
+
low = middle;
|
|
64
|
+
else
|
|
65
|
+
high = middle - 1;
|
|
66
|
+
}
|
|
67
|
+
return low;
|
|
68
|
+
}
|
|
69
|
+
function lineEnd(starts, text, index) {
|
|
70
|
+
return Math.min(starts[index + 1] - 1, text.length);
|
|
71
|
+
}
|
|
72
|
+
function lineText(starts, text, index) {
|
|
73
|
+
const end = lineEnd(starts, text, index);
|
|
74
|
+
return text.slice(starts[index], text[end - 1] === '\r' ? end - 1 : end);
|
|
75
|
+
}
|
|
76
|
+
function lineStartOf(long, at) {
|
|
77
|
+
return long.starts[lineOf(long, at)];
|
|
78
|
+
}
|
|
79
|
+
function lineFacts(raw) {
|
|
80
|
+
let indent = 0;
|
|
81
|
+
let index = 0;
|
|
82
|
+
while (index < raw.length && (raw[index] === ' ' || raw[index] === '\t')) {
|
|
83
|
+
indent += raw[index] === '\t' ? 4 - (indent % 4) : 1;
|
|
84
|
+
index += 1;
|
|
85
|
+
}
|
|
86
|
+
const content = raw.slice(index);
|
|
87
|
+
return { raw, indent, content, blank: content === '' };
|
|
88
|
+
}
|
|
89
|
+
function itemOf(line) {
|
|
90
|
+
if (line.indent > 3 || THEMATIC.test(line.content))
|
|
91
|
+
return null;
|
|
92
|
+
const marker = ITEM.exec(line.content);
|
|
93
|
+
if (marker === null)
|
|
94
|
+
return null;
|
|
95
|
+
const width = marker[0].length;
|
|
96
|
+
let columns = line.indent + width;
|
|
97
|
+
let index = width;
|
|
98
|
+
while (index < line.content.length && /[ \t]/.test(line.content[index])) {
|
|
99
|
+
columns += line.content[index] === '\t' ? 4 - (columns % 4) : 1;
|
|
100
|
+
index += 1;
|
|
101
|
+
}
|
|
102
|
+
const empty = index === line.content.length;
|
|
103
|
+
const spacing = columns - line.indent - width;
|
|
104
|
+
return {
|
|
105
|
+
indent: empty || spacing >= 5 ? line.indent + width + 1 : columns,
|
|
106
|
+
empty,
|
|
107
|
+
interrupts: !empty && (marker[1] === undefined || Number(marker[1]) === 1),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function fenceOf(line) {
|
|
111
|
+
if (line.indent > 3)
|
|
112
|
+
return null;
|
|
113
|
+
const fence = FENCE.exec(line.content);
|
|
114
|
+
if (fence === null || (fence[1][0] === '`' && fence[2].includes('`')))
|
|
115
|
+
return null;
|
|
116
|
+
return `${fence[1][0]}${fence[1].length}`;
|
|
117
|
+
}
|
|
118
|
+
function opens(line) {
|
|
119
|
+
if (line.indent > 3)
|
|
120
|
+
return false;
|
|
121
|
+
return (fenceOf(line) !== null ||
|
|
122
|
+
RAW.some(([start]) => start.test(line.content)) ||
|
|
123
|
+
line.content.startsWith('>') ||
|
|
124
|
+
ATX.test(line.content) ||
|
|
125
|
+
THEMATIC.test(line.content) ||
|
|
126
|
+
itemOf(line) !== null);
|
|
127
|
+
}
|
|
128
|
+
function fenced(track, line) {
|
|
129
|
+
const fence = track.fence;
|
|
130
|
+
if (fence === 'html')
|
|
131
|
+
return line.blank ? { ...track, fence: null } : track;
|
|
132
|
+
if (fence.startsWith('raw')) {
|
|
133
|
+
return RAW[Number(fence.slice(3))][1].test(line.raw) ? { ...track, fence: null } : track;
|
|
134
|
+
}
|
|
135
|
+
const close = line.indent <= 3 ? CLOSING.exec(line.content) : null;
|
|
136
|
+
const closes = close !== null && close[1][0] === fence[0] && close[1].length >= Number(fence.slice(1));
|
|
137
|
+
return closes ? { ...track, fence: null } : track;
|
|
138
|
+
}
|
|
139
|
+
function prose(track, plain, line) {
|
|
140
|
+
if (track.table)
|
|
141
|
+
return [{ ...plain, para: false }];
|
|
142
|
+
const paragraph = { ...plain, para: true, unresolved: UNRESOLVED.test(line.content) };
|
|
143
|
+
return track.quote ? [{ ...plain, para: false, quote: true }, paragraph] : [paragraph];
|
|
144
|
+
}
|
|
145
|
+
function topLevel(track, line) {
|
|
146
|
+
const plain = { ...track, list: null, empty: false, quote: false, unresolved: false };
|
|
147
|
+
if (line.indent >= 4)
|
|
148
|
+
return [{ ...plain, para: track.para }];
|
|
149
|
+
const fence = fenceOf(line);
|
|
150
|
+
if (fence !== null) {
|
|
151
|
+
const opened = { ...plain, fence, para: false, table: false };
|
|
152
|
+
return track.table || track.unresolved ? [opened, { ...plain, para: false }] : [opened];
|
|
153
|
+
}
|
|
154
|
+
const raw = RAW.findIndex(([start]) => start.test(line.content));
|
|
155
|
+
if (raw !== -1) {
|
|
156
|
+
const [start, end] = RAW[raw];
|
|
157
|
+
const closed = end.test(line.content.replace(start, ''));
|
|
158
|
+
const opened = { ...plain, fence: closed ? null : `raw${raw}`, para: false, table: false };
|
|
159
|
+
return track.table ? [opened, { ...plain, para: false }] : [opened];
|
|
160
|
+
}
|
|
161
|
+
if (TAG.test(line.content)) {
|
|
162
|
+
return [{ ...plain, fence: 'html', para: false, table: false }, ...prose(track, plain, line)];
|
|
163
|
+
}
|
|
164
|
+
if (line.content.startsWith('>'))
|
|
165
|
+
return [{ ...plain, para: false, table: false, quote: true }];
|
|
166
|
+
if (ATX.test(line.content) || THEMATIC.test(line.content)) {
|
|
167
|
+
return [{ ...plain, para: false, table: false }];
|
|
168
|
+
}
|
|
169
|
+
const item = itemOf(line);
|
|
170
|
+
if (item !== null) {
|
|
171
|
+
const opened = { ...plain, list: item.indent, empty: item.empty, para: false, table: false };
|
|
172
|
+
if (!item.interrupts && track.para)
|
|
173
|
+
return [{ ...plain, para: true }];
|
|
174
|
+
return track.table || (!item.interrupts && track.quote)
|
|
175
|
+
? [opened, ...prose(track, plain, line)]
|
|
176
|
+
: [opened];
|
|
177
|
+
}
|
|
178
|
+
if (track.para && UNDERLINE.test(line.content))
|
|
179
|
+
return [{ ...plain, para: false, table: false }];
|
|
180
|
+
if (track.para && DELIMITER_ROW.test(line.content)) {
|
|
181
|
+
return [
|
|
182
|
+
{ ...plain, para: false, table: true },
|
|
183
|
+
{ ...plain, para: true },
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
return prose(track, plain, line);
|
|
187
|
+
}
|
|
188
|
+
function advance(track, line, blankBefore) {
|
|
189
|
+
if (track.fence !== null)
|
|
190
|
+
return [fenced(track, line)];
|
|
191
|
+
if (line.blank) {
|
|
192
|
+
const blank = { ...track, para: false, table: false, quote: false, unresolved: false };
|
|
193
|
+
return track.empty
|
|
194
|
+
? [
|
|
195
|
+
{ ...blank, empty: false },
|
|
196
|
+
{ ...blank, list: null, empty: false },
|
|
197
|
+
]
|
|
198
|
+
: [blank];
|
|
199
|
+
}
|
|
200
|
+
if (track.list === null)
|
|
201
|
+
return topLevel(track, line);
|
|
202
|
+
if (line.indent >= track.list) {
|
|
203
|
+
return [{ ...track, empty: false, para: false, table: false, quote: false, unresolved: false }];
|
|
204
|
+
}
|
|
205
|
+
const closed = topLevel({ ...track, list: null, empty: false, para: false, table: false, quote: false }, line);
|
|
206
|
+
if (blankBefore || opens(line))
|
|
207
|
+
return closed;
|
|
208
|
+
return [{ ...track, empty: false, para: false, quote: false, unresolved: false }, ...closed];
|
|
209
|
+
}
|
|
210
|
+
function trackKey(track) {
|
|
211
|
+
return `${track.fence}|${track.list}|${track.empty}|${track.para}|${track.table}|${track.quote}|${track.unresolved}`;
|
|
212
|
+
}
|
|
213
|
+
function candidatesOf(text, start, raw, found) {
|
|
214
|
+
const lead = CANDIDATE.exec(raw);
|
|
215
|
+
if (lead === null)
|
|
216
|
+
return;
|
|
217
|
+
let at = start + lead[0].length - 1;
|
|
218
|
+
for (;;) {
|
|
219
|
+
DEFINED.lastIndex = at;
|
|
220
|
+
const label = DEFINED.exec(text);
|
|
221
|
+
if (label === null)
|
|
222
|
+
return;
|
|
223
|
+
const key = identifierOf(label[1]);
|
|
224
|
+
const held = found.get(key);
|
|
225
|
+
if (held === undefined)
|
|
226
|
+
found.set(key, [at]);
|
|
227
|
+
else
|
|
228
|
+
held.push(at);
|
|
229
|
+
if (!label[1].startsWith('^'))
|
|
230
|
+
return;
|
|
231
|
+
at = DEFINED.lastIndex;
|
|
232
|
+
while (text[at] === ' ' || text[at] === '\t')
|
|
233
|
+
at += 1;
|
|
234
|
+
if (text[at] !== '[')
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function breaksOf(flags) {
|
|
239
|
+
const breaks = new Int32Array(flags.length + 1);
|
|
240
|
+
breaks[flags.length] = flags.length;
|
|
241
|
+
for (let index = flags.length - 1; index >= 0; index -= 1) {
|
|
242
|
+
breaks[index] = flags[index] === 1 ? index : breaks[index + 1];
|
|
243
|
+
}
|
|
244
|
+
return breaks;
|
|
245
|
+
}
|
|
246
|
+
export function longOf(text) {
|
|
247
|
+
const offsets = [];
|
|
248
|
+
let at = 0;
|
|
249
|
+
while (at < text.length) {
|
|
250
|
+
offsets.push(at);
|
|
251
|
+
LINE_ENDING.lastIndex = at;
|
|
252
|
+
at = LINE_ENDING.test(text) ? LINE_ENDING.lastIndex : text.length + 1;
|
|
253
|
+
}
|
|
254
|
+
offsets.push(at);
|
|
255
|
+
const starts = Int32Array.from(offsets);
|
|
256
|
+
const count = starts.length - 1;
|
|
257
|
+
const blank = new Uint8Array(count);
|
|
258
|
+
const quoteBlank = new Uint8Array(count);
|
|
259
|
+
const anchors = [0];
|
|
260
|
+
const candidates = new Map();
|
|
261
|
+
let tracks = [START];
|
|
262
|
+
let lost = false;
|
|
263
|
+
for (let index = 0; index < count; index += 1) {
|
|
264
|
+
const line = lineFacts(lineText(starts, text, index));
|
|
265
|
+
const before = index === 0 || blank[index - 1] === 1;
|
|
266
|
+
blank[index] = line.blank ? 1 : 0;
|
|
267
|
+
quoteBlank[index] = QUOTE_BREAK.test(line.raw) ? 1 : 0;
|
|
268
|
+
if (index > 0 && !lost && !line.blank && before && line.indent <= 1) {
|
|
269
|
+
if (tracks.every((track) => track.fence === null))
|
|
270
|
+
anchors.push(starts[index]);
|
|
271
|
+
}
|
|
272
|
+
candidatesOf(text, starts[index], line.raw, candidates);
|
|
273
|
+
if (lost)
|
|
274
|
+
continue;
|
|
275
|
+
const advanced = new Map();
|
|
276
|
+
for (const track of tracks) {
|
|
277
|
+
for (const one of advance(track, line, before))
|
|
278
|
+
advanced.set(trackKey(one), one);
|
|
279
|
+
}
|
|
280
|
+
tracks = [...advanced.values()];
|
|
281
|
+
lost = tracks.length > TRACKS;
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
text,
|
|
285
|
+
starts,
|
|
286
|
+
breaks: breaksOf(blank),
|
|
287
|
+
quoteBreaks: breaksOf(quoteBlank),
|
|
288
|
+
anchors,
|
|
289
|
+
candidates,
|
|
290
|
+
pieces: [],
|
|
291
|
+
next: { start: 0, path: [], join: '', carry: '' },
|
|
292
|
+
urls: new Map(),
|
|
293
|
+
spans: new Map(),
|
|
294
|
+
discoveries: new Map(),
|
|
295
|
+
regions: new Map(),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function offsetOf(node) {
|
|
299
|
+
return node.position.start.offset;
|
|
300
|
+
}
|
|
301
|
+
function endOf(node) {
|
|
302
|
+
return node.position.end.offset;
|
|
303
|
+
}
|
|
304
|
+
function definedIn(nodes, shift, found = []) {
|
|
305
|
+
for (const node of nodes) {
|
|
306
|
+
if (node.type === 'definition') {
|
|
307
|
+
found.push({ key: node.identifier, at: offsetOf(node) + shift, url: node.url });
|
|
308
|
+
}
|
|
309
|
+
else if (node.type === 'footnoteDefinition') {
|
|
310
|
+
found.push({ key: `^${node.identifier}`, at: offsetOf(node) + shift, url: '' });
|
|
311
|
+
}
|
|
312
|
+
if (node.type === 'blockquote' ||
|
|
313
|
+
node.type === 'list' ||
|
|
314
|
+
node.type === 'listItem' ||
|
|
315
|
+
node.type === 'footnoteDefinition') {
|
|
316
|
+
definedIn(node.children, shift, found);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return found;
|
|
320
|
+
}
|
|
321
|
+
function windowOf(long, from, end, prefix) {
|
|
322
|
+
const root = parseMarkdown(`${prefix}${from.carry}${long.text.slice(from.start, end)}`);
|
|
323
|
+
const lead = prefix.length + from.carry.length;
|
|
324
|
+
const nodes = root.children.filter((node) => offsetOf(node) >= prefix.length);
|
|
325
|
+
return {
|
|
326
|
+
start: from.start,
|
|
327
|
+
end,
|
|
328
|
+
lead,
|
|
329
|
+
prefix,
|
|
330
|
+
carry: from.carry,
|
|
331
|
+
nodes,
|
|
332
|
+
defined: definedIn(nodes, from.start - lead),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function spanned(long, anchor, stop) {
|
|
336
|
+
const key = `${anchor}:${stop}`;
|
|
337
|
+
const held = long.spans.get(key);
|
|
338
|
+
if (held !== undefined)
|
|
339
|
+
return held;
|
|
340
|
+
const found = definedIn(parseMarkdown(long.text.slice(anchor, stop)).children, anchor);
|
|
341
|
+
long.spans.set(key, found);
|
|
342
|
+
return found;
|
|
343
|
+
}
|
|
344
|
+
function discovered(long, anchor, stop) {
|
|
345
|
+
let discovery = long.discoveries.get(anchor);
|
|
346
|
+
if (discovery === undefined) {
|
|
347
|
+
discovery = { found: [], next: { start: anchor, path: [], join: '', carry: '' } };
|
|
348
|
+
long.discoveries.set(anchor, discovery);
|
|
349
|
+
}
|
|
350
|
+
while (discovery.next !== null && discovery.next.start < stop) {
|
|
351
|
+
const from = discovery.next;
|
|
352
|
+
const { window, cut } = cutWindow(long, from, 'discover', (end) => windowOf(long, from, end, ''));
|
|
353
|
+
const end = cut?.at ?? long.text.length;
|
|
354
|
+
discovery.found.push(...window.defined.filter((one) => one.at < end));
|
|
355
|
+
discovery.next =
|
|
356
|
+
cut === null ? null : { start: cut.at, path: cut.path, join: cut.join, carry: cut.carry };
|
|
357
|
+
}
|
|
358
|
+
return discovery.found;
|
|
359
|
+
}
|
|
360
|
+
function anchorBefore(long, at) {
|
|
361
|
+
let low = 0;
|
|
362
|
+
let high = long.anchors.length - 1;
|
|
363
|
+
while (low < high) {
|
|
364
|
+
const middle = (low + high + 1) >> 1;
|
|
365
|
+
if (long.anchors[middle] <= at)
|
|
366
|
+
low = middle;
|
|
367
|
+
else
|
|
368
|
+
high = middle - 1;
|
|
369
|
+
}
|
|
370
|
+
return long.anchors[low];
|
|
371
|
+
}
|
|
372
|
+
function verified(long, at, key) {
|
|
373
|
+
const line = lineOf(long, at);
|
|
374
|
+
const anchor = anchorBefore(long, long.starts[line]);
|
|
375
|
+
const stop = Math.min(long.starts[long.breaks[line]], long.text.length);
|
|
376
|
+
const found = stop - anchor <= SPAN_CHARS ? spanned(long, anchor, stop) : discovered(long, anchor, stop);
|
|
377
|
+
return found.find((one) => one.key === key && one.at === at)?.url ?? null;
|
|
378
|
+
}
|
|
379
|
+
function realFrom(long, key, position) {
|
|
380
|
+
for (const at of long.candidates.get(key) ?? []) {
|
|
381
|
+
if (at < position)
|
|
382
|
+
continue;
|
|
383
|
+
const url = verified(long, at, key);
|
|
384
|
+
if (url !== null)
|
|
385
|
+
return url;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
function dummy(key) {
|
|
390
|
+
const label = key.startsWith('^') ? `^${key.slice(1)}` : key;
|
|
391
|
+
const trailing = /\\+$/.exec(label)?.[0].length ?? 0;
|
|
392
|
+
return `[${label}${trailing % 2 === 1 ? ' ' : ''}]: x`;
|
|
393
|
+
}
|
|
394
|
+
function prefixOf(keys) {
|
|
395
|
+
return keys.length === 0 ? '' : `${keys.map(dummy).join('\n')}\n\n***\n\n`;
|
|
396
|
+
}
|
|
397
|
+
function renderWindow(long, from, end) {
|
|
398
|
+
const known = [];
|
|
399
|
+
const deferred = [];
|
|
400
|
+
const seen = new Set();
|
|
401
|
+
for (const found of `${from.carry}${long.text.slice(from.start, end)}`.matchAll(LABEL)) {
|
|
402
|
+
const key = identifierOf(found[1]);
|
|
403
|
+
if (seen.has(key))
|
|
404
|
+
continue;
|
|
405
|
+
seen.add(key);
|
|
406
|
+
if (long.urls.has(key)) {
|
|
407
|
+
known.push(key);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
const first = long.candidates.get(key)?.find((at) => at >= from.start);
|
|
411
|
+
if (first === undefined)
|
|
412
|
+
continue;
|
|
413
|
+
if (first < end) {
|
|
414
|
+
deferred.push(key);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const url = realFrom(long, key, end);
|
|
418
|
+
if (url === null)
|
|
419
|
+
continue;
|
|
420
|
+
long.urls.set(key, url);
|
|
421
|
+
known.push(key);
|
|
422
|
+
}
|
|
423
|
+
const window = windowOf(long, from, end, prefixOf(known));
|
|
424
|
+
const later = [];
|
|
425
|
+
for (const key of deferred) {
|
|
426
|
+
const native = window.defined.find((one) => one.key === key);
|
|
427
|
+
if (native !== undefined) {
|
|
428
|
+
long.urls.set(key, native.url);
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const url = realFrom(long, key, from.start);
|
|
432
|
+
if (url === null)
|
|
433
|
+
continue;
|
|
434
|
+
long.urls.set(key, url);
|
|
435
|
+
later.push(key);
|
|
436
|
+
}
|
|
437
|
+
return later.length === 0 ? window : windowOf(long, from, end, prefixOf([...known, ...later]));
|
|
438
|
+
}
|
|
439
|
+
function windowEnd(long, start, size) {
|
|
440
|
+
const at = start + size;
|
|
441
|
+
if (at >= long.text.length)
|
|
442
|
+
return long.text.length;
|
|
443
|
+
const end = lineEnd(long.starts, long.text, lineOf(long, at));
|
|
444
|
+
return end - at <= VIEW_CHARS ? Math.min(end + 1, long.text.length) : at;
|
|
445
|
+
}
|
|
446
|
+
function regionOf(long, line, depth) {
|
|
447
|
+
const stop = (depth > 0 ? long.quoteBreaks : long.breaks)[line];
|
|
448
|
+
const markers = markersOf(depth);
|
|
449
|
+
const name = `${depth}:${stop}`;
|
|
450
|
+
const held = long.regions.get(name);
|
|
451
|
+
if (held !== undefined)
|
|
452
|
+
return held;
|
|
453
|
+
const { text, starts } = long;
|
|
454
|
+
let setext = false;
|
|
455
|
+
for (let index = line + 1; index < stop && !setext; index += 1) {
|
|
456
|
+
const raw = lineText(starts, text, index);
|
|
457
|
+
const facts = lineFacts(raw.replace(markers, ''));
|
|
458
|
+
setext = facts.indent <= 3 && UNDERLINE.test(facts.content);
|
|
459
|
+
}
|
|
460
|
+
const from = starts[line];
|
|
461
|
+
const to = Math.min(starts[stop], text.length);
|
|
462
|
+
const last = new Map();
|
|
463
|
+
for (const one of ['*', '_', '~', ']', '>'])
|
|
464
|
+
last.set(one, text.lastIndexOf(one, to - 1));
|
|
465
|
+
const runs = new Map();
|
|
466
|
+
for (let at = text.indexOf('`', from); at !== -1 && at < to;) {
|
|
467
|
+
let end = at;
|
|
468
|
+
while (text[end] === '`')
|
|
469
|
+
end += 1;
|
|
470
|
+
runs.set(end - at, at);
|
|
471
|
+
at = text.indexOf('`', end);
|
|
472
|
+
}
|
|
473
|
+
const region = { setext, last, runs };
|
|
474
|
+
long.regions.set(name, region);
|
|
475
|
+
return region;
|
|
476
|
+
}
|
|
477
|
+
const CODE = 1;
|
|
478
|
+
const LINKED = 2;
|
|
479
|
+
const EMPHASIZED = 4;
|
|
480
|
+
function marked(node, flags, shift, start, text) {
|
|
481
|
+
if (!('children' in node))
|
|
482
|
+
return;
|
|
483
|
+
for (const child of node.children) {
|
|
484
|
+
const from = Math.max(offsetOf(child) + shift - start, 0);
|
|
485
|
+
const to = Math.min(endOf(child) + shift - start, flags.length);
|
|
486
|
+
const flag = child.type === 'inlineCode' || child.type === 'html'
|
|
487
|
+
? CODE
|
|
488
|
+
: child.type === 'link'
|
|
489
|
+
? text[offsetOf(child) + shift] === '<'
|
|
490
|
+
? CODE
|
|
491
|
+
: LINKED
|
|
492
|
+
: child.type === 'image' ||
|
|
493
|
+
child.type === 'linkReference' ||
|
|
494
|
+
child.type === 'imageReference' ||
|
|
495
|
+
child.type === 'footnoteReference'
|
|
496
|
+
? LINKED
|
|
497
|
+
: child.type === 'emphasis' || child.type === 'strong' || child.type === 'delete'
|
|
498
|
+
? EMPHASIZED
|
|
499
|
+
: 0;
|
|
500
|
+
for (let at = from; flag !== 0 && at < to; at += 1)
|
|
501
|
+
flags[at] |= flag;
|
|
502
|
+
marked(child, flags, shift, start, text);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function opener(text, from, to, paragraph) {
|
|
506
|
+
const before = from === paragraph ? ' ' : (text[from - 1] ?? ' ');
|
|
507
|
+
const after = text[to] ?? ' ';
|
|
508
|
+
const space = (one) => SPACE.test(one);
|
|
509
|
+
const mark = (one) => PUNCTUATION.test(one);
|
|
510
|
+
const left = !space(after) && (!mark(after) || space(before) || mark(before));
|
|
511
|
+
if (text[from] !== '_')
|
|
512
|
+
return left;
|
|
513
|
+
const right = !space(before) && (!mark(before) || space(after) || mark(after));
|
|
514
|
+
return left && (!right || mark(before));
|
|
515
|
+
}
|
|
516
|
+
function pendingAt(long, window, paragraph, start, region) {
|
|
517
|
+
const { text } = long;
|
|
518
|
+
const shift = window.start - window.lead;
|
|
519
|
+
const flags = new Uint8Array(window.end - start);
|
|
520
|
+
marked(paragraph, flags, shift, start, text);
|
|
521
|
+
for (let at = start; at < window.end; at += 1) {
|
|
522
|
+
if ((flags[at - start] & CODE) !== 0)
|
|
523
|
+
continue;
|
|
524
|
+
const one = text[at];
|
|
525
|
+
if (one === '\\' && ESCAPABLE.test(text[at + 1] ?? '')) {
|
|
526
|
+
at += 1;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (one === '`') {
|
|
530
|
+
let end = at;
|
|
531
|
+
while (text[end] === '`')
|
|
532
|
+
end += 1;
|
|
533
|
+
if ((region.runs.get(end - at) ?? -1) > at)
|
|
534
|
+
return at;
|
|
535
|
+
at = end - 1;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (one === '<' && TAG_START.test(text[at + 1] ?? '') && region.last.get('>') > at)
|
|
539
|
+
return at;
|
|
540
|
+
const settled = flags[at - start];
|
|
541
|
+
if (one === '[' && (settled & LINKED) === 0 && region.last.get(']') > at)
|
|
542
|
+
return at;
|
|
543
|
+
if ((one === '*' || one === '_' || one === '~') && (settled & (LINKED | EMPHASIZED)) === 0) {
|
|
544
|
+
let end = at;
|
|
545
|
+
while (text[end] === one)
|
|
546
|
+
end += 1;
|
|
547
|
+
if (opener(text, at, end, start) && region.last.get(one) >= end)
|
|
548
|
+
return at;
|
|
549
|
+
at = end - 1;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return Infinity;
|
|
553
|
+
}
|
|
554
|
+
function restartable(text, at) {
|
|
555
|
+
const first = text[at];
|
|
556
|
+
ORDERED.lastIndex = at;
|
|
557
|
+
if (first === undefined || BLOCK_START.test(first) || ORDERED.test(text))
|
|
558
|
+
return false;
|
|
559
|
+
DEFINED.lastIndex = at;
|
|
560
|
+
return first !== '[' || !DEFINED.test(text);
|
|
561
|
+
}
|
|
562
|
+
function inside(spans, at) {
|
|
563
|
+
return spans.some(([from, to]) => from < at && at < to);
|
|
564
|
+
}
|
|
565
|
+
function markersOf(depth) {
|
|
566
|
+
return new RegExp(`^(?: {0,3}> ?){${depth}}`);
|
|
567
|
+
}
|
|
568
|
+
function paragraphCuts(long, window, paragraph, depth, mode) {
|
|
569
|
+
const { text, starts } = long;
|
|
570
|
+
const markers = markersOf(depth);
|
|
571
|
+
const leads = new RegExp(`^(?: {0,3}> ?){0,${depth}}`);
|
|
572
|
+
const carry = '> '.repeat(depth);
|
|
573
|
+
const shift = window.start - window.lead;
|
|
574
|
+
const start = Math.max(offsetOf(paragraph) + shift, window.start);
|
|
575
|
+
const first = lineOf(long, start);
|
|
576
|
+
const region = regionOf(long, first, depth);
|
|
577
|
+
if (region.setext)
|
|
578
|
+
return [];
|
|
579
|
+
const pending = mode === 'render' ? pendingAt(long, window, paragraph, start, region) : Infinity;
|
|
580
|
+
const spans = mode === 'render'
|
|
581
|
+
? paragraph.children
|
|
582
|
+
.filter((child) => child.type !== 'text')
|
|
583
|
+
.map((child) => [offsetOf(child) + shift, endOf(child) + shift])
|
|
584
|
+
: [];
|
|
585
|
+
const last = lineOf(long, window.end - 1);
|
|
586
|
+
const lines = starts.length - 1;
|
|
587
|
+
const path = [...Array(depth).fill('blockquote'), 'paragraph'];
|
|
588
|
+
const reparsed = (at) => () => windowOf(long, { start: window.start, path: [], join: '', carry: window.carry }, at, window.prefix).nodes;
|
|
589
|
+
const cuts = [];
|
|
590
|
+
const settled = (at) => at > start && at < pending && !inside(spans, at);
|
|
591
|
+
const unbroken = (index) => {
|
|
592
|
+
if (index >= lines)
|
|
593
|
+
return true;
|
|
594
|
+
const next = lineText(starts, text, index);
|
|
595
|
+
return !DELIMITER_ROW.test(lineFacts(next.replace(markers, '')).content);
|
|
596
|
+
};
|
|
597
|
+
const contentOf = (index) => starts[index] + leads.exec(lineText(starts, text, index))[0].length;
|
|
598
|
+
for (let index = first + 1; index <= last; index += 1) {
|
|
599
|
+
const line = starts[index];
|
|
600
|
+
if (line >= pending)
|
|
601
|
+
break;
|
|
602
|
+
const whole = markers.test(lineText(starts, text, index));
|
|
603
|
+
const content = contentOf(index);
|
|
604
|
+
const at = whole ? line : content;
|
|
605
|
+
const previous = lineText(starts, text, index - 1);
|
|
606
|
+
if (!restartable(text, content) || /[ \t\\]$/.test(previous))
|
|
607
|
+
continue;
|
|
608
|
+
if (!settled(at) || !unbroken(index + 1))
|
|
609
|
+
continue;
|
|
610
|
+
const join = text.slice(starts[index - 1] + previous.length, line);
|
|
611
|
+
cuts.push({ at, path, join, carry: whole ? '' : carry, nodes: reparsed(at) });
|
|
612
|
+
}
|
|
613
|
+
if (cuts.length > 0)
|
|
614
|
+
return cuts;
|
|
615
|
+
for (let index = first; index <= last; index += 1) {
|
|
616
|
+
const content = contentOf(index);
|
|
617
|
+
const end = Math.min(lineEnd(starts, text, index), window.end);
|
|
618
|
+
for (let at = Math.max(content + 1, start + 1); at < end; at += 1) {
|
|
619
|
+
if (at >= pending)
|
|
620
|
+
return cuts;
|
|
621
|
+
if (!/[ \t]/.test(text[at - 1]) || !restartable(text, at) || !settled(at))
|
|
622
|
+
continue;
|
|
623
|
+
if (!unbroken(index + 1))
|
|
624
|
+
break;
|
|
625
|
+
let from = at - 1;
|
|
626
|
+
while (from > content && /[ \t]/.test(text[from - 1]))
|
|
627
|
+
from -= 1;
|
|
628
|
+
if (from === content)
|
|
629
|
+
continue;
|
|
630
|
+
cuts.push({ at, path, join: text.slice(from, at), carry, nodes: reparsed(at) });
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return cuts;
|
|
634
|
+
}
|
|
635
|
+
function cutsOf(long, window, mode) {
|
|
636
|
+
const { nodes } = window;
|
|
637
|
+
const shift = window.start - window.lead;
|
|
638
|
+
const at = (node) => lineStartOf(long, offsetOf(node) + shift);
|
|
639
|
+
const cuts = [];
|
|
640
|
+
for (let index = 1; index < nodes.length; index += 1) {
|
|
641
|
+
const start = at(nodes[index]);
|
|
642
|
+
if (start > window.start) {
|
|
643
|
+
const taken = nodes.slice(0, index);
|
|
644
|
+
cuts.push({ at: start, path: [], join: '', carry: '', nodes: () => taken });
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const last = nodes.at(-1);
|
|
648
|
+
if (last === undefined)
|
|
649
|
+
return cuts;
|
|
650
|
+
const before = nodes.slice(0, -1);
|
|
651
|
+
const chain = [];
|
|
652
|
+
const within = (parent, step, carry) => {
|
|
653
|
+
const held = [...chain, parent];
|
|
654
|
+
const path = [...Array(chain.length).fill('blockquote'), step];
|
|
655
|
+
const marked = markersOf(path.filter((one) => one === 'blockquote').length);
|
|
656
|
+
for (let index = 1; index < parent.children.length; index += 1) {
|
|
657
|
+
const start = at(parent.children[index]);
|
|
658
|
+
if (start <= window.start)
|
|
659
|
+
continue;
|
|
660
|
+
if (!marked.test(lineText(long.starts, long.text, lineOf(long, start))))
|
|
661
|
+
continue;
|
|
662
|
+
const taken = [...before, truncated(held, index)];
|
|
663
|
+
cuts.push({ at: start, path, join: '', carry, nodes: () => taken });
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
let node = last;
|
|
667
|
+
while (node !== undefined) {
|
|
668
|
+
if (node.type === 'paragraph') {
|
|
669
|
+
cuts.push(...paragraphCuts(long, window, node, chain.length, mode));
|
|
670
|
+
}
|
|
671
|
+
if (node.type === 'list')
|
|
672
|
+
within(node, 'list', '');
|
|
673
|
+
if (node.type === 'table' && node.children.length > 1) {
|
|
674
|
+
const begun = offsetOf(node) + shift < window.start;
|
|
675
|
+
const carry = begun ? window.carry : long.text.slice(at(node), at(node.children[1]));
|
|
676
|
+
within(node, 'table', carry);
|
|
677
|
+
}
|
|
678
|
+
if (node.type !== 'blockquote')
|
|
679
|
+
break;
|
|
680
|
+
within(node, 'blockquote', '');
|
|
681
|
+
chain.push(node);
|
|
682
|
+
node = node.children.at(-1);
|
|
683
|
+
}
|
|
684
|
+
return cuts;
|
|
685
|
+
}
|
|
686
|
+
function truncated(chain, index) {
|
|
687
|
+
const [outer, ...inner] = chain;
|
|
688
|
+
if (inner.length === 0)
|
|
689
|
+
return { ...outer, children: outer.children.slice(0, index) };
|
|
690
|
+
const children = outer.children.slice(0, -1);
|
|
691
|
+
return { ...outer, children: [...children, truncated(inner, index)] };
|
|
692
|
+
}
|
|
693
|
+
function chosen(cuts, target) {
|
|
694
|
+
let best = null;
|
|
695
|
+
for (const cut of cuts) {
|
|
696
|
+
if (best === null)
|
|
697
|
+
best = cut;
|
|
698
|
+
else if (cut.at >= target) {
|
|
699
|
+
if (best.at < target || cut.at < best.at)
|
|
700
|
+
best = cut;
|
|
701
|
+
}
|
|
702
|
+
else if (best.at < target && cut.at > best.at)
|
|
703
|
+
best = cut;
|
|
704
|
+
}
|
|
705
|
+
return best;
|
|
706
|
+
}
|
|
707
|
+
function closingOf(long, window) {
|
|
708
|
+
const last = window.nodes.at(-1);
|
|
709
|
+
if (last?.type !== 'code')
|
|
710
|
+
return 0;
|
|
711
|
+
const { text, starts } = long;
|
|
712
|
+
const line = lineOf(long, offsetOf(last) + window.start - window.lead);
|
|
713
|
+
const fence = fenceOf(lineFacts(lineText(starts, text, line)));
|
|
714
|
+
if (fence === null)
|
|
715
|
+
return 0;
|
|
716
|
+
const open = { ...START, fence };
|
|
717
|
+
for (let index = line + 1; index < starts.length - 1; index += 1) {
|
|
718
|
+
if (fenced(open, lineFacts(lineText(starts, text, index))).fence === null) {
|
|
719
|
+
return windowEnd(long, lineEnd(starts, text, index) + 1, WINDOW_CHARS);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return text.length;
|
|
723
|
+
}
|
|
724
|
+
function cutWindow(long, from, mode, open) {
|
|
725
|
+
const line = Math.min(lineOf(long, from.start) + WINDOW_LINES, long.starts.length - 1);
|
|
726
|
+
let end = windowEnd(long, from.start, Math.min(WINDOW_CHARS, long.starts[line] - from.start));
|
|
727
|
+
for (;;) {
|
|
728
|
+
const window = open(end);
|
|
729
|
+
if (end >= long.text.length)
|
|
730
|
+
return { window, cut: null };
|
|
731
|
+
const cut = chosen(cutsOf(long, window, mode), from.start + VIEW_CHARS);
|
|
732
|
+
if (cut !== null)
|
|
733
|
+
return { window, cut };
|
|
734
|
+
const grown = windowEnd(long, from.start, 2 * (end - from.start));
|
|
735
|
+
const whole = 2 * grown - from.start >= long.text.length;
|
|
736
|
+
end = Math.max(whole ? long.text.length : grown, closingOf(long, window));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
export function pieceAt(long, index) {
|
|
740
|
+
while (long.pieces.length <= index && long.next !== null) {
|
|
741
|
+
const from = long.next;
|
|
742
|
+
const { window, cut } = cutWindow(long, from, 'render', (end) => renderWindow(long, from, end));
|
|
743
|
+
const end = cut?.at ?? long.text.length;
|
|
744
|
+
for (const one of window.defined) {
|
|
745
|
+
if (one.at < end && !long.urls.has(one.key))
|
|
746
|
+
long.urls.set(one.key, one.url);
|
|
747
|
+
}
|
|
748
|
+
const nodes = cut === null ? window.nodes : cut.nodes();
|
|
749
|
+
long.pieces.push({ nodes, path: from.path, join: from.join });
|
|
750
|
+
long.next =
|
|
751
|
+
cut === null ? null : { start: cut.at, path: cut.path, join: cut.join, carry: cut.carry };
|
|
752
|
+
}
|
|
753
|
+
return long.pieces[index] ?? null;
|
|
754
|
+
}
|
|
755
|
+
function opened(node, made) {
|
|
756
|
+
if (made.has(node))
|
|
757
|
+
return node;
|
|
758
|
+
const copy = { ...node, children: [...node.children] };
|
|
759
|
+
made.add(copy);
|
|
760
|
+
return copy;
|
|
761
|
+
}
|
|
762
|
+
function continued(into, more, path, join, made) {
|
|
763
|
+
const [step, ...deeper] = path;
|
|
764
|
+
const tail = (step === 'table' ? more.children.slice(1) : more.children);
|
|
765
|
+
const merged = opened(into, made);
|
|
766
|
+
const held = merged.children;
|
|
767
|
+
if (step === 'paragraph')
|
|
768
|
+
held.push({ type: 'text', value: join }, ...tail);
|
|
769
|
+
else if (deeper.length === 0)
|
|
770
|
+
held.push(...tail);
|
|
771
|
+
else {
|
|
772
|
+
const [head, ...rest] = tail;
|
|
773
|
+
held.push(continued(held.pop(), head, deeper, join, made), ...rest);
|
|
774
|
+
}
|
|
775
|
+
return merged;
|
|
776
|
+
}
|
|
777
|
+
export function drawn(long, count) {
|
|
778
|
+
const nodes = [];
|
|
779
|
+
const made = new Set();
|
|
780
|
+
for (let index = 0; index < count; index += 1) {
|
|
781
|
+
const piece = pieceAt(long, index);
|
|
782
|
+
if (piece === null)
|
|
783
|
+
break;
|
|
784
|
+
const [first, ...rest] = piece.nodes;
|
|
785
|
+
const last = nodes.at(-1);
|
|
786
|
+
if (piece.path.length === 0 || first === undefined || last === undefined) {
|
|
787
|
+
nodes.push(...piece.nodes);
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
nodes.pop();
|
|
791
|
+
nodes.push(continued(last, first, piece.path, piece.join, made), ...rest);
|
|
792
|
+
}
|
|
793
|
+
return nodes;
|
|
794
|
+
}
|
|
795
|
+
export function remaining(long, count) {
|
|
796
|
+
return long.pieces.length > count || (long.pieces.length === count && long.next !== null);
|
|
797
|
+
}
|